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
.mapping
;
21 * Loads the mapping file (the description of how data should be moved
22 * from XML to the EDD)
25 import java
.io
.IOException
;
26 import java
.text
.DateFormat
;
27 import java
.text
.ParseException
;
28 import java
.text
.SimpleDateFormat
;
29 import java
.util
.Date
;
30 import java
.util
.HashMap
;
31 import java
.util
.Iterator
;
33 import com
.dtrules
.entity
.IREntity
;
34 import com
.dtrules
.entity
.REntity
;
35 import com
.dtrules
.infrastructure
.RulesException
;
36 import com
.dtrules
.interpreter
.IRObject
;
37 import com
.dtrules
.interpreter
.RArray
;
38 import com
.dtrules
.interpreter
.RBoolean
;
39 import com
.dtrules
.interpreter
.RDouble
;
40 import com
.dtrules
.interpreter
.RInteger
;
41 import com
.dtrules
.interpreter
.RName
;
42 import com
.dtrules
.interpreter
.RNull
;
43 import com
.dtrules
.interpreter
.RString
;
44 import com
.dtrules
.interpreter
.RTime
;
45 import com
.dtrules
.session
.DTState
;
46 import com
.dtrules
.session
.IRSession
;
47 import com
.dtrules
.session
.RSession
;
48 import com
.dtrules
.xmlparser
.IGenericXMLParser
;
50 @SuppressWarnings({"unchecked"})
51 public class LoadXMLData
implements IGenericXMLParser
{
58 static DateFormat df_in
= new SimpleDateFormat ("yyyy-MM-dd");
60 static DateFormat df_out
= new SimpleDateFormat ("MM/dd/yyyy");
63 public LoadXMLData(Mapping _map
){
67 public LoadXMLData(Mapping _map
, IRSession session
, String _ruleSetName
){
69 this.session
= session
;
70 this.state
= session
.getState();
71 this.ruleSetName
= _ruleSetName
;
73 try{ // Cache the def operator.
74 def
= session
.getState().find(RName
.getRName("def"));
77 state
.traceInfo("error", null,"General Rules Engine Failure");
78 } catch (RulesException e1
) { } // Ignore since we are going to throw anyway...
79 throw new RuntimeException(e
);
82 for(RName ename
: this.map
.entities
.keySet()){
84 IREntity e
= findEntity(ename
.stringValue().toLowerCase(),null,null);
86 } catch (RulesException e
) {
88 state
.traceInfo("error", null,"Failed to initialize the Entity Stack (Failed on "+ename
+")\n"+e
);
89 } catch (RulesException e1
) { } // Ignore since we are going to throw anyway...
90 throw new RuntimeException(e
);
96 * Looks to make sure that we have not yet created an Entity
97 * of this name with the given code. If we have, we return the
98 * earlier created Entity. Otherwise, we create a new instance.
99 * @param entity -- We assume this is a valid Entity name (no dot syntax)
102 * @throws RulesException
104 IREntity
findEntity( String entity
, String code
, EntityInfo info
) throws RulesException
{
105 String number
= (String
) this.map
.entityinfo
.get(entity
);
110 if(number
.equals("1")){
111 e
= (IREntity
)entities
.get(entity
);
113 e
= session
.getState().findEntity(RName
.getRName(entity
+"."+entity
));
115 e
= ((RSession
)session
).createEntity(null,entity
);
117 entities
.put(entity
,e
);
119 }else { // We assume number.equals("*") || number.equals("+")
122 if(code
!=null && code
.length()!=0) {
123 key
= entity
+"$"+code
;
124 e
= (IREntity
)entities
.get(key
);
127 e
= ((RSession
)session
).createEntity(null,entity
);
129 if(code
!=null) entities
.put(key
,e
);
131 if(e
==null)throw new RulesException("undefined","LoadXMLData.findEntity()","Failed to create the entity "+entity
);
132 UpdateReferences(e
,info
);
136 public void beginTag(String
[] tagstk
, int tagstkptr
, String tag
,
137 HashMap attribs
) throws IOException
, Exception
{
138 String name
= tag
; // We assume the tag might create an entity
139 @SuppressWarnings("unused")
140 boolean traceopen
= false;
141 EntityInfo info
= (EntityInfo
) this.map
.requests
.get(name
);
142 AttributeInfo aInfo
= (AttributeInfo
) this.map
.setattributes
.get(tag
);
145 // If I get info, then create an entity.
146 // Get the code from this tag.
147 // If a fixed entity name is specified,
148 // or the tag name, use it. Otherwise use the multiple name
150 Object objCode
= attribs
.get(info
.id
);
151 String code
= objCode
==null?
"":objCode
.toString();
152 String eName
= info
.name
;
153 if (eName
== null || eName
.length() <= 0)
155 eName
= (String
) attribs
.get("name");
157 IREntity e
= findEntity(eName
, code
, info
); // Look up the entity I should create.
158 if(e
!=null){ // I hope to goodness I can find it!
159 attribs
.put("create entity","true");
160 if(code
.length()!=0) {
161 e
.put(IREntity
.mappingKey
,RString
.newRString(code
));
163 e
.put(IREntity
.mappingKey
,RString
.newRString("v"+ (++codeCnt
)));
167 if(state
.testState(DTState
.TRACE
)){
168 state
.traceTagBegin("createEntity", "name='"+info
.name
+"' id='"+code
+"'");
173 state
.traceInfo("error", null, "The Mapping defines '"+info
.entity
+"', but this entity isn't defined in the EDD");
174 throw new Exception("The Mapping defines '"+info
.entity
+"', but this entity isn't defined in the EDD");
178 if(aInfo
!=null){ // If we are supposed to set an attribute, then we set ourselves up
179 // to define the entity attribute on the end tag. We may be setting this
180 // Attribute to the value of the Entity we just created/looked up.
182 * First check enclosures, then check the blank case. This allows
183 * the user to specify a default mapping, yet still direct some attributes to
184 * specific destinations based on the enclosure.
186 AttributeInfo
.Attrib attrib
;
187 { // Not only do you have to match the attribute name,
188 int i
=tagstkptr
-2; // But you must match the immediately enclosing tag
190 attrib
= aInfo
.lookup(tagstk
[i
]);
192 queueSetAttribute(attrib
, attribs
);
196 attrib
= aInfo
.lookup(""); // If I don't find the enclosure defined, look to see
197 queueSetAttribute(attrib
,attribs
); // if a general default is defined.
201 public void endTag(String
[] tagstk
, int tagstkptr
, String tag
, String body
,
202 HashMap attribs
) throws Exception
, IOException
205 REntity entity
= null;
207 if(attribs
.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
208 entity
= (REntity
) state
.entitypop();
209 Iterator pairs
= map
.attribute2listPairs
.iterator();
210 body
= ""; // Don't care about the Body if we created an Entity.
211 while(pairs
.hasNext()){
212 Object
[] pair
= (Object
[]) pairs
.next();
213 if(entity
.containsAttribute(RName
.getRName((String
)pair
[0]))){
214 RName
.getRName((String
) pair
[1],true).execute(state
);
215 state
.entitypush(entity
);
216 RName
.getRName("addto",true).execute(state
);
220 if(state
.testState(DTState
.TRACE
)){
221 state
.traceTagEnd("createEntity", null);
225 // If this is a Date format, we are going to reformat it, and let it feed into
226 // the regular set attribute code.
227 if ((attr
= (String
) attribs
.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
228 if (body
.trim().length() > 0)
232 if(false && body
.indexOf("7777")>=0){
233 date
= new Date(0x7FFFFFFFFFFFL
);
235 date
= df_in
.parse(body
);
237 } catch (ParseException e
) {
239 date
= df_out
.parse(body
);
240 }catch (ParseException e2
){
241 date
= df_out
.parse("01/05/2008");
242 //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
245 body
= df_out
.format(date
);
246 attribs
.put("set attribute",attr
);
250 if ((attr
= (String
) attribs
.get("set attribute"))!=null){
251 // Look and see if we have an attribute name defined.
253 RName a
= RName
.getRName(attr
);
256 IREntity enclosingEntity
= session
.getState().findEntity(a
);
257 if(enclosingEntity
!=null){
260 int type
= enclosingEntity
.getEntry(a
).type
;
262 if(type
== IRObject
.iInteger
){
263 value
= RInteger
.getRIntegerValue(body
.length()==0?
"0" : body
);
264 } else if (type
== IRObject
.iDouble
) {
265 value
= RDouble
.getRDoubleValue(body
.length()==0?
"0" : body
);
266 } else if (type
== IRObject
.iBoolean
){
267 value
= RBoolean
.getRBoolean(body
.length()==0?
"false" : body
);
268 } else if (type
== IRObject
.iTime
){
269 if(body
.trim().length()>0){
270 value
= RTime
.getRDate(body
);
272 throw new RulesException("MappingError","LoadXMLData","Bad Date... Could not parse '"+body
+"'");
275 value
= RNull
.getRNull();
277 } else if (type
== IRObject
.iEntity
){
281 throw new RulesException("MappingError","LoadXMLData","Entity Tags have to create some Entity Reference");
284 value
= RString
.newRString(body
);
286 // conversion in the Rules Engine to do the proper thing.
287 state
.def(a
,value
,false);
295 public boolean error(String v
) throws Exception
{
300 * Does nothing if the info is null... Just means we are not mapping this attribute.
301 * Otherwise it updates the attribs hashmap.
305 private void queueSetAttribute( AttributeInfo
.Attrib attrib
, HashMap attribs
){
306 if(attrib
==null)return;
307 switch (attrib
.type
){
308 case AttributeInfo
.DATE_STRING_CODE
:
309 attribs
.put("set attribute date",attrib
.rAttribute
);
311 case AttributeInfo
.STRING_CODE
:
312 case AttributeInfo
.NONE_CODE
:
313 case AttributeInfo
.INTEGER_CODE
:
314 case AttributeInfo
.BOOLEAN_CODE
:
315 case AttributeInfo
.FLOAT_CODE
:
316 case AttributeInfo
.ENTITY_CODE
:
317 case AttributeInfo
.XMLVALUE_CODE
:
318 attribs
.put("set attribute",attrib
.rAttribute
);
321 throw new RuntimeException("Bad Type Code "+attrib
.type
+" in com.dtrules.mapping.AttributeInfo: "+attrib
.rAttribute
);
326 * We collect all the Entities we create as we go. These
327 * are stored as a value, and their id as the key. Then if
328 * we encounter the same key in the XML, we return the same
331 HashMap entities
= new HashMap();
333 IREntity
UpdateReferences(IREntity e
, EntityInfo info
)throws RulesException
{
335 if(info
!=null && info
.list
.length()==0){
336 listname
= RName
.getRName(e
.getName().stringValue()+"s");
338 listname
= RName
.getRName(info
.list
);
340 // First add this entity to any list found on the entity stack.
341 for(int i
=0; i
< state
.edepth(); i
++){
342 // Look for all Array Lists on the Entity Stack that look like lists of this Entity
343 IREntity entity
= state
.getes(i
);
344 IRObject elist
= entity
.get(listname
);
345 if(elist
!=null && elist
.type()==IRObject
.iArray
){
346 // If not a member of this list, then add it.
347 if(!((RArray
)elist
).contains(e
)){
348 ((RArray
)elist
).add(e
);
352 // Then update the reference to this entity that might be on the Entity Stack.
353 // DON'T go wild. Only look at the top entity (or you may overwrite a reference
354 // you'd rather leave alone.
355 // DON'T mess with any entity's self reference though! That is BAD.
356 int i
=state
.edepth()-1;
357 if(((IREntity
)state
.getes(i
)).get(e
.getName())!=null){
358 IREntity refto
= state
.getes(i
);
359 if(! refto
.getName().equals(e
.getName())) // Update a reference to an Entity of the same name,
360 ((IREntity
)state
.getes(i
)).put(e
.getName(), e
); // but only if it isn't a self reference.