initial load
[DTRules.git] / DTRules / src / main / java / com / dtrules / interpreter / RName.java
blob2da35baa96c38a94db7d9be1835940a363f78bc9
1 /*
2 * $Id$
3 *
4 * Copyright 2004-2007 MTBJ, Inc.
5 *
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
9 *
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.
17 */
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 {
31 final RName entity;
32 final String name;
33 final boolean executable;
34 final int hashcode;
35 final RName partner; // RNames are created in pairs, executable and non-executable.
37 static HashMap names = new HashMap();
39 /**
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.
44 * @param _name
45 * @param _executable
46 * @param _hashcode
47 * @param _partner
49 private RName(RName _entity, String _name, boolean _executable, int _hashcode, RName _partner){
50 entity = _entity;
51 name = _name;
52 executable = _executable;
53 hashcode = _hashcode;
54 partner = _partner;
56 /**
57 * This constructor should only be called by the getRName method. This
58 * constructor always creates two RNames, the one requested and its partner.
60 * @param _name
61 * @param _executable
62 * @param _hashcode
64 private RName(RName _entity, String _name, boolean _executable, int _hashcode ){
65 entity = _entity;
66 name = _name;
67 executable = _executable;
68 hashcode = _hashcode;
69 partner = new RName(_entity, _name,!_executable,_hashcode,this);
72 static Pattern spaces = Pattern.compile(" ");
73 /**
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
78 * the "dot" syntax.
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);
87 if(!executable){
88 _name = _name.substring(1); // Remove the slash.
90 int dot = _name.indexOf('.');
92 if(dot>=0){
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)
105 * <br><br>
106 * Thus one calls one of the getRName functions, and one cannot call our
107 * constructors directly.
108 * <br><br>
109 * Returns a null if a RName cannot be found/created.
111 * @param _name
112 * @return
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)
124 * <br><br>
125 * Thus one calls one of the getRName functions, and one cannot call our
126 * constructors directly.
128 * @param _name
129 * @return
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;
137 if(_entity!=null){
138 cname = _entity.stringValue().toLowerCase()+"."+lname;
140 RName rn = (RName) names.get(cname);
141 if(rn == null ) {
142 rn = new RName(_entity ,_name,_executable, lname.hashCode());
143 names.put(cname,rn);
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.
152 * @return
154 public RName getEntityName(){
155 return entity;
158 public boolean equals(Object arg0) {
159 if(arg0.getClass()!=RName.class)return false;
160 boolean f = name.equalsIgnoreCase(((RName)arg0).name);
161 return f;
164 public int hashCode() {
165 return 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);
176 static int cnt= 0;
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 {
185 cnt++;
186 IRObject o = state.find(this); // Does a lookup of the name on the Entity Stack
187 if(o==null){
188 throw new RulesException("Undefined","RName","The Name '"+name+"' was not defined by any Entity on the Entity Stack");
190 if(o.isExecutable()){
191 o.execute(state);
192 }else{
193 state.datapush(o);
197 public IRObject getExecutable() {
198 return executable ? this : partner ;
201 public IRObject getNonExecutable() {
202 return executable ? partner : this ;
205 public boolean isExecutable() {
206 return executable;
210 /**
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() {
222 if(entity!=null){
223 return entity.stringValue()+"."+name;
225 return 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(){
233 return postFix();
236 public int type() {
237 return iName;
240 @Override
241 public int compare(IRObject obj) throws RulesException {
242 String v = obj.stringValue();
243 return name.compareToIgnoreCase(v);
246 * Returns myself
248 public RName rNameValue() throws RulesException {
249 return this;
251 /* (non-Javadoc)
252 * @see com.dtrules.interpreter.ARObject#rStringValue()
254 @Override
255 public RString rStringValue() {
256 return RString.newRString(name);