4 * Copyright 2004-2007 MTBJ, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 package com
.dtrules
.interpreter
;
22 import java
.util
.HashMap
;
23 import java
.util
.regex
.Pattern
;
25 import com
.dtrules
.infrastructure
.RulesException
;
26 import com
.dtrules
.session
.DTState
;
28 @SuppressWarnings({"unchecked"})
29 public class RName
extends ARObject
{
33 final boolean executable
;
35 final RName partner
; // RNames are created in pairs, executable and non-executable.
37 static HashMap names
= new HashMap();
40 * This constructor should only be called by the other RName constructor.
41 * It is used to build its partner. RNames are always created in pairs,
42 * one executable and one non-executable.
49 private RName(RName _entity
, String _name
, boolean _executable
, int _hashcode
, RName _partner
){
52 executable
= _executable
;
57 * This constructor should only be called by the getRName method. This
58 * constructor always creates two RNames, the one requested and its partner.
64 private RName(RName _entity
, String _name
, boolean _executable
, int _hashcode
){
67 executable
= _executable
;
69 partner
= new RName(_entity
, _name
,!_executable
,_hashcode
,this);
72 static Pattern spaces
= Pattern
.compile(" ");
74 * When you don't really care about the executable nature of the
75 * name, then use this accessor. We parse looking for the slash to
76 * determine a literal, so by default (i.e. no slash given), we
77 * return executable names. This constructor also pareses to handle
79 * @exception RuntimeException is thrown if the Syntax is incorrect.
80 * @param _name String from which to create a name
81 * @return The Name object
83 static public RName
getRName(String _name
){
84 // Fix the name; trim and then replace internal spaces with '_'.
85 _name
= spaces
.matcher(_name
.trim()).replaceAll("_");
86 boolean executable
= !(_name
.indexOf('/')==0);
88 _name
= _name
.substring(1); // Remove the slash.
90 int dot
= _name
.indexOf('.');
93 String entity
= _name
.substring(0,dot
);
94 if(dot
== 0 || dot
+1 == _name
.length() || _name
.indexOf(dot
+1,'.')>=0){
95 throw new RuntimeException("Invalid Name Syntax: ("+_name
+")");
97 String name
= _name
.substring(dot
+1);
98 return getRName(RName
.getRName(entity
),name
,executable
);
100 return getRName(null, _name
, executable
);
103 * We cache the creation of RNames so as to not create new copies
104 * of RNames that we don't have to create. (RNames are reusable)
106 * Thus one calls one of the getRName functions, and one cannot call our
107 * constructors directly.
109 * Returns a null if a RName cannot be found/created.
114 static public RName
getRName(String _name
, boolean _executable
) {
115 // Fix the name; trim and then replace internal spaces with '_'.
116 _name
= _name
.trim().replaceAll(" ","_");
117 return getRName(null,_name
,_executable
);
120 static Pattern space
= Pattern
.compile(" ");
122 * We cache the creation of RNames so as to not create new copies
123 * of RNames that we don't have to create. (RNames are reusable)
125 * Thus one calls one of the getRName functions, and one cannot call our
126 * constructors directly.
131 static public RName
getRName(RName _entity
, String _name
, boolean _executable
) {
132 // Fix the name; trim and then replace internal spaces with '_'.
133 _name
= space
.matcher(_name
).replaceAll("_");
134 // If we already have the RName, we are done.
135 String lname
= _name
.toLowerCase();
136 String cname
= _name
;
138 cname
= _entity
.stringValue().toLowerCase()+"."+lname
;
140 RName rn
= (RName
) names
.get(cname
);
142 rn
= new RName(_entity
,_name
,_executable
, lname
.hashCode());
145 if(_executable
) return (RName
) rn
.getExecutable();
146 return (RName
) rn
.getNonExecutable();
149 * Returns the entity component of the name, which is null if none
150 * was specfied when the name was created.
154 public RName
getEntityName(){
158 public boolean equals(Object arg0
) {
159 if(arg0
.getClass()!=RName
.class)return false;
160 boolean f
= name
.equalsIgnoreCase(((RName
)arg0
).name
);
164 public int hashCode() {
169 * Compare this RName with another Rules Engine Object. RNames
170 * are only equal to other RNames.
172 public boolean equals(IRObject o
) {
173 if(o
.type()!=IRObject
.iName
)return false;
174 return equals((Object
)o
);
178 * The execution of an RName looks up that RName in the Entity
179 * Stack. If the object found there is an Array, it is pushed
180 * to the Entity Stack. If the object found there is not an
181 * array, and it is not executable, then it is pushed. Otherwise
182 * (not an array, and executable) the object is executed.
184 public void execute(DTState state
) throws RulesException
{
186 IRObject o
= state
.find(this); // Does a lookup of the name on the Entity Stack
188 throw new RulesException("Undefined","RName","The Name '"+name
+"' was not defined by any Entity on the Entity Stack");
190 if(o
.isExecutable()){
197 public IRObject
getExecutable() {
198 return executable ?
this : partner
;
201 public IRObject
getNonExecutable() {
202 return executable ? partner
: this ;
205 public boolean isExecutable() {
211 * Returns the postfix version of the name.
213 public String
postFix() {
214 return executable ?
stringValue() : "/"+stringValue();
218 * Returns the value of the name unadorned by the leading slash, even
219 * if the name is a literal.
221 public String
stringValue() {
223 return entity
.stringValue()+"."+name
;
229 * Returns the nicest format for debugging, i.e. the Postfix version which
230 * has the slash if the name is a literal name.
232 public String
toString(){
241 public int compare(IRObject obj
) throws RulesException
{
242 String v
= obj
.stringValue();
243 return name
.compareToIgnoreCase(v
);
248 public RName
rNameValue() throws RulesException
{
252 * @see com.dtrules.interpreter.ARObject#rStringValue()
255 public RString
rStringValue() {
256 return RString
.newRString(name
);