initial load
[DTRules.git] / DTRules / src / main / java / com / dtrules / entity / REntity.java
blobea6d0411a2896b6bda652733e850594295485a54
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.entity;
21 import java.io.PrintStream;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.Iterator;
26 import com.dtrules.infrastructure.RulesException;
27 import com.dtrules.interpreter.ARObject;
28 import com.dtrules.interpreter.IRObject;
29 import com.dtrules.interpreter.RName;
30 import com.dtrules.interpreter.RNull;
31 import com.dtrules.session.IRSession;
32 import com.dtrules.session.RSession;
34 /**
35 * Entities serve as the dictionaries of the Rules Engine. These
36 * Dictionaries are typed Hashtables. In other words, you can't
37 * just put any old object into an Entity. There has to be an
38 * attribute with the appropriate name and type in order to put
39 * a particular object with that name into an Entity.
40 * <br><br>
41 * This structure catches many data entry and program structure
42 * errors, as well as provides for a number of convienent automatic
43 * data conversions (if the compiler writer cares to provide such
44 * facilities).
46 * @author Paul Snow
49 public class REntity extends ARObject implements IREntity {
51 public void removeAttribute(RName attrib) {
52 attributes.remove(attrib);
55 /** This attribute's name */
56 final RName name;
57 boolean readonly;
59 HashMap<RName,REntityEntry> attributes;
60 ArrayList<IRObject> values = new ArrayList<IRObject>();
62 /**
63 * A readonly entity cannot be modified at run time.
65 public boolean isReadOnly(){ return readonly; }
67 /**
68 * All reference Entities (i.e. those from which we clone instances) have
69 * an id of zero. Clones have an id that is non zero, and unique.
71 final int id;
73 /**
74 * Returns the ID number for this instance of the entity. Entities with
75 * an ID of zero are reference entities.
76 * @return
78 public int getID(){ return id;}
80 /**
81 * Returns an interator that provides all the names of all the attributes for this entity.
83 public Iterator<RName> getAttributeIterator(){
84 return attributes.keySet().iterator();
86 /**
87 * Checks to see if the given attribute is defined by this entity.
88 * @param attName
89 * @return
91 public boolean containsAttribute(RName attName){
92 return attributes.containsKey(attName);
95 /**
96 * Create a clone of an Entity.
99 public REntity( boolean _readonly, REntity entity, IRSession s) throws RulesException{
100 id = s.getUniqueID();
101 readonly = _readonly;
102 name = entity.name;
103 attributes = entity.attributes;
104 values = new ArrayList<IRObject>(entity.values);
105 for(int i=0;i<values.size();i++){
106 IRObject value = values.get(i);
107 if(value.type()!=iEntity){ // Entities are copied by reference.
108 values.set(i,value.clone(s));
109 }else{
110 values.set(i,value); // The clone references the same entity
113 put(name,this); //Patch up the self reference to point to self.
114 put(mappingKey,RNull.getRNull()); //
118 * Regular Constructor. This should only be called when building the EntityFactory.
119 * However, we make it public so the EntityFactory can be defined in the Session
120 * package. We might like to reconsider that decision some time in the future.
122 * @param _name
124 public REntity( int id, boolean _readonly, RName _name) {
125 this.id = id;
126 readonly = _readonly;
127 name = _name;
128 attributes = new HashMap<RName,REntityEntry>();
129 this.addAttribute(_name, "", this, false, true, type(),null); // Add a reference to self!
130 this.addAttribute(mappingKey,"",RNull.getRNull(),false, true, iString,null);
133 /* (non-Javadoc)
134 * @see com.dtrules.entity.IREntity#getName()
136 public RName getName(){
137 return name;
141 * Adds this REntityEntry to this Entity. If an EntityEntry already exists, it will
142 * be replaced by this new one, no questions asked. The assumption is that one is
143 * editing the Attributes of the Entity, and the latest is the the right one to keep.
145 * @param entry The new Attribute meta data.
148 public void addAttribute(REntityEntry entry){
149 REntityEntry oldentry = getEntry(entry.attribute);
150 if(oldentry!=null){ // If the attribute already exists
151 entry.index = oldentry.index; // replace the old one (keep their index)
152 }else{
153 entry.index = values.size(); // If the attribute is new, make a new
154 values.add(RNull.getRNull()); // value index.
156 if(entry.defaultvalue==null){ // Update with the default value.
157 values.set(entry.index, RNull.getRNull());
158 }else{
159 values.set(entry.index, entry.defaultvalue);
162 attributes.put(entry.attribute,entry); // Put the new Entity Entry into this Entity.
167 * This adds an attribute into the REntity. This is called by the Entity
168 * construction during the loading of the Entity Description Dictionary.
170 * @param defaultvalue Default value for this tag
171 * @param writable If true, the attribute is writable by decision tables
172 * @param readable If true, the attribute is readable by decision tables
173 * @param type
174 * @return null if successful, and an Error string if it failed.
176 public String addAttribute(RName attributeName,
177 String defaulttxt,
178 IRObject defaultvalue,
179 boolean writable,
180 boolean readable,
181 int type,
182 String subtype ){
183 REntityEntry entry = getEntry(attributeName);
184 if(entry==null){
185 int index = values.size();
186 if(defaultvalue==null){
187 values.add(RNull.getRNull());
188 }else{
189 values.add(defaultvalue);
191 REntityEntry newEntry = new REntityEntry(this,attributeName,defaulttxt, defaultvalue,writable,readable,type,subtype,index);
193 attributes.put(attributeName,newEntry);
194 return null;
196 if(entry.type!=type){
197 String type1 ="";
198 String type2 ="";
199 try{
200 type1="("+ RSession.typeInt2Str(entry.type)+") ";
201 }catch(RulesException e){}
202 try{
203 type2="("+ RSession.typeInt2Str(type)+")";
204 }catch(RulesException e){}
206 return "The entity '"+name.stringValue()+
207 "' has an attribute '"+attributeName.stringValue()+
208 "' with two types: "+type1+" and "+ type2+ "\n";
210 return null; // Entry already matches what we already have.
212 /* (non-Javadoc)
213 * @see com.dtrules.entity.IREntity#put(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject)
215 public void put(RName attrib, IRObject value) throws RulesException {
216 REntityEntry entry = (REntityEntry)attributes.get(attrib);
217 if(entry==null)throw new RulesException("Undefined", "REntity.put()", "Undefined Attribute "+attrib+" in Entity: "+name);
218 if(value.type()!= iNull && entry.type != value.type()){
219 switch(entry.type) {
220 case iInteger : value = value.rIntegerValue(); break;
221 case iDouble : value = value.rDoubleValue(); break;
222 case iBoolean : value = value.rBooleanValue(); break;
223 //case iDecisiontable : value = value.rDecisiontableValue(); break;
224 case iEntity : value = value.rEntityValue(); break;
225 //case iMark : value = value.rMarkValue(); break;
226 case iName : value = value.rNameValue(); break;
227 //case iOperator : value = value.rOperatorValue(); break;
228 case iString : value = value.rStringValue(); break;
229 case iTime : value = value.rTimeValue(); break;
232 values.set(entry.index,value);
236 * Looks up the name of an attribute,
237 * and returns the associated value.
238 * If no value is defined, returns a null.
240 public IRObject get(String attribName)
242 return get(RName.getRName(attribName));
246 * Looks up the given name, and returns the associated value. If
247 * no value is defined, returns a null.
249 public IRObject get(RName attrib) {
250 REntityEntry entry = (REntityEntry)attributes.get(attrib);
251 if(entry==null)return null;
252 return (IRObject) values.get(entry.index);
255 /* (non-Javadoc)
256 * @see com.dtrules.entity.IREntity#get(int)
258 public IRObject get(int i) {
259 return (IRObject) values.get(i);
263 * Sets a value in the values array. Should only be used
264 * RARELY outside of REntity.
265 * @param i
266 * @param v
268 public void set(int i, IRObject v){
269 values.set(i, v);
272 * Returns an object that describes all the information we track about an
273 * Entity Attribute (the key to get its value). If the attribute is undefined,
274 * then a null is returned.
276 public REntityEntry getEntry(RName attrib) {
277 REntityEntry entry = (REntityEntry)attributes.get(attrib);
278 return entry;
280 /* (non-Javadoc)
281 * @see com.dtrules.entity.IREntity#getValue(int)
283 public IRObject getValue(int index) {
284 return (IRObject) values.get(index);
288 /* (non-Javadoc)
289 * @see com.dtrules.entity.IREntity#postFix()
291 public String postFix() {
292 return "/"+name.stringValue()+" "+id+" createEntity ";
295 /* (non-Javadoc)
296 * @see com.dtrules.entity.IREntity#stringValue()
298 public String stringValue() {
299 return name.stringValue();
302 /* (non-Javadoc)
303 * @see com.dtrules.entity.IREntity#type()
305 public int type() {
306 return iEntity;
309 public String toString(){
310 String v = name.stringValue()+" = {";
311 Iterator<RName> ia = getAttributeIterator();
312 while(ia.hasNext()){
313 RName n = ia.next();
314 IRObject o = get(n);
315 if(o==null){ // Protect ourselves from nulls.
316 o = RNull.getRNull();
318 v +=n.stringValue()+" = "+get(n).stringValue()+" ";
320 v +="}";
321 return v;
325 public IRObject clone(IRSession s) throws RulesException {
326 if(readonly)return this;
327 return new REntity(false,this,s);
331 * Returns itself
333 public IREntity rEntityValue() throws RulesException {
334 return this;
337 public void writeXML(PrintStream p) throws RulesException {
338 Iterator<RName> attribs = getAttributeIterator();
339 p.println();
340 while(attribs.hasNext()){
341 RName attrib = attribs.next();
342 if(attrib.equals(name))continue; // Skip the self reference.
343 REntityEntry entry = attributes.get(attrib);
344 p.print("<entity attribute=\"");
345 p.print(attrib.stringValue());
346 p.print("\" type =\"");
347 p.print(RSession.typeInt2Str(entry.type));
348 p.print("\" cdd_default_value=\"");
349 p.print(entry.defaulttxt);
350 p.print("\" cdd_i_c=\"");
351 p.print(entry.writable?"c":"i");
352 p.print("\" parseStr=\"\">");
353 p.print(name.stringValue());
354 p.println("</entity>");