--- /dev/null
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="M2_REPO/jsr94/jsr94/2.1/jsr94-2.1.jar"/>
+</classpath>
\ No newline at end of file
--- /dev/null
+<projectDescription>
+ <name>DTRules</name>
+ <comment>SDC Parent POM</comment>
+ <projects/>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
\ No newline at end of file
--- /dev/null
+#Thu May 15 12:54:22 CDT 2008
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
--- /dev/null
+K 10
+svn:ignore
+V 47
+.settings
+target
+.classpath
+.project
+.git
+
+END
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T14:06:05.224285Z
+11701
+mgoshorn
+has-props
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+src
+dir
+\f
+docs
+dir
+\f
+pom.xml
+file
+
+
+
+
+2008-09-09T20:34:36.296875Z
+05341a3a4e589711e1ebae68bb1790ff
+2008-09-09T14:06:05.224285Z
+11701
+mgoshorn
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+697
+\f
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>RulesEngine</artifactId>
+ <groupId>com.dtrules</groupId>
+ <version>1.20-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.dtrules</groupId>
+ <artifactId>DTRules</artifactId>
+ <name>DTRules</name>
+ <version>1.20-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>jsr94</groupId>
+ <artifactId>jsr94</artifactId>
+ <version>2.1</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/docs
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+DTRules.doc
+file
+
+
+
+
+2008-05-15T17:28:04.765625Z
+a78bca7db23ba0f051e9d538e67abae8
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+has-props
+\f
+OperatorList.doc
+file
+
+
+
+
+2008-05-15T17:28:04.781250Z
+875f80d4dafd59cd00a064c6268d6607
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+has-props
+\f
--- /dev/null
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
--- /dev/null
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>RulesEngine</artifactId>
+ <groupId>com.dtrules</groupId>
+ <version>1.20-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.dtrules</groupId>
+ <artifactId>DTRules</artifactId>
+ <name>DTRules</name>
+ <version>1.20-SNAPSHOT</version>
+ <dependencies>
+ <dependency>
+ <groupId>jsr94</groupId>
+ <artifactId>jsr94</artifactId>
+ <version>2.1</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+test
+dir
+\f
+main
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+java
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+com
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+dtrules
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+infrastructure
+dir
+\f
+App.java
+file
+
+
+
+
+2008-05-15T17:28:01.859375Z
+88e0dd001d2a35a1d3218b9363be91be
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+interpreter
+dir
+\f
+session
+dir
+\f
+admin
+dir
+\f
+decisiontables
+dir
+\f
+mapping
+dir
+\f
+entity
+dir
+\f
+xmlparser
+dir
+\f
+trace
+dir
+\f
--- /dev/null
+package com.dtrules;
+
+/**
+ * Hello world!
+ *
+ */
+public class App
+{
+ public static void main( String[] args )
+ {
+ System.out.println( "Hello World!" );
+ }
+}
--- /dev/null
+package com.dtrules;
+
+/**
+ * Hello world!
+ *
+ */
+public class App
+{
+ public static void main( String[] args )
+ {
+ System.out.println( "Hello World!" );
+ }
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/admin
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RulesAdminService.java
+file
+
+
+
+
+2008-08-21T13:30:09.218750Z
+0125a58d146eff77fd62b02bc9bd9d4e
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+IRulesAdminService.java
+file
+
+
+
+
+2008-08-21T15:15:31.359375Z
+68754d905b0a6aa8a66543dd9fff5bb7
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import java.util.List;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+
+/**
+ * @author Prasath Ramachandran
+ * Feb 1, 2007
+ *
+ */
+@SuppressWarnings({"unchecked"})
+public interface IRulesAdminService {
+
+ public void initialize(String pathtoDTrules);
+ public List<String> getRulesets(); // List of Ruleset Names
+ public RuleSet getRuleset(String RulesetName);
+ public void updateRuleset(RuleSet ruleset);
+ public void createRuleset(RuleSet ruleset) throws RulesException;
+
+ public List getDecisionTables(String rulesetname);
+ public RDecisionTable getDecisionTable(String rulesetname, String DecisionTableName);
+ public void saveDecisionTables(RSession session, String rulesetname) throws RulesException;
+ public RDecisionTable createDecisionTable(String rulesetname, String decisiontablename) throws RulesException;
+ //public Node getDecisionTableTree(String rulesetname) --- not needed now
+
+ public List getEntities(String rulesetname);
+ public List getAttributes(String rulesetname, String entityName);
+ public IREntity createEntity(String rulesetname, boolean readonly, String EntityName);
+ public boolean createAttribute(String rulesetname, REntityEntry attribute);
+ public void saveEDD(RSession session, String rulesetname)throws RulesException;
+ public void updateAttribute(REntity entity, String rulesetname,REntityEntry attribute)throws RulesException;
+
+ /**
+ * Given an incomplete table, this method returns a balanced table.
+ * Entries in the table provided can be 'y', 'n', '-', or ' '. If
+ * blank, then it is assumed that the caller assumes this should be
+ * flushed out. If the result will be larger than 16 columns, an
+ * null is returned. (You can't have a table larger than 16 columns).
+ * @param table -- A partial truth table.
+ * @return
+ */
+ public String[][] balanceTable(String [] [] table);
+ /**
+ * Given a Rule Set and an Entity, returns the list of EntityEntry objects
+ * that define the meta information about each attribute of the entity.
+ * @param rulesetname The Rule Set in which the entity is defined
+ * @param entityname The entity name of intrest.
+ * @return The list of Entity Entries that define the attributes of the Entity
+ */
+ public List<REntityEntry> getEntityEntries(String rulesetname, String entityname);
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+/**
+ * @author Prasath Ramachandran
+ * Feb 1, 2007
+ *
+ * The RulesAdminService provides all the methods for adding to and maintaining a
+ * Rules in DTRules. This is the interface to be used by editors and other tools
+ * to add/remove decision tables, modify the Entity Description Dictionary, and
+ * create and modify Rule Sets.
+ */
+@SuppressWarnings("unchecked")
+public class RulesAdminService implements IRulesAdminService{
+ final private RSession session;
+ private RulesDirectory rd; // The Rules Directory provides a place where Rule
+ // sets are defined.
+
+ /**
+ * The RulesAdminService needs a session for specifing the output of debugging
+ * and trace information. It needs a Rules Directory to administer.
+ */
+ public RulesAdminService(final RSession session, final RulesDirectory rd) {
+ super();
+ this.session = session;
+ this.rd = rd;
+ }
+
+ /**
+ * Create a new Attribute; The Entity modified is specified by the attribute.
+ * @param rulesetname The name of the RuleSet where the attribute should be created.
+ * @param attribute The REntityEntry defines the Entity to be modified. It is
+ * assumed that this Entity already exists.
+ * @return true if the attribute was successfully added.
+ */
+ public boolean createAttribute(final String rulesetname, final REntityEntry attribute) {
+ try {
+ RuleSet rs = getRuleset(rulesetname);
+ IREntity entity = rs.getEntityFactory(session).findRefEntity(attribute.attribute);
+ entity.addAttribute(attribute);
+ return true;
+ } catch (RulesException e) {
+ return false;
+ }
+
+ }
+
+ /**
+ * Given a Rule Set and an Entity, returns the list of EntityEntry objects
+ * that define the meta information about each attribute of the entity. If an
+ * error occurs while building the list, an empty list is returned.
+ *
+ * @param rulesetname The Rule Set in which the entity is defined
+ * @param entityname The entity name of intrest.
+ * @return The list of Entity Entries that define the attributes of the Entity
+ */
+ public List<REntityEntry> getEntityEntries(String rulesetname, String entityname){
+ ArrayList<REntityEntry> entries = new ArrayList<REntityEntry>();
+ RuleSet rs = getRuleset(rulesetname);
+ IREntity entity;
+ try {
+ entity = rs.getEntityFactory(session).findRefEntity(RName.getRName(entityname));
+ Iterator<RName> attribs = entity.getAttributeIterator();
+
+ while(attribs.hasNext()){
+ entries.add(entity.getEntry(attribs.next()));
+ }
+ } catch (RulesException e) { }
+
+ return entries;
+ }
+
+ /**
+ * Create a new Decision Table
+ */
+ public RDecisionTable createDecisionTable(String rulesetname, String decisiontablename)
+ throws RulesException{
+ RuleSet rs = getRuleset(rulesetname);
+ return rs.getEntityFactory(session).newDecisionTable(decisiontablename,session);
+ }
+
+ /**
+ * Creates a new Entity of the given name within the RuleSet. If
+ * the Entity already exists or the name is invalid, or this operation
+ * fails in any other way, a null is returned.
+ * @see com.dtrules.admin.IRulesAdminService#createEntity(java.lang.String, java.lang.String)
+ * @param rulesetname The name of the RuleSet in which to create this entity
+ * @param EntityName The name of the new Entity
+ */
+ public IREntity createEntity(String rulesetname, boolean readonly, String entityName) {
+ RName name = RName.getRName(entityName);
+ IREntity e = session.getEntityFactory().findRefEntity(name);
+ if(e!=null)return null;
+ try {
+ return session.getEntityFactory().findcreateRefEntity(readonly, name);
+ } catch (RulesException e1) {
+ return null;
+ }
+ }
+
+ /**
+ * Create a new Rule Set
+ * @see com.dtrules.admin.IRulesAdminService#createRuleset(com.dtrules.session.RuleSet)
+ */
+ public void createRuleset(RuleSet ruleset) throws RulesException{
+ rd.addRuleSet(ruleset);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getAttributes(java.lang.String, java.lang.String)
+ */
+ @SuppressWarnings("unchecked")
+ public List getAttributes(String rulesetname, String entityName) {
+ if(rd==null)return null;
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ Iterator it = rs.getEntityFactory(session)
+ .findRefEntity(RName.getRName(entityName)).getAttributeIterator();
+ return getList(it);
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getDecisionTable(java.lang.String, java.lang.String)
+ */
+ public RDecisionTable getDecisionTable(String rulesetname, String DecisionTableName) {
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ return rs.getEntityFactory(session)
+ .findTable(RName.getRName(DecisionTableName));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getDecisionTables(java.lang.String)
+ */
+ public List getDecisionTables(String rulesetname) {
+ if(rd==null)return null;
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ Iterator it = rs.getEntityFactory(session).getDecisionTableRNameIterator();
+ return getList(it);
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getList(Iterator iterator){
+ List list = new ArrayList();
+ while(iterator.hasNext()){
+ list.add(((IRObject)iterator.next()).stringValue());
+ }
+ return list;
+
+ }
+
+ /**
+ * Return the list of Entities known to the given ruleset
+ * @return List of Entity RName objects
+ * @see com.dtrules.admin.IRulesAdminService#getEntities(java.lang.String)
+ */
+ public List getEntities(String rulesetname) {
+ if(rd==null)return null;
+ try {
+ Iterator e = rd.getRuleSet(RName.getRName(rulesetname)).getEntityFactory(session)
+ .getEntityRNameIterator();
+ return getList(e);
+ } catch (RulesException e) {}
+ return null;
+ }
+
+ /**
+ * Return the RuleSet associated with the given RuleSet Name
+ * @return RuleSet A set of Decision Tables and Entities which define a RuleSet
+ * @see com.dtrules.admin.IRulesAdminService#getRuleset(java.lang.String)
+ */
+ public RuleSet getRuleset(String RulesetName) {
+ if(rd==null)return null;
+ return rd.getRuleSet(RName.getRName(RulesetName));
+ }
+
+ /**
+ * Returns the list of RuleSets known to this Rules Directory
+ * @return A List of RName objects giving the list Rule Sets
+ * @see com.dtrules.admin.IRulesAdminService#getRulesets()
+ */
+ public List<String> getRulesets() {
+ List<String> rulesets = new ArrayList<String>();
+ for(Iterator it = rd.getRulesets().keySet().iterator(); it.hasNext();){
+ RName name = (RName)it.next();
+ rulesets.add(name.stringValue());
+ }
+ return rulesets;
+ }
+
+ /**
+ * Loads the XML defining the RulesDirectory. The given path must be a
+ * path and filename which is valid in the file system, or a valid Java
+ * resource, or a valid URL.
+ * @param pathtoDT
+ * @see com.dtrules.admin.IRulesAdminService#initialize(java.lang.String)
+ */
+ public void initialize(String pathtoDTrules) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = path + "DTRules.xml";
+ if(pathtoDTrules != null){
+ file = pathtoDTrules;
+ }
+
+ try {
+ rd = new RulesDirectory("",file);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * This method changes (potentially) the attributes of an attribute of an
+ * Entity. The REntityEntry attribute must be populated correctly.
+ *
+ * @param rulesetname The Ruleset which holds the Entity for which the
+ * attribute applies.
+ * @param attribute Contains the Entity Name and all the other meta data
+ * for the attribute to be changed.
+ *
+ * @see com.dtrules.admin.IRulesAdminService#updateAttribute(java.lang.String, com.dtrules.entity.REntityEntry)
+ */
+ public void updateAttribute(REntity entity, String rulesetname, REntityEntry attribute) throws RulesException {
+ entity.addAttribute(attribute);
+
+ }
+ /**
+ * Updates the Decision Table XML specified in the RuleSet with the Decision Tables as
+ * currently held in memory.
+ */
+ public void saveDecisionTables(RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ String filepath = rs.getFilepath();
+ String filename = rs.getDT_XMLName();
+
+ OutputStream out;
+ try {
+ out = new FileOutputStream(filepath+filename);
+ } catch (FileNotFoundException e) {
+ throw new RulesException(
+ "OutputFileCreationError",
+ "saveDecisionTables",
+ "An error occured openning the file: "+filepath+filename+"\n"+e
+ );
+ }
+ saveDecisionTables(out,session,rulesetname);
+ }
+
+ /**
+ * Writes out the Decision Tables to the given output stream as the currently exist in
+ * Memory.
+ *
+ * @param out outputstream to write the decision tables to.
+ * @param session The session which gives us the outputstreams for debug statements and trace statements
+ * @param rulesetname The Rule Set to be written out to the output stream
+ * @throws RulesException
+ */
+ public void saveDecisionTables(OutputStream out, RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ EntityFactory ef = rs.getEntityFactory(session);
+
+ PrintStream ps = new PrintStream(out);
+ Iterator<RName> tables = ef.getDecisionTableRNameIterator();
+ ps.println("<decision_tables>");
+ while(tables.hasNext()){
+ RName dtname = tables.next();
+ ef.getDecisionTable(dtname).writeXML(ps);
+ }
+ ps.println("\n</decision_tables>");
+
+ }
+
+ /**
+ * Test function.
+ * @param args ignored.
+ */
+ public static void main(String args[]){
+ String path = "C:\\eclipse\\workspace\\EB_POC\\new_york_EB\\xml\\";
+ String file = path + "DTRules.xml";
+
+ RulesDirectory rd = new RulesDirectory("",file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ RSession session;
+ try {
+ OutputStream out = new FileOutputStream("c:\\temp\\dt.xml");
+ session = new RSession(rs);
+ RulesAdminService admin = new RulesAdminService(session, rd);
+
+ admin.saveDecisionTables(out, session, "ebdemo");
+ } catch (Exception e1) {
+ System.out.println(e1.toString());
+ }
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#updateEntity(java.lang.String, com.dtrules.entity.REntity)
+ */
+ public void saveEDD(RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ EntityFactory ef = rs.getEntityFactory(session);
+ String filepath = rs.getFilepath();
+ String filename = rs.getEDD_XMLName();
+
+ OutputStream out;
+ try {
+ out = new FileOutputStream(filepath+filename);
+ } catch (FileNotFoundException e) {
+ throw new RulesException(
+ "OutputFileCreationError",
+ "saveDecisionTables",
+ "An error occured openning the file: "+filepath+filename+"\n"+e
+ );
+ }
+ PrintStream ps = new PrintStream(out);
+ Iterator<RName> entities = ef.getEntityRNameIterator();
+ ps.println("<entity_data_dictionary>");
+ while(entities.hasNext()){
+ RName ename = entities.next();
+ ef.findRefEntity(ename).writeXML(ps);
+ }
+ ps.println("\n</entity_data_dictionary>");
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#updateRuleset(com.dtrules.session.RuleSet)
+ */
+ public void updateRuleset(RuleSet ruleset) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ /**
+ * Given an incomplete table, this method returns a balanced table.
+ * Entries in the table provided can be 'y', 'n', '-', or ' '. If
+ * blank, then it is assumed that the caller assumes this should be
+ * flushed out. If the result will be larger than 16 columns, an
+ * null is returned. (You can't have a table larger than 16 columns).
+ * @param table -- A partial truth table.
+ * @return
+ */
+ public String[][] balanceTable(String [] [] table){
+ int rows = table.length;
+ if(rows>4||rows<=0)return null;
+ int cols = 1<<(rows);
+
+ String newTable[][] = new String [rows][cols];
+
+ for(int i=0; i< cols; i++){
+ for(int j=0;j<rows; j++){
+ newTable[j][i]= ((i>>(rows-1-j))&1)==1?"n":"y";
+ }
+ }
+
+ return newTable;
+ }
+
+ public final RulesDirectory getRd() {
+ return rd;
+ }
+
+ public final RSession getSession() {
+ return session;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import java.util.List;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+
+/**
+ * @author Prasath Ramachandran
+ * Feb 1, 2007
+ *
+ */
+@SuppressWarnings({"unchecked"})
+public interface IRulesAdminService {
+
+ public void initialize(String pathtoDTrules);
+ public List<String> getRulesets(); // List of Ruleset Names
+ public RuleSet getRuleset(String RulesetName);
+ public void updateRuleset(RuleSet ruleset);
+ public void createRuleset(RuleSet ruleset) throws RulesException;
+
+ public List getDecisionTables(String rulesetname);
+ public RDecisionTable getDecisionTable(String rulesetname, String DecisionTableName);
+ public void saveDecisionTables(RSession session, String rulesetname) throws RulesException;
+ public RDecisionTable createDecisionTable(String rulesetname, String decisiontablename) throws RulesException;
+ //public Node getDecisionTableTree(String rulesetname) --- not needed now
+
+ public List getEntities(String rulesetname);
+ public List getAttributes(String rulesetname, String entityName);
+ public IREntity createEntity(String rulesetname, boolean readonly, String EntityName);
+ public boolean createAttribute(String rulesetname, REntityEntry attribute);
+ public void saveEDD(RSession session, String rulesetname)throws RulesException;
+ public void updateAttribute(REntity entity, String rulesetname,REntityEntry attribute)throws RulesException;
+
+ /**
+ * Given an incomplete table, this method returns a balanced table.
+ * Entries in the table provided can be 'y', 'n', '-', or ' '. If
+ * blank, then it is assumed that the caller assumes this should be
+ * flushed out. If the result will be larger than 16 columns, an
+ * null is returned. (You can't have a table larger than 16 columns).
+ * @param table -- A partial truth table.
+ * @return
+ */
+ public String[][] balanceTable(String [] [] table);
+ /**
+ * Given a Rule Set and an Entity, returns the list of EntityEntry objects
+ * that define the meta information about each attribute of the entity.
+ * @param rulesetname The Rule Set in which the entity is defined
+ * @param entityname The entity name of intrest.
+ * @return The list of Entity Entries that define the attributes of the Entity
+ */
+ public List<REntityEntry> getEntityEntries(String rulesetname, String entityname);
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+/**
+ * @author Prasath Ramachandran
+ * Feb 1, 2007
+ *
+ * The RulesAdminService provides all the methods for adding to and maintaining a
+ * Rules in DTRules. This is the interface to be used by editors and other tools
+ * to add/remove decision tables, modify the Entity Description Dictionary, and
+ * create and modify Rule Sets.
+ */
+@SuppressWarnings("unchecked")
+public class RulesAdminService implements IRulesAdminService{
+ final private RSession session;
+ private RulesDirectory rd; // The Rules Directory provides a place where Rule
+ // sets are defined.
+
+ /**
+ * The RulesAdminService needs a session for specifing the output of debugging
+ * and trace information. It needs a Rules Directory to administer.
+ */
+ public RulesAdminService(final RSession session, final RulesDirectory rd) {
+ super();
+ this.session = session;
+ this.rd = rd;
+ }
+
+ /**
+ * Create a new Attribute; The Entity modified is specified by the attribute.
+ * @param rulesetname The name of the RuleSet where the attribute should be created.
+ * @param attribute The REntityEntry defines the Entity to be modified. It is
+ * assumed that this Entity already exists.
+ * @return true if the attribute was successfully added.
+ */
+ public boolean createAttribute(final String rulesetname, final REntityEntry attribute) {
+ try {
+ RuleSet rs = getRuleset(rulesetname);
+ IREntity entity = rs.getEntityFactory(session).findRefEntity(attribute.attribute);
+ entity.addAttribute(attribute);
+ return true;
+ } catch (RulesException e) {
+ return false;
+ }
+
+ }
+
+ /**
+ * Given a Rule Set and an Entity, returns the list of EntityEntry objects
+ * that define the meta information about each attribute of the entity. If an
+ * error occurs while building the list, an empty list is returned.
+ *
+ * @param rulesetname The Rule Set in which the entity is defined
+ * @param entityname The entity name of intrest.
+ * @return The list of Entity Entries that define the attributes of the Entity
+ */
+ public List<REntityEntry> getEntityEntries(String rulesetname, String entityname){
+ ArrayList<REntityEntry> entries = new ArrayList<REntityEntry>();
+ RuleSet rs = getRuleset(rulesetname);
+ IREntity entity;
+ try {
+ entity = rs.getEntityFactory(session).findRefEntity(RName.getRName(entityname));
+ Iterator<RName> attribs = entity.getAttributeIterator();
+
+ while(attribs.hasNext()){
+ entries.add(entity.getEntry(attribs.next()));
+ }
+ } catch (RulesException e) { }
+
+ return entries;
+ }
+
+ /**
+ * Create a new Decision Table
+ */
+ public RDecisionTable createDecisionTable(String rulesetname, String decisiontablename)
+ throws RulesException{
+ RuleSet rs = getRuleset(rulesetname);
+ return rs.getEntityFactory(session).newDecisionTable(decisiontablename,session);
+ }
+
+ /**
+ * Creates a new Entity of the given name within the RuleSet. If
+ * the Entity already exists or the name is invalid, or this operation
+ * fails in any other way, a null is returned.
+ * @see com.dtrules.admin.IRulesAdminService#createEntity(java.lang.String, java.lang.String)
+ * @param rulesetname The name of the RuleSet in which to create this entity
+ * @param EntityName The name of the new Entity
+ */
+ public IREntity createEntity(String rulesetname, boolean readonly, String entityName) {
+ RName name = RName.getRName(entityName);
+ IREntity e = session.getEntityFactory().findRefEntity(name);
+ if(e!=null)return null;
+ try {
+ return session.getEntityFactory().findcreateRefEntity(readonly, name);
+ } catch (RulesException e1) {
+ return null;
+ }
+ }
+
+ /**
+ * Create a new Rule Set
+ * @see com.dtrules.admin.IRulesAdminService#createRuleset(com.dtrules.session.RuleSet)
+ */
+ public void createRuleset(RuleSet ruleset) throws RulesException{
+ rd.addRuleSet(ruleset);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getAttributes(java.lang.String, java.lang.String)
+ */
+ @SuppressWarnings("unchecked")
+ public List getAttributes(String rulesetname, String entityName) {
+ if(rd==null)return null;
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ Iterator it = rs.getEntityFactory(session)
+ .findRefEntity(RName.getRName(entityName)).getAttributeIterator();
+ return getList(it);
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getDecisionTable(java.lang.String, java.lang.String)
+ */
+ public RDecisionTable getDecisionTable(String rulesetname, String DecisionTableName) {
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ return rs.getEntityFactory(session)
+ .findTable(RName.getRName(DecisionTableName));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#getDecisionTables(java.lang.String)
+ */
+ public List getDecisionTables(String rulesetname) {
+ if(rd==null)return null;
+ try {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ Iterator it = rs.getEntityFactory(session).getDecisionTableRNameIterator();
+ return getList(it);
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List getList(Iterator iterator){
+ List list = new ArrayList();
+ while(iterator.hasNext()){
+ list.add(((IRObject)iterator.next()).stringValue());
+ }
+ return list;
+
+ }
+
+ /**
+ * Return the list of Entities known to the given ruleset
+ * @return List of Entity RName objects
+ * @see com.dtrules.admin.IRulesAdminService#getEntities(java.lang.String)
+ */
+ public List getEntities(String rulesetname) {
+ if(rd==null)return null;
+ try {
+ Iterator e = rd.getRuleSet(RName.getRName(rulesetname)).getEntityFactory(session)
+ .getEntityRNameIterator();
+ return getList(e);
+ } catch (RulesException e) {}
+ return null;
+ }
+
+ /**
+ * Return the RuleSet associated with the given RuleSet Name
+ * @return RuleSet A set of Decision Tables and Entities which define a RuleSet
+ * @see com.dtrules.admin.IRulesAdminService#getRuleset(java.lang.String)
+ */
+ public RuleSet getRuleset(String RulesetName) {
+ if(rd==null)return null;
+ return rd.getRuleSet(RName.getRName(RulesetName));
+ }
+
+ /**
+ * Returns the list of RuleSets known to this Rules Directory
+ * @return A List of RName objects giving the list Rule Sets
+ * @see com.dtrules.admin.IRulesAdminService#getRulesets()
+ */
+ public List<String> getRulesets() {
+ List<String> rulesets = new ArrayList<String>();
+ for(Iterator it = rd.getRulesets().keySet().iterator(); it.hasNext();){
+ RName name = (RName)it.next();
+ rulesets.add(name.stringValue());
+ }
+ return rulesets;
+ }
+
+ /**
+ * Loads the XML defining the RulesDirectory. The given path must be a
+ * path and filename which is valid in the file system, or a valid Java
+ * resource, or a valid URL.
+ * @param pathtoDT
+ * @see com.dtrules.admin.IRulesAdminService#initialize(java.lang.String)
+ */
+ public void initialize(String pathtoDTrules) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = path + "DTRules.xml";
+ if(pathtoDTrules != null){
+ file = pathtoDTrules;
+ }
+
+ try {
+ rd = new RulesDirectory("",file);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * This method changes (potentially) the attributes of an attribute of an
+ * Entity. The REntityEntry attribute must be populated correctly.
+ *
+ * @param rulesetname The Ruleset which holds the Entity for which the
+ * attribute applies.
+ * @param attribute Contains the Entity Name and all the other meta data
+ * for the attribute to be changed.
+ *
+ * @see com.dtrules.admin.IRulesAdminService#updateAttribute(java.lang.String, com.dtrules.entity.REntityEntry)
+ */
+ public void updateAttribute(REntity entity, String rulesetname, REntityEntry attribute) throws RulesException {
+ entity.addAttribute(attribute);
+
+ }
+ /**
+ * Updates the Decision Table XML specified in the RuleSet with the Decision Tables as
+ * currently held in memory.
+ */
+ public void saveDecisionTables(RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ String filepath = rs.getFilepath();
+ String filename = rs.getDT_XMLName();
+
+ OutputStream out;
+ try {
+ out = new FileOutputStream(filepath+filename);
+ } catch (FileNotFoundException e) {
+ throw new RulesException(
+ "OutputFileCreationError",
+ "saveDecisionTables",
+ "An error occured openning the file: "+filepath+filename+"\n"+e
+ );
+ }
+ saveDecisionTables(out,session,rulesetname);
+ }
+
+ /**
+ * Writes out the Decision Tables to the given output stream as the currently exist in
+ * Memory.
+ *
+ * @param out outputstream to write the decision tables to.
+ * @param session The session which gives us the outputstreams for debug statements and trace statements
+ * @param rulesetname The Rule Set to be written out to the output stream
+ * @throws RulesException
+ */
+ public void saveDecisionTables(OutputStream out, RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ EntityFactory ef = rs.getEntityFactory(session);
+
+ PrintStream ps = new PrintStream(out);
+ Iterator<RName> tables = ef.getDecisionTableRNameIterator();
+ ps.println("<decision_tables>");
+ while(tables.hasNext()){
+ RName dtname = tables.next();
+ ef.getDecisionTable(dtname).writeXML(ps);
+ }
+ ps.println("\n</decision_tables>");
+
+ }
+
+ /**
+ * Test function.
+ * @param args ignored.
+ */
+ public static void main(String args[]){
+ String path = "C:\\eclipse\\workspace\\EB_POC\\new_york_EB\\xml\\";
+ String file = path + "DTRules.xml";
+
+ RulesDirectory rd = new RulesDirectory("",file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ RSession session;
+ try {
+ OutputStream out = new FileOutputStream("c:\\temp\\dt.xml");
+ session = new RSession(rs);
+ RulesAdminService admin = new RulesAdminService(session, rd);
+
+ admin.saveDecisionTables(out, session, "ebdemo");
+ } catch (Exception e1) {
+ System.out.println(e1.toString());
+ }
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#updateEntity(java.lang.String, com.dtrules.entity.REntity)
+ */
+ public void saveEDD(RSession session, String rulesetname) throws RulesException {
+ RuleSet rs = rd.getRuleSet(RName.getRName(rulesetname));
+ EntityFactory ef = rs.getEntityFactory(session);
+ String filepath = rs.getFilepath();
+ String filename = rs.getEDD_XMLName();
+
+ OutputStream out;
+ try {
+ out = new FileOutputStream(filepath+filename);
+ } catch (FileNotFoundException e) {
+ throw new RulesException(
+ "OutputFileCreationError",
+ "saveDecisionTables",
+ "An error occured openning the file: "+filepath+filename+"\n"+e
+ );
+ }
+ PrintStream ps = new PrintStream(out);
+ Iterator<RName> entities = ef.getEntityRNameIterator();
+ ps.println("<entity_data_dictionary>");
+ while(entities.hasNext()){
+ RName ename = entities.next();
+ ef.findRefEntity(ename).writeXML(ps);
+ }
+ ps.println("\n</entity_data_dictionary>");
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.admin.IRulesAdminService#updateRuleset(com.dtrules.session.RuleSet)
+ */
+ public void updateRuleset(RuleSet ruleset) {
+ // TODO Auto-generated method stub
+
+ }
+
+
+ /**
+ * Given an incomplete table, this method returns a balanced table.
+ * Entries in the table provided can be 'y', 'n', '-', or ' '. If
+ * blank, then it is assumed that the caller assumes this should be
+ * flushed out. If the result will be larger than 16 columns, an
+ * null is returned. (You can't have a table larger than 16 columns).
+ * @param table -- A partial truth table.
+ * @return
+ */
+ public String[][] balanceTable(String [] [] table){
+ int rows = table.length;
+ if(rows>4||rows<=0)return null;
+ int cols = 1<<(rows);
+
+ String newTable[][] = new String [rows][cols];
+
+ for(int i=0; i< cols; i++){
+ for(int j=0;j<rows; j++){
+ newTable[j][i]= ((i>>(rows-1-j))&1)==1?"n":"y";
+ }
+ }
+
+ return newTable;
+ }
+
+ public final RulesDirectory getRd() {
+ return rd;
+ }
+
+ public final RSession getSession() {
+ return session;
+ }
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/decisiontables
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+CompilerError.java
+file
+
+
+
+
+2008-05-15T17:27:59.656250Z
+37f7ae08562c3e43a14c06d68c67615f
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+ANode.java
+file
+
+
+
+
+2008-06-19T16:00:18.343750Z
+5363b3e5bc6c1c45717361f24d1a68f8
+2008-06-19T16:05:25.781620Z
+9844
+psnow
+\f
+DecisionTableTypeTest.java
+file
+
+
+
+
+2008-08-21T15:18:49.328125Z
+7ebf89b1d77f6742c5d3d9cdd0bca548
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+RDecisionTable.java
+file
+
+
+
+
+2008-08-21T15:13:46.984375Z
+f11cf16b59d96219322c6cbf07c967ea
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+CNode.java
+file
+
+
+
+
+2008-06-19T16:03:51.812500Z
+1179e1ccd1d80894cfd717210a2641e3
+2008-06-19T16:05:25.781620Z
+9844
+psnow
+\f
+BalanceTable.java
+file
+11820
+
+
+
+2008-09-10T20:14:57.125000Z
+15096acd2e57bbf55f4fca3607088fcc
+2008-09-11T21:12:57.213608Z
+11820
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4184
+\f
+DTNode.java
+file
+
+
+
+
+2008-06-19T15:59:23.625000Z
+2d51f70cb8b1b49e70d61197bce3031f
+2008-06-19T16:05:25.781620Z
+9844
+psnow
+\f
+DTLoader.java
+file
+
+
+
+
+2008-09-04T03:06:47.093750Z
+8a07a90b175b48be6623bf9443d3ba8c
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13998
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.session.DTState;
+
+/**
+ * ANodes execute a list of actions.
+ * @author ps24876
+ *
+ */
+public class ANode implements DTNode {
+ RDecisionTable dtable; // The Decision Table to which this ANode belongs
+ ArrayList<IRObject> action = new ArrayList<IRObject>(); // The action postfix
+ ArrayList<Integer> anumbers = new ArrayList<Integer>(); // The action numbers (for tracing purposes)
+ ArrayList<Integer> columns = new ArrayList<Integer>(); // Keep track of the columns that send us here, for tracing
+ String section; // What section we are being called from.
+
+
+ public DTNode cloneDTNode(){
+ ANode newANode = new ANode(dtable);
+ newANode.action.addAll(this.action);
+ newANode.anumbers.addAll(this.anumbers);
+ newANode.columns.addAll(this.columns);
+ newANode.section = this.section;
+ return newANode;
+ }
+
+ public int getRow(){ return -1; }
+
+ /**
+ * Create and return an new ANode instance that holds all of the
+ * actions whose supposed to execute if this column executes.
+ * @param col (the zero based column number)
+ */
+ public static ANode newANode(RDecisionTable dt, int col){
+ //int cnt = 0;
+ ArrayList<IRObject> list = new ArrayList<IRObject> ();
+ ArrayList<Integer> numbers = new ArrayList<Integer>();
+ for(int i=0; i< dt.actiontable.length; i++){
+ if(dt.actiontable[i][col].equalsIgnoreCase("x")){
+ if(dt.ractions!=null && dt.ractions.length>=i){
+ list.add(dt.ractions[i]);
+ numbers.add(Integer.valueOf(i));
+ }
+ }
+ }
+ return new ANode(dt,col+1, list, numbers);
+ }
+
+ public void addNode(ANode node){
+ columns.addAll(node.columns);
+ for(int i=0;i<node.anumbers.size(); i++){
+ Integer index = node.anumbers.get(i);
+ if(!anumbers.contains(index)){
+ int v = index.intValue();
+ int pos = 0;
+ while(pos< anumbers.size() && anumbers.get(pos).intValue()<v) pos++;
+ anumbers.add(pos,index);
+ action.add(pos,dtable.ractions[v]);
+ }
+ }
+ }
+
+ public int countColumns(){
+ return 1;
+ }
+
+ private ANode(RDecisionTable dt, int column, ArrayList<IRObject> objects, ArrayList<Integer> numbers){
+ dtable = dt;
+ columns.add(new Integer(column));
+ action = objects;
+ anumbers = numbers;
+ }
+
+ public ANode(RDecisionTable dt){
+ dtable = dt;
+ }
+
+ /** Give the list of columns that got us to this ANode. Unbalanced tables
+ * can give us multiple columns in a single ANode
+ * @param columns
+ * @return
+ */
+ public String prtColumns(ArrayList<Integer> columns){
+ String s="";
+ for(Integer column : columns){
+ s += column.toString()+" ";
+ }
+ return s;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ Iterator<Integer> inum = anumbers.iterator();
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("Column", "n='"+prtColumns(columns)+"'");
+ }
+ for(IRObject v : action){
+ int num = inum.next().intValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("action","n='"+(num+1)+"'");
+ state.traceTagBegin("formal",null);
+ state.traceTagEnd("formal",dtable.getActions()[num]);
+ int d = state.ddepth();
+
+ try {
+ String section = state.getCurrentTableSection();
+ int numhld = state.getNumberInSection();
+ state.setCurrentTableSection("Action",num);
+ state.evaluate(v);
+ state.setCurrentTableSection(section, numhld);
+ } catch (RulesException e) {
+ e.setSection("Action",num+1);
+ throw e;
+ }
+ if(d!=state.ddepth()){
+ throw new RulesException("data stack unbalanced","ANode Execute","Action "+(num+1)+" in table "+dtable.getDtname());
+ }
+ state.traceTagEnd("action",null);
+ }else{
+ try {
+ String section = state.getCurrentTableSection();
+ int numhld = state.getNumberInSection();
+ state.setCurrentTableSection("Action",num);
+ state.evaluate(v);
+ state.setCurrentTableSection(section, numhld);
+ } catch (RulesException e) {
+ e.setSection("Action",num+1);
+ throw e;
+ }
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("Column", null);
+ }
+ }
+
+ public Coordinate validate() {
+ return null;
+ }
+
+ public String toString(){
+ return "Action Node for columns "+(prtColumns(columns));
+ }
+ /**
+ * An Action Node is equal to another DTNode if 1) it has one and
+ * only one set of actions it executes regardless of the path taken, and
+ * 2) if the actions this node takes are exactly the as the node provided.
+ */
+ public boolean equalsNode(DTNode node) {
+ ANode other = node.getCommonANode(); // Get the common path
+ if(other==null)return false; // No common path? Not Equal then!
+ if(other.anumbers.size()!=anumbers.size()) return false;// Must be the same length.
+ Iterator<Integer> iother = other.anumbers.iterator(); // Iterate through the other node's actions.
+ Iterator<Integer> ithis = anumbers.iterator(); // Also Iterate through this nodee's actions.
+ while(iother.hasNext()){ // The other node still has actions? loop!
+ if(!iother.next().equals(ithis.next()))return false;// Make sure each action is the same action.
+ } // If a mismatch is found, Not Equal!!!
+ return true;
+ }
+
+ public ANode getCommonANode() {
+ return this;
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.IRSession;
+
+/**
+ * Builds a balanced decision table from the given decision table.
+ * @author paul snow
+ * Mar 5, 2007
+ *
+ */
+public class BalanceTable {
+
+ private int maxRow=0,maxCol=0;
+ private int maxARow=0;
+ private String ctable[][] = new String[32][10240];
+ private String atable[][] = new String[32][10240];
+
+ final RDecisionTable dt;
+ public BalanceTable(RDecisionTable dt) throws RulesException{
+ this.dt = dt;
+ }
+
+ RDecisionTable balancedTable (IRSession s) throws RulesException{
+ if(!dt.isCompiled())dt.build();
+ if(!dt.isCompiled()){
+ throw new RulesException("DecisionTableError","balancedTable()","Malformed Decision Table");
+ }
+ RDecisionTable btable = (RDecisionTable) dt.clone(s);
+ ctable = btable.conditiontable;
+ atable = btable.actiontable;
+ filltable(0,0,btable.decisiontree);
+ btable.setType(RDecisionTable.Type.BALANCED);
+ btable.build();
+ return btable;
+ }
+
+ public String getPrintableTable(){
+ if(dt.decisiontree==null)return "empty table";
+ filltable(0, 0, dt.decisiontree);
+ StringBuffer buff = new StringBuffer();
+ buff.append("Number of Columns: "+maxCol+"\r\n\r\n");
+ String spacer = " ";
+ if(maxCol < 25) spacer = " ";
+
+
+ for(int i=0;i<maxRow;i++){
+ String row = (i+1)+"";
+ row = " ".substring(row.length())+row+spacer;
+ buff.append(row);
+ for(int j=0;j<maxCol; j++){
+ if(ctable[i][j]==null)ctable[i][j]="-";
+ buff.append(ctable[i][j]);
+ buff.append(spacer);
+ }
+ buff.append("\r\n");
+ }
+ buff.append("\n");
+ for(int i=0;i<=maxARow;i++){
+ String row = (i+1)+"";
+ row = " ".substring(row.length())+row+spacer;
+ buff.append(row);
+ for(int j=0;j<maxCol; j++){
+ if(atable[i][j]==null)atable[i][j]=" ";
+ buff.append(atable[i][j]);
+ buff.append(spacer);
+ }
+ buff.append("\r\n");
+ }
+ buff.append("\r\n");
+ return buff.toString();
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ if(maxARow<index) maxARow = index;
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.session.DTState;
+/**
+ * The Condition Node evaluates conditions within a Decision
+ * table.
+ * @author Paul Snow
+ *
+ */
+public class CNode implements DTNode {
+
+ final int column; //Column that created this node
+ final int conditionNumber; //NOPMD
+ final IRObject condition;
+ final RDecisionTable dtable; // Pointer back to the Decision Table for debug purposes
+
+ DTNode iftrue = null;
+ DTNode iffalse = null;
+
+ /**
+ * Clone this CNode and all the CNodes referenced by this CNode
+ */
+ public CNode cloneDTNode (){
+ CNode newCNode = new CNode(dtable,column,conditionNumber,condition);
+ newCNode.iftrue = iftrue == null ? null : iftrue.cloneDTNode();
+ newCNode.iffalse = iffalse == null ? null : iffalse.cloneDTNode();
+ return newCNode;
+ }
+
+ public int getRow(){ return conditionNumber; }
+ /**
+ * Two CNodes are equal if their true paths and their
+ * false paths are the same.
+ * And those CommonANodes have to be equal.
+ */
+ public boolean equalsNode(DTNode node) {
+ if(node.getClass().equals(CNode.class)){
+ CNode cnode = (CNode)node;
+ return(cnode.iffalse.equalsNode(iffalse) &&
+ cnode.iftrue.equalsNode(iftrue));
+ }else{
+ ANode me = getCommonANode(); // Get this CNode's commonANode.
+ if(me==null)return false; // If none exists, it can't be equal!
+ ANode him = getCommonANode(); // Get the other DTNode's commonANode
+ if(him==null)return false; // If none exists, it can't be equal!
+ return me.equalsNode(him); // Return true if this node matches that node!
+ }
+ }
+
+ /**
+ * To have a CommonANode, every path through the CNode (i.e. both
+ * the true path and the false path) has to have the same commonANode.
+ * So both iftrue and iffalse have to have a commonANode, and those have
+ * to match.
+ */
+ public ANode getCommonANode() {
+ ANode trueSide = iftrue.getCommonANode(); // Does the true side have a CommonANode
+ if(trueSide==null)return null; // Nope? false!
+ ANode falseSide = iffalse.getCommonANode(); // Does the false side have a CommonANode?
+ if(falseSide==null)return null; // Nope? false!
+ if(trueSide.equalsNode(falseSide))return trueSide; // If they match, I just have to return one of them!
+ return null; // If they don't match, I have to return false!
+ }
+
+
+
+ CNode(RDecisionTable dt, int column, int conditionNumber, IRObject condition){
+ this.column = column;
+ this.conditionNumber = conditionNumber;
+ this.condition = condition;
+ this.dtable = dt;
+ }
+
+ public int countColumns(){
+ int t = iftrue.countColumns();
+ int f = iffalse.countColumns();
+ return t+f;
+ }
+
+ public void execute(DTState state) throws RulesException{
+ boolean result;
+ try {
+ result = state.evaluateCondition(condition);
+ } catch (RulesException e) {
+ e.setSection("Condition",conditionNumber+1);
+ throw e;
+ }
+ if(state.testState(DTState.TRACE)){
+ if(state.testState(DTState.VERBOSE)){
+ state.traceTagBegin("Condition", "n='"+conditionNumber+"'"+"r='"+(result?"Y'":"N'"));
+ state.traceInfo("Formal", null,dtable.getConditions()[conditionNumber]);
+ state.traceTagEnd("Condition", "");
+ }else{
+ state.traceInfo("Condition", "n='"+conditionNumber+"'"+"r='"+(result?"Y'":"N'"));
+ }
+ }
+ if(result){
+ iftrue.execute(state);
+ }else{
+ iffalse.execute(state);
+ }
+ }
+
+ public Coordinate validate() {
+ if(iftrue == null || iffalse == null){
+ return new Coordinate(conditionNumber,column);
+ }
+ Coordinate result = iffalse.validate();
+ if(result!=null){
+ return result;
+ }
+
+ return iftrue.validate();
+ }
+
+ public String toString(){
+ return "Condition Number "+(conditionNumber+1);
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.session.ICompilerError;
+
+
+public class CompilerError implements ICompilerError {
+ final private Type errorType; //NOPMD Supid PMD wants a set method for a final field...
+ final private String message; //NOPMD
+ final private String source; //NOPMD Only valid for type ACTION or CONDITION
+
+
+ /**
+ * Returns the source string which caused the error.
+ * @return source
+ */
+ public String getSource() {
+ return source;
+ }
+ final private int index; //NOPMD Only valid for type INITIALACTION,
+ // ACTION, andCONDITON
+ final private int row; //NOPMD Only valid for type TABLE
+ final private int col; //NOPMD Only valid for type TABLE
+
+ /**
+ * Constructor for INITALACTION, ACTION or CONDITION errors.
+ * @param type
+ * @param message
+ * @param source
+ * @param index provided as a zero based number; reported 1 based.
+ */
+ public CompilerError(
+ final Type type,
+ final String message,
+ final String source,
+ final int index){
+ errorType = type;
+ this.message = message;
+ this.source = source;
+ row = 0;
+ col = 0;
+ this.index = index + 1;
+ }
+ /**
+ * Constructor for TABLE errors.
+ * @param type
+ * @param message
+ * @param row provided as a zero based number; reported 1 based.
+ * @param col provided as a zero based number; reported 1 based.
+ */
+ public CompilerError(
+ final Type type,
+ final String message,
+ final int row,
+ final int col){
+ errorType = type;
+ this.message = message;
+ this.source = "";
+ this.row = row+1;
+ this.col = col+1;
+ this.index = 0;
+ }
+
+
+ public int getActionIndex() {
+ if(errorType == Type.ACTION){
+ return index;
+ }
+ return 0;
+ }
+
+ public int getCol() {
+ return col;
+ }
+
+ public int getConditionIndex() {
+ if(errorType == Type.CONDITION){
+ return index;
+ }
+ return 0;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Type getErrorType() {
+ return errorType;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public int getRow() {
+ return row;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+/**
+ * The DTLoader loads decision tables into the EntityFactory. Warning messages
+ * are routed through a RSession object.
+ *
+ * @author paul snow
+ * Feb 12, 2007
+ *
+ */
+@SuppressWarnings({"unchecked","unused"})
+public class DTLoader implements IGenericXMLParser {
+
+ private transient String _tag;
+ private transient String _body;
+ private transient Map _attribs;
+
+ private final EntityFactory ef; // As tables are loaded, they need to be registered
+ // with the entity factory.
+ private final IRSession session; // Even though we are not building anything within
+ // a session, we need a session to print warning messages.
+ private final DTState state; // For error reporting.
+
+ private int context_cnt = 0; // Count of contexts
+ private int ia_cnt = 0; // Count of initial actions.
+ private int c_cnt = 0; // Count of conditions
+ private int a_cnt = 0; // Count of actions
+ private int col_cnt = 1; // Count of columns (We assume at least one column)
+ private int col = 0; // Current column
+
+ private boolean processing_fields = false; // This boolean is only set within the <attribute_fields> tag.
+ // Any tag within this tag is interpreted as an attribute of
+ // the decision table. The Table_type tag is treated special.
+ /**
+ * The limit here is many times too large for actual decision tables.
+ * In fact, one should throw an error if a table has more than 16 columns,
+ * or more than 16 actions. Tables larger than that are too hard to
+ * understand to be useful.
+ **/
+ static final int LIMIT = 100;
+
+ // Temp Space for collecting data for the decision tables
+ String context_formal [] = new String[LIMIT];
+ String context_postfix [] = new String[LIMIT];
+ String ia_formal [] = new String[LIMIT];
+ String ia_postfix [] = new String[LIMIT];
+ String ia_comment [] = new String[LIMIT];
+ String c_formal[] = new String[LIMIT];
+ String c_comment[] = new String[LIMIT];
+ String c_postfix[] = new String[LIMIT];
+ String c_table[][] = new String[LIMIT][LIMIT];
+ String a_formal[] = new String[LIMIT];
+ String a_comment[] = new String[LIMIT];
+ String a_postfix[] = new String[LIMIT];
+ String a_table[][] = new String[LIMIT][LIMIT];
+
+ RDecisionTable dt = null;
+
+ /**
+ * In order to load decision tables into an EntityFactory, we create
+ * a loader. The tables are loaded into the entityfactory, and warning
+ * messages will be routed through the session.
+ *
+ * @param _session
+ * @param _ef
+ */
+ public DTLoader(IRSession _session, EntityFactory _ef){
+ session = _session;
+ state = _session.getState();
+ ef = _ef;
+ }
+
+
+ public void end_decision_tables()throws Exception {
+ /**
+ * Now we build all the decision tables.
+ */
+ Iterator<RName> it = ef.getDecisionTableRNameIterator();
+ while(it.hasNext()){
+ try {
+ RDecisionTable dt = ef.getDecisionTable(it.next());
+ dt.build();
+
+ } catch (RulesException e) {
+ state.traceInfo("error", null,"Error building Decision Table "+dt+"\r\n"+e);
+ }
+ }
+ }
+
+
+ /**
+ * Handle the Decision Table setup and initialization.
+ */
+
+ /**
+ * Decision Table Name
+ * @throws RulesException
+ */
+ public void end_table_name() throws RulesException {
+ dt = ef.newDecisionTable(_body, session);
+
+ c_cnt = 0;
+ a_cnt = 0;
+ col_cnt = 1;
+ col = 0;
+ ia_cnt = 0;
+ context_cnt = 0;
+
+ c_table = new String[LIMIT][LIMIT];
+ a_table = new String[LIMIT][LIMIT];
+
+ }
+
+ /**
+ * All done gathering the info for the table. Now we need to
+ * pack it away into the actual decision table.
+ *
+ */
+ public void end_decision_table(){
+ /** Contexts do not have comments **/
+ dt.contexts = new String[context_cnt];
+ dt.contextsPostfix = new String[context_cnt];
+
+ /** Initial Actions have Comments, descriptions, and postfix **/
+ dt.initialActionsComment = new String[ia_cnt];
+ dt.initialActions = new String[ia_cnt];
+ dt.initialActionsPostfix = new String[ia_cnt];
+
+ /** The count of columns for Conditions and actions have to match **/
+ dt.maxcol = col_cnt;
+
+ /** Conditions have a comment, description, Postfix, and a truth table **/
+ dt.conditionsComment = new String[c_cnt];
+ dt.conditions = new String[c_cnt];
+ dt.conditionsPostfix = new String[c_cnt];
+ dt.conditiontable = new String[c_cnt][col_cnt];
+
+ /** Actions have a comment, description, Postfix, and a action table **/
+ dt.actionsComment = new String[a_cnt];
+ dt.actions = new String[a_cnt];
+ dt.actionsPostfix = new String[a_cnt];
+ dt.actiontable = new String[a_cnt][col_cnt];
+
+ //Move over the information for the contexts
+ for(int i=0;i<context_cnt;i++){
+ dt.contexts[i] = context_formal[i];
+ dt.contextsPostfix[i] = context_postfix[i];
+ }
+
+ //Move over the information for actions
+ for(int i=0;i<ia_cnt;i++){
+ dt.initialActions[i] =ia_formal[i];
+ dt.initialActionsPostfix[i] =ia_postfix[i];
+ dt.initialActionsComment[i] =ia_comment[i];
+ }
+
+ //Move over the information for the conditions
+ for(int i=0;i<c_cnt;i++){
+ dt.conditions[i] = c_formal[i];
+ dt.conditionsComment[i] = c_comment[i]==null?"":c_comment[i];
+ dt.conditionsPostfix[i] = c_postfix[i]==null?"":c_postfix[i];
+ for(int j=0;j<col_cnt;j++){
+ String v = c_table[i][j];
+ dt.conditiontable[i][j]= v==null ? " " : v ;
+ }
+ }
+
+ //Move over the information for the actions
+ for(int i=0;i<a_cnt;i++){
+ dt.actions[i] = a_formal[i];
+ dt.actionsComment[i] = a_comment[i]==null?"":a_comment[i];
+ dt.actionsPostfix[i] = a_postfix[i]==null?"":a_postfix[i];
+ for(int j=0;j<col_cnt;j++){
+ String v = a_table[i][j];
+ dt.actiontable[i][j]= v==null ? " " : v;
+ }
+ }
+ }
+
+ /**
+ * Set the filename on the Decision Table
+ */
+ public void end_xls_file(){
+ dt.setFilename(_body);
+ }
+
+ /** Turn on field processing when the <attribute_field> tag is encountered
+ *
+ */
+ public void begin_attribute_fields() {
+ processing_fields = true;
+ }
+ /**
+ * Turn off attribute field processing outside the </attribute_filed> tag
+ */
+ public void end_attribute_fields() {
+ processing_fields = false;
+ }
+
+ /**
+ * Mostly we just collect attribute fields. But if the attribute field is the
+ * table_type tag, then it has to have a value of FIRST, ALL, or BALANCED.
+ */
+ public void process_field() throws RulesException {
+ dt.fields.put(RName.getRName(_tag),_body);
+ if(_tag.equalsIgnoreCase("type")){
+ if(_body.equalsIgnoreCase("first")){
+ dt.setType(RDecisionTable.Type.FIRST);
+ }else if (_body.equalsIgnoreCase("all")){
+ dt.setType(RDecisionTable.Type.ALL);
+ }else if (_body.equalsIgnoreCase("balanced")){
+ dt.setType(RDecisionTable.Type.BALANCED);
+ }else {
+ throw new RulesException("Invalid","Decision Table Load","Bad Decision Table type Encountered: '"+_body+"'");
+ }
+ }
+ }
+
+
+ /*
+ * Handle each condition in turn.
+ *
+ */
+
+ public void begin_condition_details(){
+ col=0; // Start at the begining of the columns again.
+ }
+
+ public void end_context_description(){
+ context_formal[context_cnt] = _body;
+ }
+
+ public void end_context_postfix (){
+ context_postfix[context_cnt] = _body;
+ }
+
+ public void end_context_details (){
+ context_cnt++;
+ }
+
+ public void end_initial_action_description(){
+ ia_formal[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_comment(){
+ ia_comment[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_postfix () {
+ ia_postfix[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_details () {
+ ia_cnt++;
+ }
+
+
+ public void end_condition_description(){
+ c_formal[c_cnt]=_body;
+ }
+
+ public void end_condition_postfix(){
+ c_postfix[c_cnt]=_body;
+ }
+
+ public void end_condition_comment(){
+ c_comment[c_cnt]=_body;
+ }
+
+ public void begin_condition_column() throws RulesException {
+ if(col>=col_cnt){
+ col_cnt++;
+ }
+ int theCol = Integer.parseInt((String)_attribs.get("column_number"))-1;
+ c_table[c_cnt][theCol]= (String) _attribs.get("column_value");
+ col++;
+ }
+
+ public void end_condition_details(){
+ c_cnt++;
+ }
+
+ /*
+ * Load Actions
+ */
+
+
+ public void begin_action_details(){
+ for(int i=0;i<col_cnt;i++){
+ a_table[a_cnt][i]="";
+ }
+ }
+
+ public void end_action_description(){
+ a_formal[a_cnt]=_body;
+ }
+
+ public void end_action_postfix(){
+ a_postfix[a_cnt]=_body;
+ }
+
+ public void end_action_comment(){
+ a_comment[a_cnt]=_body;
+ }
+
+ public void begin_action_column() {
+ int a_col = Integer.parseInt((String)_attribs.get("column_number"))-1;
+ if(a_col>=col_cnt){
+ throw new RuntimeException("Decision Table Loader: Too many columns found in "+dt.toString());
+ }
+ String a_v = (String)_attribs.get("column_value");
+
+ a_table[a_cnt][a_col]= a_v;
+ }
+
+ public void end_action_details() {
+ a_cnt++;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+
+ _tag = tag;
+ _attribs = attribs;
+ _body = null;
+ String tagname = "begin_"+tag;
+ try {
+ Method m = methodCache.get(tagname);
+ if(m==null){
+ m = this.getClass().getMethod(tagname,(Class [])null);
+ methodCache.put(tagname,m);
+ }
+ m.invoke(this,(Object [])null);
+ } catch (NoSuchMethodException e){ // Ignore undefined tags
+ } catch (InvocationTargetException e){ // Ignore errors thrown by Decision Table parsing
+ throw new RuntimeException("An Invocation Target Exception was thrown processing the Begin XML tag "+tag+
+ "\nError states: "+e.getCause());
+ } catch (Exception e) {
+ state.traceInfo("error", null,e.getCause().getMessage());
+ throw new RuntimeException("Error Parsing Decision Tables: "+e.getMessage());
+ }
+ }
+
+ HashMap<String,Method> methodCache = new HashMap<String,Method>();
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+
+ _tag = tag;
+ _attribs = attribs;
+ body = body.trim().replaceAll("[\\n\\r]"," ");
+ _body = body;
+ String tagname = "end_"+tag;
+ try {
+ Class[] classArr = null;
+ Object[] objArr = null;
+ Method m = methodCache.get(tagname);
+ if(m==null){
+ m = this.getClass().getMethod(tagname,classArr);
+ methodCache.put(tagname, m);
+ }
+ m.invoke(this, objArr);
+ } catch (NoSuchMethodException e){ // Ignore undefined tags
+ if(processing_fields){ // Unless we are in the attribute files section.
+ process_field();
+ }
+ } catch (InvocationTargetException e){ // Ignore errors thrown by Decision Table parsing
+ state.traceInfo("error", null,"An Invocation Target Exception was thrown processing the End XML tag "+tag+
+ "\nError states "+e.getCause());
+ } catch (Exception e) {
+ state.traceInfo("error", null,e.getCause().getMessage());
+ throw new RuntimeException("Error Parsing Decision Tables: "+e.getMessage());
+ }
+
+ }
+
+ /**
+ * Skip DTD stuff and other parsing things the Rules Engine doesn't
+ * care about.
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+public interface DTNode {
+ static class Coordinate {
+ int row;
+ int col;
+ Coordinate(int row, int col){
+ this.row = row;
+ this.col = col;
+ }
+ public int getCol() {
+ return col;
+ }
+ public void setCol(int col) {
+ this.col = col;
+ }
+ public int getRow() {
+ return row;
+ }
+ public void setRow(int row) {
+ this.row = row;
+ }
+ }
+
+ public int getRow();
+
+ /**
+ * Returns a clone of this node, and all nodes below (if it
+ * has subnodes).
+ * @return
+ */
+ public DTNode cloneDTNode();
+
+ public int countColumns();
+
+ void execute(DTState state) throws RulesException;
+ Coordinate validate();
+
+ /**
+ * For two DTNodes are equal if every path through both nodes
+ * execute exactly the same set of Actions.
+ * @param node
+ * @return
+ */
+ boolean equalsNode(DTNode node);
+ /**
+ * Returns an ANode which represents the execution of every
+ * path through the given DTNode. If different paths through
+ * the DTNode execute different actions, this method returns
+ * a null. Note that ANodes always return themselves (i.e.
+ * there is only one execution path through an ANode).
+ */
+ ANode getCommonANode();
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+public class DecisionTableTypeTest {
+
+ int maxRow=0,maxCol=0;
+ String ctable [][] = new String[128][128];
+ String atable [][] = new String[128][128];
+ RDecisionTable dt;
+
+ public DecisionTableTypeTest(IRSession session, RuleSet rs) throws RulesException{
+
+ dt = new RDecisionTable(session, rs, "test");
+
+ String ctable[][] = {
+ { "y", "n", "n", "y", "d", "a" },
+ { "n", "n", "y", " ", " ", " " },
+ { "y", "y", "y", "n", " ", " " },
+ { "y", "y", " ", " ", " ", " " },
+ { " ", " ", "y", " ", " ", " " },
+ { "y", " ", " ", " ", " ", " " },
+
+ };
+ dt.conditiontable = ctable;
+
+ String atable[][] = {
+ { "x", " ", " ", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", " ", " ", "x", "x", " " },
+ { " ", " ", " ", " ", "x", " " },
+ { " ", " ", " ", "x", " ", "x" },
+ };
+ dt.maxcol = ctable[0].length;
+ dt.actiontable = atable;
+ dt.rconditions = new IRObject[ctable.length];
+ dt.ractions = new IRObject[atable.length];
+
+ String cps[] = new String[ctable.length];
+ for (int i = 0; i < cps.length; i++)
+ cps[i] = "{ 'Condition " + i + "' }";
+
+ String aps[] = new String[atable.length];
+ for (int i = 0; i < aps.length; i++)
+ aps[i] = "{ 'Action " + i + "' }";
+
+ dt.conditions = cps;
+ dt.conditionsPostfix = cps;
+ dt.actions = aps;
+ dt.actionsPostfix = aps;
+ dt.setType(RDecisionTable.Type.FIRST);
+ }
+
+ public static void main(String[] args) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = "DTRules.xml";
+ if(args.length>0){
+ file = args[0];
+ }
+
+ try {
+ RulesDirectory rd = new RulesDirectory(path,file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ IRSession session = rs.newSession();
+ DecisionTableTypeTest test;
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.FIRST);
+ test.dt.build();
+ test.printtable ();
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.ALL);
+ test.dt.build();
+ test.printtable ();
+
+
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
+
+ }
+
+ void printtable(){
+ maxRow = maxCol = 0;
+ filltable(0,0,dt.decisiontree);
+
+ System.out.print(" ");
+ for(int i=0;i<maxCol;i++){
+ System.out.print(i+((i<10)?" ":" "));
+ }
+ System.out.println();
+ for(int i=0;i<maxRow;i++){
+ System.out.print(dt.conditions[i]+" ");
+ for(int j=0; j<maxCol;j++){
+ System.out.print(ctable[i][j]==null?"- ":ctable[i][j]+" ");
+ }
+ System.out.println();
+ }
+ System.out.println("--------------------------------------");
+ for(int i=0;i<dt.actions.length;i++){
+ System.out.print(dt.actions[i]+" ");
+ for(int j=0;j<maxCol;j++){
+ System.out.print(atable[i][j]==null?" ":"X ");
+ }
+ System.out.println();
+ }
+ Iterator<ICompilerError> errors = dt.getErrorList().iterator();
+ while(errors.hasNext()){
+ ICompilerError error = errors.next();
+ System.out.println(error.getMessage()+
+ " on "+"Row " + error.getRow()+" Column "+error.getCol());
+
+
+ }
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.dtrules.decisiontables.DTNode.Coordinate;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+/**
+ * Decision Tables are the classes that hold the Rules for a set of Policy
+ * implemented using DTRules. There are three types: <br><br>
+ *
+ * BALANCED -- These decision tables expect all branches to be defined in the condition table <br>
+ * ALL -- Evaluates all the columns, then executes all the actions, in the order they
+ * are specified, for all columns whose conditions are met.<br>
+ * FIRST -- Effectively evaluates each column, and executes only the first Column whose
+ * conditions are met.<br>
+ * @author paul snow
+ * Mar 1, 2007
+ *
+ */
+public class RDecisionTable extends ARObject {
+
+ private final RName dtname; // The decision table's name.
+
+ private String filename = null; // Filename of Excel file where the table is defined,
+ // if this decision table is defined in Excel.
+
+ enum UnbalancedType { FIRST, ALL }; // Unbalanced Table Types.
+ public static enum Type {
+ BALANCED { void build(RDecisionTable dt) {dt.buildBalanced(); }},
+ FIRST { void build(RDecisionTable dt) {dt.buildUnbalanced(UnbalancedType.FIRST); }},
+ ALL { void build(RDecisionTable dt) {dt.buildUnbalanced(UnbalancedType.ALL); }};
+ abstract void build(RDecisionTable dt);
+ }
+
+ public Type type = Type.BALANCED; // By default, all decision tables are balanced.
+
+ public static final int MAXCOL = 16; // The Maximum number of columns in a decision table.
+
+ int maxcol = 1; // The number of columns in this decision table.
+
+ private final RuleSet ruleset; // A decision table must belong to a particular ruleset
+
+ public final Map<RName,String> fields = new HashMap<RName, String>(); // Holds meta information about this decision table.
+
+ private boolean compiled=false; // The decision table isn't compiled
+ // until fully constructed. And
+ // it won't be if compilation fails.
+ String [][] conditiontable;
+ String [] conditions; // The conditions in formal. The formal langauge is compiled to get the postfix
+ String [] conditionsPostfix; // The conditions in postfix. derived from the formal
+ String [] conditionsComment; // A comment per condition.
+ IRObject [] rconditions; // Each compiled condition
+
+ String [][] actiontable;
+ String [] actions;
+ String [] actionsComment;
+ String [] actionsPostfix;
+ IRObject [] ractions; // Each compiled action
+
+
+ String [] initialActions; // A list of actions to be executed each time the
+ // decision table is executed before the conditions
+ // are evaluated.
+ IRObject [] rinitialActions;
+ String [] initialActionsPostfix; // Compiled Initial Actions
+ String [] initialActionsComment; // Comment for Initial Actions
+ String [] contexts; // Contexts in which to execute this table.
+ String [] contextsPostfix; // The Postfix for each context statement.
+ String contextsrc; // For Tracing...
+ IRObject rcontext; // lists of entities. It is best if this is done within the table than
+ // by the calling table.
+
+ List<ICompilerError> errorlist = new ArrayList<ICompilerError>();
+ DTNode decisiontree=null;
+
+ private int numberOfRealColumns = 0; // Number of real columns (as unbalanced tables can have
+ // far more columns than they appear to have).
+
+ public int getNumberOfRealColumns() {
+ if(decisiontree==null)return 0;
+ return decisiontree.countColumns();
+ }
+
+ /**
+ * Check for errors in the decision table. Returns the column
+ * and row of a problem if one is found. If nothing is wrong,
+ * a null is returned.
+ * @return
+ */
+ public Coordinate validate(){
+ if(decisiontree==null){
+ if(actions !=null && actions.length==0)return null;
+ return new Coordinate(0,0);
+ }
+ return decisiontree.validate();
+ }
+
+ BalanceTable balanceTable = null; // Helper class to build a balanced or optimized version
+ // of this decision table.
+
+ public boolean isCompiled(){return compiled;}
+
+
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ @Override
+ public IRObject clone(IRSession s) throws RulesException {
+ RDecisionTable dt = new RDecisionTable(s,ruleset, dtname.stringValue());
+ dt.numberOfRealColumns = numberOfRealColumns;
+ dt.conditiontable = conditiontable.clone();
+ dt.conditions = conditions.clone();
+ dt.conditionsPostfix = conditionsPostfix.clone();
+ dt.conditionsComment = conditionsComment.clone();
+ dt.rconditions = rconditions.clone();
+ dt.actiontable = actiontable.clone();
+ dt.actions = actions.clone();
+ dt.actionsComment = actionsComment.clone();
+ dt.actionsPostfix = actionsPostfix.clone();
+ dt.ractions = ractions.clone();
+ dt.rinitialActions = rinitialActions.clone();
+ dt.initialActions = initialActions.clone();
+ dt.initialActionsComment = initialActionsComment.clone();
+ dt.initialActionsPostfix = initialActionsPostfix.clone();
+ dt.contexts = contexts.clone();
+ dt.contextsPostfix = contextsPostfix.clone();
+ dt.contextsrc = contextsrc;
+ dt.rcontext = rcontext.clone(s);
+ return dt;
+ }
+ /**
+ * Changes the type of the given decision table. The table is rebuilt.
+ * @param type
+ * @return Returns a list of errors which occurred when the type was changed.
+ */
+ public void setType(Type type) {
+ this.type = type;
+ }
+ /**
+ * This routine compiles the Context statements for the
+ * decision table into a single executable array.
+ * It must embed into this array a call to executeTable
+ * (which avoids this context building for the table).
+ */
+ private void buildContexts(){
+ // Nothing to do if no extra contexts are specfied.
+ if(contextsPostfix==null || contextsPostfix.length==0) return;
+
+ // This is the call to executeTable against this decisiontable
+ // that we are going to embed into our executable array.
+ contextsrc = "/"+getName().stringValue()+" executeTable ";
+
+ boolean keep = false;
+ for(int i=contextsPostfix.length-1;i>=0;i--){
+ if(contextsPostfix[i]!=null){
+ contextsrc = "{ "+contextsrc+" } "+contextsPostfix[i];
+ keep = true;
+ }
+ }
+ if(keep == true){
+ try {
+ rcontext = RString.compile(ruleset, contextsrc, true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError (
+ ICompilerError.Type.CONTEXT,
+ "Formal Compiler Error: "+e,
+ contextsrc,0));
+ }
+ }
+ }
+
+ /**
+ * Build this decision table according to its type.
+ *
+ */
+ public void build(){
+ errorlist.clear();
+ decisiontree = null;
+ buildContexts();
+ /**
+ * If a context or contexts are specified for this decision table,
+ * compile the context formal into postfix.
+ */
+ type.build(this);
+ }
+
+ /**
+ * Return the name of this decision table.
+ * @return
+ */
+ public RName getName(){
+ return dtname;
+ }
+
+ /**
+ * Renames this decision table.
+ * @param session
+ * @param newname
+ * @throws RulesException
+ */
+ public void rename(IRSession session, RName newname)throws RulesException{
+ ruleset.getEntityFactory(session).deleteDecisionTable(dtname);
+ ruleset.getEntityFactory(session).newDecisionTable(newname, session);
+ }
+
+ /**
+ * Create a Decision Table
+ * @param tables
+ * @param name
+ * @throws RulesException
+ */
+
+ public RDecisionTable(IRSession session, RuleSet _ruleset, String name) throws RulesException{
+ ruleset = _ruleset;
+ dtname = RName.getRName(name,true);
+ EntityFactory ef = ruleset.getEntityFactory(session);
+ RDecisionTable dttable =ef.findDecisionTable(RName.getRName(name));
+ if(dttable != null){
+ new CompilerError(CompilerError.Type.TABLE,"Duplicate Decision Tables Found",0,0);
+ }
+ }
+
+ /**
+ * Compile each condition and action. We mark the decision table as
+ * uncompiled if any error is detected. However, we still attempt to
+ * compile all conditions and all actions.
+ */
+ public List<ICompilerError> compile(){
+ compiled = true; // Assume the compile will work.
+ rconditions = new IRObject[conditionsPostfix.length];
+ ractions = new IRObject[actionsPostfix.length];
+ rinitialActions = new IRObject[initialActionsPostfix.length];
+
+ for(int i=0; i< initialActions.length; i++){
+ try {
+ rinitialActions[i] = RString.compile(ruleset, initialActionsPostfix[i],true);
+ } catch (Exception e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.INITIALACTION,
+ "Postfix Interpretation Error: "+e,
+ initialActionsPostfix[i],
+ i
+ )
+ );
+ compiled = false;
+ rinitialActions[i]=RNull.getRNull();
+ }
+ }
+
+ for(int i=0;i<rconditions.length;i++){
+ try {
+ rconditions[i]= RString.compile(ruleset, conditionsPostfix[i],true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.CONDITION,
+ "Postfix Interpretation Error: "+e,
+ conditionsPostfix[i],
+ i
+ )
+ );
+ compiled=false;
+ rconditions[i]=RNull.getRNull();
+ }
+ }
+ for(int i=0;i<ractions.length;i++){
+ try {
+ ractions[i]= RString.compile(ruleset, actionsPostfix[i],true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.ACTION,
+ "Postfix Interpretation Error: "+e,
+ actionsPostfix[i],
+ i
+ )
+ );
+ compiled=false;
+ ractions[i]=RNull.getRNull();
+ }
+ }
+ return errorlist;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ RDecisionTable last = state.getCurrentTable();
+ state.setCurrentTable(this);
+ try {
+ int estk = state.edepth();
+ int dstk = state.ddepth();
+ int cstk = state.cdepth();
+
+ state.pushframe();
+
+ if(rcontext==null){
+ executeTable(state);
+ }else{
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("context", "execute='"+contextsrc+"'");
+ try {
+ rcontext.execute(state);
+ } catch (RulesException e) {
+ e.setSection("Context", 0);
+ throw e;
+ }
+ state.traceTagEnd("context", null);
+ }else{
+ rcontext.execute(state);
+ }
+ }
+ state.popframe();
+
+ if(estk!= state.edepth() ||
+ dstk!= state.ddepth() ||
+ cstk!= state.cdepth() ){
+ throw new RulesException("Stacks Not balanced","DecisionTables",
+ "Error while executing table: "+getName().stringValue() +"\n" +
+ (estk!= state.edepth() ? "Entity Stack before "+estk+" after "+state.edepth()+"\n":"")+
+ (dstk!= state.ddepth() ? "Data Stack before "+dstk+" after "+state.ddepth()+"\n":"")+
+ (cstk!= state.cdepth() ? "Control Stack before "+cstk+" after "+state.cdepth()+"\n":""));
+ }
+ } catch (RulesException e) {
+ e.addDecisionTable(this.getName().stringValue(), this.getFilename());
+ state.setCurrentTable(last);
+ throw e;
+ }
+ state.setCurrentTable(last);
+ }
+
+ /**
+ * A decision table is executed by simply executing the
+ * binary tree underneath the table.
+ */
+ public void executeTable(DTState state) throws RulesException {
+ if(compiled==false){
+ throw new RulesException(
+ "UncompiledDecisionTable",
+ "RDecisionTable.execute",
+ "Attempt to execute an uncompiled decision table: "+dtname.stringValue()
+ );
+ }
+
+ boolean trace = state.testState(DTState.TRACE);
+ int edepth = state.edepth(); // Get the initial depth of the entity stack
+ // so we can toss any extra entities added...
+ if(trace){
+ state.traceTagBegin("decisiontable","tID='"+state.tracePt()+"' name='"+dtname+"'");
+ if(state.testState(DTState.VERBOSE)){
+ state.traceTagBegin("entity_stack", null);
+ for(int i=0;i<state.edepth();i++){
+ state.traceInfo("entity", "id='"+state.getes(i).getID()+"'", state.getes(i).stringValue());
+ }
+ state.traceTagEnd("entity_stack",null);
+ }
+ state.traceTagBegin("initialActions", null);
+ for( int i=0; rinitialActions!=null && i<rinitialActions.length; i++){
+ try{
+ rinitialActions[i].execute(state);
+ }catch(RulesException e){
+ e.setSection("Initial Actions", i+1);
+ throw e;
+ }
+ }
+ state.traceTagEnd("initialActions", null);
+ if(decisiontree!=null)decisiontree.execute(state);
+ state.traceTagEnd ("decisiontable",null);
+
+ }else{
+ for( int i=0; rinitialActions!=null && i<rinitialActions.length; i++){
+ state.setCurrentTableSection("InitialActions", i);
+ try{
+ rinitialActions[i].execute(state);
+ }catch(RulesException e){
+ e.setSection("Initial Actions", i+1);
+ throw e;
+ }
+ }
+ if(decisiontree!=null)decisiontree.execute(state);
+ }
+ while(state.edepth() > edepth)state.entitypop(); // Pop off extra entities.
+ }
+
+ /**
+ * Builds (if necessary) the internal representation of the decision table,
+ * then validates that structure.
+ * @return true if the structure builds and is valid; false otherwise.
+ */
+ public List<ICompilerError> getErrorList() {
+ if(decisiontree==null){
+ errorlist.clear();
+ build();
+ }
+ return errorlist;
+ }
+
+
+
+
+ /**
+ * Builds the decision tree, which is a binary tree of "DTNode"'s which can be executed
+ * directly. This defines the execution of a Decision Table.
+ * <br><br>
+ * The way we build this binary tree is we walk down each column, tracing
+ * that column's path through the decision tree. Once we are at the end of the column,
+ * we add on the actions. This algorithm assumes that a decision table describes
+ * a complete decision tree, i.e. there is no set of posible condition states which
+ * are not explicitly handled by the decision table.
+ *
+ */
+ void buildBalanced() {
+ compile();
+ if(conditiontable[0].length == 0 || // If we have no conditions, or
+ conditiontable[0][0].equals("*")){ // If *, we just execute all actions
+ decisiontree = ANode.newANode(this,0); // checked in the first column
+ return;
+ }
+
+ decisiontree = new CNode(this,0,0, rconditions[0]); // Allocate a root node.
+
+ for(int col=0;col<maxcol;col++){ // For each column, we are going to run down the
+ // column building that path through the tree.
+ boolean laststep = conditiontable[0][col].equalsIgnoreCase("y"); // Set the test for the root condition.
+ CNode last = (CNode) decisiontree; // The last node will start as the root.
+
+ for(int i=1; i<conditiontable.length; i++){ // Now go down the rest of the conditions.
+ String t = conditiontable[i][col]; // Get this conditions truth table entry.
+ boolean yes = t.equalsIgnoreCase("y");
+ boolean invalid = false;
+ if(yes || t.equalsIgnoreCase("n")){ // If this condition should be considered...
+ CNode here=null;
+ try {
+ if(laststep){
+ here = (CNode) last.iftrue;
+ }else{
+ here = (CNode) last.iffalse;
+ }
+ if(here == null){ // Missing a CNode? Create it!
+ here = new CNode(this,col,i,rconditions[i]);
+ if(laststep){
+ last.iftrue = here;
+ }else{
+ last.iffalse = here;
+ }
+ }
+ } catch (RuntimeException e) {
+ invalid = true;
+ }
+ if(invalid || here.conditionNumber != i ){
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.TABLE,
+ "Condition Table Compile Error ",
+ i,col
+ )
+ );
+ return;
+ }
+ last = here;
+ laststep = yes;
+ }
+ }
+ if(laststep){ // Once we have traced the column, add the actions.
+ last.iftrue=ANode.newANode(this,col);
+ }else{
+ last.iffalse=ANode.newANode(this,col);
+ }
+
+ }
+ DTNode.Coordinate rowCol = decisiontree.validate();
+ if(rowCol!=null){
+ errorlist.add(
+ new CompilerError(ICompilerError.Type.TABLE,"Condition Table isn't balanced.",rowCol.row,rowCol.col)
+ );
+ compiled = false;
+ }
+ }
+
+ boolean newline=true;
+
+ private void printattrib(PrintStream p, String tag, String body){
+ if(!newline){p.println();}
+ p.print("<"); p.print(tag); p.print(">");
+ p.print(body);
+ p.print("</"); p.print(tag); p.print(">");
+ newline = false;
+ }
+
+ private void openTag(PrintStream p,String tag){
+ if(!newline){p.println();}
+ p.print("<"); p.print(tag); p.print(">");
+ newline=false;
+ }
+
+ /**
+ * Write the XML representation of this decision table to the given outputstream.
+ * @param o Output stream where the XML for this decision table will be written.
+ */
+ public void writeXML(PrintStream p){
+ p.println("<decision_table>");
+ newline = true;
+ printattrib(p,"table_name",dtname.stringValue());
+ Iterator<RName> ifields = fields.keySet().iterator();
+ while(ifields.hasNext()){
+ RName name = ifields.next();
+ printattrib(p,name.stringValue(),fields.get(name));
+ }
+ openTag(p, "conditions");
+ for(int i=0; i< conditions.length; i++){
+ openTag(p, "condition_details");
+ printattrib(p,"condition_number",(i+1)+"");
+ printattrib(p,"condition_description",GenericXMLParser.encode(conditions[i]));
+ printattrib(p,"condition_postfix",GenericXMLParser.encode(conditionsPostfix[i]));
+ printattrib(p,"condition_comment",GenericXMLParser.encode(conditionsComment[i]));
+ p.println();
+ newline=true;
+ for(int j=0; j<maxcol; j++){
+ p.println("<condition_column column_number=\""+(j+1)+"\" column_value=\""+conditiontable[i][j]+"\" />");
+ }
+ p.println("</condition_details>");
+ }
+ p.println("</conditions>");
+ openTag(p, "actions");
+ for(int i=0; i< actions.length; i++){
+ openTag(p, "action_details");
+ printattrib(p,"action_number",(i+1)+"");
+ printattrib(p,"action_description",GenericXMLParser.encode(actions[i]));
+ printattrib(p,"action_postfix",GenericXMLParser.encode(actionsPostfix[i]));
+ printattrib(p,"action_comment",GenericXMLParser.encode(actionsComment[i]));
+ p.println();
+ newline=true;
+ for(int j=0; j<maxcol; j++){
+ if(actiontable[i][j].length()>0){
+ p.println("<action_column column_number=\""+(j+1)+"\" column_value=\""+actiontable[i][j]+"\" />");
+ }
+ }
+ p.println("</action_details>");
+ }
+ p.println("</actions>");
+ p.println("</decision_table>");
+ }
+
+
+ /**
+ * All Decision Tables are executable.
+ */
+ public boolean isExecutable() {
+ return true;
+ }
+
+ /**
+ * The string value of the decision table is simply its name.
+ */
+ public String stringValue() {
+ String number = fields.get("ipad_id");
+ if(number==null)number = "";
+ return number+" "+dtname.stringValue();
+ }
+
+ /**
+ * The string value of the decision table is simply its name.
+ */
+ public String toString() {
+ return stringValue();
+ }
+
+ /**
+ * Return the postFix value
+ */
+ public String postFix() {
+ return dtname.stringValue();
+ }
+
+ /**
+ * The type is Decision Table.
+ */
+ public int type() {
+ return iDecisiontable;
+ }
+
+ /**
+ * @return the actions
+ */
+ public String[] getActions() {
+ return actions;
+ }
+
+ /**
+ * @return the actiontable
+ */
+ public String[][] getActiontable() {
+ return actiontable;
+ }
+
+ /**
+ * @return the conditions
+ */
+ public String[] getConditions() {
+ return conditions;
+ }
+
+ /**
+ * @return the conditiontable
+ */
+ public String[][] getConditiontable() {
+ return conditiontable;
+ }
+
+ public String getDecisionTableId(){
+ return fields.get(RName.getRName("table_number"));
+ }
+
+ public void setDecisionTableId(String decisionTableId){
+ fields.put(RName.getRName("table_number"),decisionTableId);
+ }
+
+ public String getPurpose(){
+ return fields.get(RName.getRName("purpose"));
+ }
+
+ public void setPurpose(String purpose){
+ fields.put(RName.getRName("purpose"),purpose);
+ }
+
+ public String getComments(){
+ return fields.get(RName.getRName("comments"));
+ }
+
+ public void setComments(String comments){
+ fields.put(RName.getRName("comments"),comments);
+ }
+
+ public String getReference(){
+ return fields.get(RName.getRName("policy_reference"));
+ }
+
+ public void setReference(String reference){
+ fields.put(RName.getRName("policy_reference"),reference);
+ }
+
+ /**
+ * @return the dtname
+ */
+ public String getDtname() {
+ return dtname.stringValue();
+ }
+
+
+ /**
+ * @return the ractions
+ */
+ public IRObject[] getRactions() {
+ return ractions;
+}
+ /**
+ * @param ractions the ractions to set
+ */
+ public void setRactions(IRObject[] ractions) {
+ this.ractions = ractions;
+ }
+
+ /**
+ * @return the rconditions
+ */
+ public IRObject[] getRconditions() {
+ return rconditions;
+ }
+
+ /**
+ * @param rconditions the rconditions to set
+ */
+ public void setRconditions(IRObject[] rconditions) {
+ this.rconditions = rconditions;
+ }
+
+ /**
+ * @param actions the actions to set
+ */
+ public void setActions(String[] actions) {
+ this.actions = actions;
+ }
+
+ /**
+ * @param actiontable the actiontable to set
+ */
+ public void setActiontable(String[][] actiontable) {
+ this.actiontable = actiontable;
+ }
+
+ /**
+ * @param conditions the conditions to set
+ */
+ public void setConditions(String[] conditions) {
+ this.conditions = conditions;
+ }
+
+ /**
+ * @param conditiontable the conditiontable to set
+ */
+ public void setConditiontable(String[][] conditiontable) {
+ this.conditiontable = conditiontable;
+ }
+
+
+ /**
+ * @return the actionsComment
+ */
+ public final String[] getActionsComment() {
+ return actionsComment;
+ }
+
+
+ /**
+ * @param actionsComment the actionsComment to set
+ */
+ public final void setActionsComment(String[] actionsComment) {
+ this.actionsComment = actionsComment;
+ }
+
+
+ /**
+ * @return the actionsPostfix
+ */
+ public final String[] getActionsPostfix() {
+ return actionsPostfix;
+ }
+
+
+ /**
+ * @param actionsPostfix the actionsPostfix to set
+ */
+ public final void setActionsPostfix(String[] actionsPostfix) {
+ this.actionsPostfix = actionsPostfix;
+ }
+
+
+ /**
+ * @return the conditionsComment
+ */
+ public final String[] getConditionsComment() {
+ return conditionsComment;
+ }
+
+
+ /**
+ * @param conditionsComment the conditionsComment to set
+ */
+ public final void setConditionsComment(String[] conditionsComment) {
+ this.conditionsComment = conditionsComment;
+ }
+
+
+ /**
+ * @return the conditionsPostfix
+ */
+ public final String[] getConditionsPostfix() {
+ return conditionsPostfix;
+ }
+
+
+ /**
+ * @param conditionsPostfix the conditionsPostfix to set
+ */
+ public final void setConditionsPostfix(String[] conditionsPostfix) {
+ this.conditionsPostfix = conditionsPostfix;
+ }
+
+ /**
+ * A little helpper function that inserts a new column in a table
+ * of strings organized as String table [row][column]; Inserts blanks
+ * in all new entries, so this works for both conditions and actions.
+ * @param table
+ * @param col
+ */
+ private static void insert(String[][]table, int maxcol, final int col){
+ for(int i=0; i<maxcol; i++){
+ for(int j=15; j> col; j--){
+ table[i][j]=table[i][j-1];
+ }
+ table[i][col]=" ";
+ }
+ }
+ /**
+ * Insert a new column at the given column number (Zero based)
+ * @param col The zero based column number for the new column
+ * @throws RulesException
+ */
+ public void insert(int col) throws RulesException {
+ if(maxcol>=16){
+ throw new RulesException("TableTooBig","insert","Attempt to insert more than 16 columns in a Decision Table");
+ }
+ insert(conditiontable,maxcol,col);
+ insert(actiontable,maxcol,col);
+ }
+
+ /**
+ * Balances an unbalanced decision table. The additional columns have
+ * no actions added. There are two approaches to balancing tables. One
+ * is to have executed all columns whose conditions are met. The other is
+ * to execute only the first column whose conditions are met. This
+ * routine executes all columns whose conditions are met.
+ */
+ public void buildUnbalanced(UnbalancedType type) {
+
+ compile();
+
+ if(
+ conditiontable.length == 0 ||
+ conditiontable[0].length == 0 || // If we have no conditions, or
+ conditiontable[0][0].equals("*")){ // If *, we just execute all actions
+ decisiontree = ANode.newANode(this,0); // checked in the first column
+ return;
+ }
+
+ if(conditions.length<1){
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.CONDITION,
+ "You have to have at least one condition in a decision table",
+ 0,0)
+ );
+ }
+ if( conditiontable[0].length==0 || conditiontable[0][0].trim().equals("*"))return;
+ /**
+ *
+ */
+ CNode top = new CNode(this,1,0,this.rconditions[0]);
+ int defaultCol = -1; // The Index of the Default Column
+ int allCol = -1; // The Index of the "All" Column (executed on all conditions)
+ for(int col=0;col<maxcol;col++){ // Look at each column.
+ boolean nonemptycolumn = false;
+ for(int row=0; !nonemptycolumn && row<conditions.length; row++){
+ String v = conditiontable[row][col]; // Get the value from the condition table
+ nonemptycolumn = !v.equals("-") && !v.equals(" ");
+ }
+ if(nonemptycolumn){
+ try {
+ processCol(type,top,0,col); // Process all other columns.
+ } catch (Exception e) {
+ /** Any error detected is recorded in the errorlist. Nothing to do here **/
+ }
+ }
+ }
+ ANode defaults;
+ if(defaultCol >= 0){
+ defaults = ANode.newANode(this,defaultCol);
+ }else{
+ defaults = new ANode(this);
+ }
+ addDefaults(top,defaults); // Add defaults to all unmapped branches
+ if(allCol >= 0) addAll(top, ANode.newANode(this,allCol)); // Add to all branches the All actions
+ decisiontree = optimize(top); // Optimize the given tree.
+ }
+
+ /**
+ * Replace any untouched branches in the tree with a pointer
+ * to the defaults for this table. We only replace nulls.
+ * @param node
+ * @param defaults
+ * @return
+ */
+ private DTNode addDefaults(DTNode node, ANode defaults){
+ if(node == null ) return defaults;
+ if(node instanceof ANode)return node;
+ CNode cnode = (CNode)node;
+ cnode.iffalse = addDefaults(cnode.iffalse,defaults);
+ cnode.iftrue = addDefaults(cnode.iftrue, defaults);
+ return node;
+ }
+
+ private void addAll(DTNode node, ANode all){
+ if(node.getClass()==ANode.class){
+ ((ANode)node).addNode(all);
+ }else{
+ addAll( ((CNode)node).iffalse ,all);
+ addAll( ((CNode)node).iftrue ,all);
+ }
+ }
+
+ /**
+ * Replaces the given DTNode with the optimized DTNode.
+ * @param node
+ * @return
+ */
+ private DTNode optimize(DTNode node){
+ ANode opt = node.getCommonANode();
+ if(opt!=null){
+ return opt;
+ }
+ CNode cnode = (CNode) node;
+ cnode.iftrue = optimize(cnode.iftrue);
+ cnode.iffalse = optimize(cnode.iffalse);
+ if(cnode.iftrue.equalsNode(cnode.iffalse)){
+ return cnode.iftrue;
+ }
+ return cnode;
+ }
+
+ /**
+ * Build a path through the decision tables for a particular column.
+ * This routine throws an exception, but the calling routine just ignores it.
+ * That way we don't flood the error list with lots of duplicate errors.
+ * @param here
+ * @param row
+ * @param col
+ * @return
+ */
+ private DTNode processCol(UnbalancedType code, DTNode here, int row, int col) throws Exception{
+ if(row >= conditions.length){ // Ah, end of the column!
+ ANode thisCol = ANode.newANode(this, col); // Get a new ANode for the column
+
+ if(here!=null && code == UnbalancedType.FIRST){ // If we execute only the First, we are done!
+ thisCol = (ANode) here;
+ }
+ if(here!=null && code == UnbalancedType.ALL){ // If Some path lead here, fold the
+ thisCol.addNode((ANode)here); // old stuff in with this column.
+ }
+ return thisCol; // Return the mix!
+ }
+
+ String v = conditiontable[row][col]; // Get the value from the condition table
+ boolean dcare = v.equals("-") || v.equals(" "); // Standardize Don't cares.
+
+ if(!v.equalsIgnoreCase("y") && !v.equalsIgnoreCase("n") && !dcare){
+ errorlist.add(
+ new CompilerError (
+ ICompilerError.Type.CONTEXT,
+ "Bad value in Condition Table '"+v+"' at row "+(row+1)+" column "+(col+1),
+ v,0));
+ }
+ if((here==null || here.getRow()!= row ) && dcare){ // If we are a don't care, but not on a row
+ return processCol(code,here,row+1,col); // that matches us, we skip this row for now.
+ }
+
+ if(here==null){ // If this node is null, and I need
+ here = new CNode(this,col,row,rconditions[row]); // a condition node, create it!
+ }else if (here!=null && here.getRow()!= row ){ // If this is the wrong node, and I need
+ CNode t = new CNode(this,col,row,rconditions[row]); // a condition node, create a new one and insert it.
+ t.iffalse = here; // Put the node I have on the false tree
+ t.iftrue = here.cloneDTNode(); // and its clone on the true path.
+ here = t; // Continue with the new node.
+ }
+
+ if(v.equalsIgnoreCase("y") || dcare){ // If 'y' or a don't care,
+ DTNode next = ((CNode) here).iftrue; // Recurse on the True Branch.
+ ((CNode) here).iftrue = processCol(code,next,row+1,col);
+ }
+ if (v.equalsIgnoreCase("n")|| dcare){ // If 'n' or a don't care,
+ DTNode next = ((CNode) here).iffalse; // Recurse on the False branch. Note that
+ ((CNode) here).iffalse = processCol(code,next,row+1,col); // Don't care branches both ways.
+ }
+ return here; // Return the Condition node.
+ }
+
+ /**
+ * In the case of an unbalanced decision table, this method returns a balanced
+ * decision table using one of the two unbalanced rules: FIRST (which executes only
+ * the first column whose conditions are matched) and ALL (which executes all columns
+ * whose conditions are matched). If the decision table is balanced, this method returns
+ * an "optimized" decision table where all possible additional "don't cares" are inserted.
+ *
+ * @return
+ */
+ RDecisionTable balancedTable(IRSession session) throws RulesException{
+ if(balanceTable==null)balanceTable = new BalanceTable(this);
+ return balanceTable.balancedTable(session);
+ }
+
+ public BalanceTable getBalancedTable() throws RulesException {
+ return new BalanceTable(this);
+ }
+
+ public Iterator<RDecisionTable> DecisionTablesCalled(){
+ ArrayList<RDecisionTable> tables = new ArrayList<RDecisionTable>();
+ ArrayList<RArray> stack = new ArrayList<RArray>();
+ for(int i=0;i<ractions.length;i++){
+ addTables(ractions[i],stack,tables);
+ }
+ return tables.iterator();
+ }
+
+ private void addTables(IRObject action,List<RArray> stack, List<RDecisionTable> tables){
+ if(action==null)return;
+ if(action.type()==iArray){
+ RArray array = (RArray)action;
+ if(stack.contains(array))return; // We have already been here.
+ stack.add(array);
+ try { // As this is an array, arrayValue() will not ever throw an exception
+ @SuppressWarnings({"unchecked"})
+ Iterator objects = array.arrayValue().iterator();
+ while(objects.hasNext()){
+ addTables((IRObject) objects.next(),stack,tables);
+ }
+ } catch (RulesException e) { }
+ }
+ if(action.type()==iDecisiontable && !tables.contains(action)){
+ tables.add((RDecisionTable)action);
+ }
+ }
+ /**
+ * Returns the list of Decision Tables called by this Decision Table
+ * @return
+ */
+ ArrayList<RDecisionTable> decisionTablesCalled(){
+ ArrayList<RDecisionTable> calledTables = new ArrayList<RDecisionTable>();
+
+ addlist(calledTables, rinitialActions);
+ addlist(calledTables, rconditions);
+ addlist(calledTables, ractions);
+
+ return calledTables;
+ }
+ /**
+ * We do a recursive search down each IRObject in these lists, looking for
+ * references to Decision Tables. We only add references to Decision Tables
+ * to the list of called tables if the list of called tables doesn't yet have
+ * that reference.
+ *
+ * @param calledTables
+ * @param list
+ */
+ private void addlist(ArrayList<RDecisionTable> calledTables, IRObject [] list){
+ for(int i=0; i<list.length; i++){
+ ArrayList<RDecisionTable> tables = new ArrayList<RDecisionTable>();
+ ArrayList<RArray> stack = new ArrayList<RArray>();
+ getTables(stack, tables, list[i]);
+ for(RDecisionTable table : tables){
+ if(!calledTables.contains(table))calledTables.add(table);
+ }
+ }
+ }
+ /**
+ * Here we do a recursive search of all the constructs in an IROBject. This
+ * is because some IRObjects are arrays, so we search them as well.
+ * @param obj
+ * @return
+ */
+ private ArrayList<RDecisionTable> getTables(ArrayList<RArray>stack, ArrayList<RDecisionTable> tables, IRObject obj){
+
+ if(obj instanceof RDecisionTable) tables.add((RDecisionTable) obj);
+ if(obj instanceof RArray && !stack.contains(obj)){
+ stack.add((RArray) obj);
+ for(IRObject obj2 : (RArray) obj){
+ getTables(stack,tables,obj2);
+ }
+ }
+ return tables;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.session.DTState;
+
+/**
+ * ANodes execute a list of actions.
+ * @author ps24876
+ *
+ */
+public class ANode implements DTNode {
+ RDecisionTable dtable; // The Decision Table to which this ANode belongs
+ ArrayList<IRObject> action = new ArrayList<IRObject>(); // The action postfix
+ ArrayList<Integer> anumbers = new ArrayList<Integer>(); // The action numbers (for tracing purposes)
+ ArrayList<Integer> columns = new ArrayList<Integer>(); // Keep track of the columns that send us here, for tracing
+ String section; // What section we are being called from.
+
+
+ public DTNode cloneDTNode(){
+ ANode newANode = new ANode(dtable);
+ newANode.action.addAll(this.action);
+ newANode.anumbers.addAll(this.anumbers);
+ newANode.columns.addAll(this.columns);
+ newANode.section = this.section;
+ return newANode;
+ }
+
+ public int getRow(){ return -1; }
+
+ /**
+ * Create and return an new ANode instance that holds all of the
+ * actions whose supposed to execute if this column executes.
+ * @param col (the zero based column number)
+ */
+ public static ANode newANode(RDecisionTable dt, int col){
+ //int cnt = 0;
+ ArrayList<IRObject> list = new ArrayList<IRObject> ();
+ ArrayList<Integer> numbers = new ArrayList<Integer>();
+ for(int i=0; i< dt.actiontable.length; i++){
+ if(dt.actiontable[i][col].equalsIgnoreCase("x")){
+ if(dt.ractions!=null && dt.ractions.length>=i){
+ list.add(dt.ractions[i]);
+ numbers.add(Integer.valueOf(i));
+ }
+ }
+ }
+ return new ANode(dt,col+1, list, numbers);
+ }
+
+ public void addNode(ANode node){
+ columns.addAll(node.columns);
+ for(int i=0;i<node.anumbers.size(); i++){
+ Integer index = node.anumbers.get(i);
+ if(!anumbers.contains(index)){
+ int v = index.intValue();
+ int pos = 0;
+ while(pos< anumbers.size() && anumbers.get(pos).intValue()<v) pos++;
+ anumbers.add(pos,index);
+ action.add(pos,dtable.ractions[v]);
+ }
+ }
+ }
+
+ public int countColumns(){
+ return 1;
+ }
+
+ private ANode(RDecisionTable dt, int column, ArrayList<IRObject> objects, ArrayList<Integer> numbers){
+ dtable = dt;
+ columns.add(new Integer(column));
+ action = objects;
+ anumbers = numbers;
+ }
+
+ public ANode(RDecisionTable dt){
+ dtable = dt;
+ }
+
+ /** Give the list of columns that got us to this ANode. Unbalanced tables
+ * can give us multiple columns in a single ANode
+ * @param columns
+ * @return
+ */
+ public String prtColumns(ArrayList<Integer> columns){
+ String s="";
+ for(Integer column : columns){
+ s += column.toString()+" ";
+ }
+ return s;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ Iterator<Integer> inum = anumbers.iterator();
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("Column", "n='"+prtColumns(columns)+"'");
+ }
+ for(IRObject v : action){
+ int num = inum.next().intValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("action","n='"+(num+1)+"'");
+ state.traceTagBegin("formal",null);
+ state.traceTagEnd("formal",dtable.getActions()[num]);
+ int d = state.ddepth();
+
+ try {
+ String section = state.getCurrentTableSection();
+ int numhld = state.getNumberInSection();
+ state.setCurrentTableSection("Action",num);
+ state.evaluate(v);
+ state.setCurrentTableSection(section, numhld);
+ } catch (RulesException e) {
+ e.setSection("Action",num+1);
+ throw e;
+ }
+ if(d!=state.ddepth()){
+ throw new RulesException("data stack unbalanced","ANode Execute","Action "+(num+1)+" in table "+dtable.getDtname());
+ }
+ state.traceTagEnd("action",null);
+ }else{
+ try {
+ String section = state.getCurrentTableSection();
+ int numhld = state.getNumberInSection();
+ state.setCurrentTableSection("Action",num);
+ state.evaluate(v);
+ state.setCurrentTableSection(section, numhld);
+ } catch (RulesException e) {
+ e.setSection("Action",num+1);
+ throw e;
+ }
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("Column", null);
+ }
+ }
+
+ public Coordinate validate() {
+ return null;
+ }
+
+ public String toString(){
+ return "Action Node for columns "+(prtColumns(columns));
+ }
+ /**
+ * An Action Node is equal to another DTNode if 1) it has one and
+ * only one set of actions it executes regardless of the path taken, and
+ * 2) if the actions this node takes are exactly the as the node provided.
+ */
+ public boolean equalsNode(DTNode node) {
+ ANode other = node.getCommonANode(); // Get the common path
+ if(other==null)return false; // No common path? Not Equal then!
+ if(other.anumbers.size()!=anumbers.size()) return false;// Must be the same length.
+ Iterator<Integer> iother = other.anumbers.iterator(); // Iterate through the other node's actions.
+ Iterator<Integer> ithis = anumbers.iterator(); // Also Iterate through this nodee's actions.
+ while(iother.hasNext()){ // The other node still has actions? loop!
+ if(!iother.next().equals(ithis.next()))return false;// Make sure each action is the same action.
+ } // If a mismatch is found, Not Equal!!!
+ return true;
+ }
+
+ public ANode getCommonANode() {
+ return this;
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.IRSession;
+
+/**
+ * Builds a balanced decision table from the given decision table.
+ * @author paul snow
+ * Mar 5, 2007
+ *
+ */
+public class BalanceTable {
+
+ private int maxRow=0,maxCol=0;
+ private int maxARow=0;
+ private String ctable[][] = new String[32][10240];
+ private String atable[][] = new String[32][10240];
+
+ final RDecisionTable dt;
+ public BalanceTable(RDecisionTable dt) throws RulesException{
+ this.dt = dt;
+ }
+
+ RDecisionTable balancedTable (IRSession s) throws RulesException{
+ if(!dt.isCompiled())dt.build();
+ if(!dt.isCompiled()){
+ throw new RulesException("DecisionTableError","balancedTable()","Malformed Decision Table");
+ }
+ RDecisionTable btable = (RDecisionTable) dt.clone(s);
+ ctable = btable.conditiontable;
+ atable = btable.actiontable;
+ filltable(0,0,btable.decisiontree);
+ btable.setType(RDecisionTable.Type.BALANCED);
+ btable.build();
+ return btable;
+ }
+
+ public String getPrintableTable(){
+ if(dt.decisiontree==null)return "empty table";
+ filltable(0, 0, dt.decisiontree);
+ StringBuffer buff = new StringBuffer();
+ buff.append("Number of Columns: "+maxCol+"\r\n\r\n");
+ String spacer = " ";
+ if(maxCol < 25) spacer = " ";
+
+
+ for(int i=0;i<maxRow;i++){
+ String row = (i+1)+"";
+ row = " ".substring(row.length())+row+spacer;
+ buff.append(row);
+ for(int j=0;j<maxCol; j++){
+ if(ctable[i][j]==null)ctable[i][j]="-";
+ buff.append(ctable[i][j]);
+ buff.append(spacer);
+ }
+ buff.append("\r\n");
+ }
+ buff.append("\n");
+ for(int i=0;i<=maxARow;i++){
+ String row = (i+1)+"";
+ row = " ".substring(row.length())+row+spacer;
+ buff.append(row);
+ for(int j=0;j<maxCol; j++){
+ if(atable[i][j]==null)atable[i][j]=" ";
+ buff.append(atable[i][j]);
+ buff.append(spacer);
+ }
+ buff.append("\r\n");
+ }
+ buff.append("\r\n");
+ return buff.toString();
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ if(maxARow<index) maxARow = index;
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.session.DTState;
+/**
+ * The Condition Node evaluates conditions within a Decision
+ * table.
+ * @author Paul Snow
+ *
+ */
+public class CNode implements DTNode {
+
+ final int column; //Column that created this node
+ final int conditionNumber; //NOPMD
+ final IRObject condition;
+ final RDecisionTable dtable; // Pointer back to the Decision Table for debug purposes
+
+ DTNode iftrue = null;
+ DTNode iffalse = null;
+
+ /**
+ * Clone this CNode and all the CNodes referenced by this CNode
+ */
+ public CNode cloneDTNode (){
+ CNode newCNode = new CNode(dtable,column,conditionNumber,condition);
+ newCNode.iftrue = iftrue == null ? null : iftrue.cloneDTNode();
+ newCNode.iffalse = iffalse == null ? null : iffalse.cloneDTNode();
+ return newCNode;
+ }
+
+ public int getRow(){ return conditionNumber; }
+ /**
+ * Two CNodes are equal if their true paths and their
+ * false paths are the same.
+ * And those CommonANodes have to be equal.
+ */
+ public boolean equalsNode(DTNode node) {
+ if(node.getClass().equals(CNode.class)){
+ CNode cnode = (CNode)node;
+ return(cnode.iffalse.equalsNode(iffalse) &&
+ cnode.iftrue.equalsNode(iftrue));
+ }else{
+ ANode me = getCommonANode(); // Get this CNode's commonANode.
+ if(me==null)return false; // If none exists, it can't be equal!
+ ANode him = getCommonANode(); // Get the other DTNode's commonANode
+ if(him==null)return false; // If none exists, it can't be equal!
+ return me.equalsNode(him); // Return true if this node matches that node!
+ }
+ }
+
+ /**
+ * To have a CommonANode, every path through the CNode (i.e. both
+ * the true path and the false path) has to have the same commonANode.
+ * So both iftrue and iffalse have to have a commonANode, and those have
+ * to match.
+ */
+ public ANode getCommonANode() {
+ ANode trueSide = iftrue.getCommonANode(); // Does the true side have a CommonANode
+ if(trueSide==null)return null; // Nope? false!
+ ANode falseSide = iffalse.getCommonANode(); // Does the false side have a CommonANode?
+ if(falseSide==null)return null; // Nope? false!
+ if(trueSide.equalsNode(falseSide))return trueSide; // If they match, I just have to return one of them!
+ return null; // If they don't match, I have to return false!
+ }
+
+
+
+ CNode(RDecisionTable dt, int column, int conditionNumber, IRObject condition){
+ this.column = column;
+ this.conditionNumber = conditionNumber;
+ this.condition = condition;
+ this.dtable = dt;
+ }
+
+ public int countColumns(){
+ int t = iftrue.countColumns();
+ int f = iffalse.countColumns();
+ return t+f;
+ }
+
+ public void execute(DTState state) throws RulesException{
+ boolean result;
+ try {
+ result = state.evaluateCondition(condition);
+ } catch (RulesException e) {
+ e.setSection("Condition",conditionNumber+1);
+ throw e;
+ }
+ if(state.testState(DTState.TRACE)){
+ if(state.testState(DTState.VERBOSE)){
+ state.traceTagBegin("Condition", "n='"+conditionNumber+"'"+"r='"+(result?"Y'":"N'"));
+ state.traceInfo("Formal", null,dtable.getConditions()[conditionNumber]);
+ state.traceTagEnd("Condition", "");
+ }else{
+ state.traceInfo("Condition", "n='"+conditionNumber+"'"+"r='"+(result?"Y'":"N'"));
+ }
+ }
+ if(result){
+ iftrue.execute(state);
+ }else{
+ iffalse.execute(state);
+ }
+ }
+
+ public Coordinate validate() {
+ if(iftrue == null || iffalse == null){
+ return new Coordinate(conditionNumber,column);
+ }
+ Coordinate result = iffalse.validate();
+ if(result!=null){
+ return result;
+ }
+
+ return iftrue.validate();
+ }
+
+ public String toString(){
+ return "Condition Number "+(conditionNumber+1);
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.session.ICompilerError;
+
+
+public class CompilerError implements ICompilerError {
+ final private Type errorType; //NOPMD Supid PMD wants a set method for a final field...
+ final private String message; //NOPMD
+ final private String source; //NOPMD Only valid for type ACTION or CONDITION
+
+
+ /**
+ * Returns the source string which caused the error.
+ * @return source
+ */
+ public String getSource() {
+ return source;
+ }
+ final private int index; //NOPMD Only valid for type INITIALACTION,
+ // ACTION, andCONDITON
+ final private int row; //NOPMD Only valid for type TABLE
+ final private int col; //NOPMD Only valid for type TABLE
+
+ /**
+ * Constructor for INITALACTION, ACTION or CONDITION errors.
+ * @param type
+ * @param message
+ * @param source
+ * @param index provided as a zero based number; reported 1 based.
+ */
+ public CompilerError(
+ final Type type,
+ final String message,
+ final String source,
+ final int index){
+ errorType = type;
+ this.message = message;
+ this.source = source;
+ row = 0;
+ col = 0;
+ this.index = index + 1;
+ }
+ /**
+ * Constructor for TABLE errors.
+ * @param type
+ * @param message
+ * @param row provided as a zero based number; reported 1 based.
+ * @param col provided as a zero based number; reported 1 based.
+ */
+ public CompilerError(
+ final Type type,
+ final String message,
+ final int row,
+ final int col){
+ errorType = type;
+ this.message = message;
+ this.source = "";
+ this.row = row+1;
+ this.col = col+1;
+ this.index = 0;
+ }
+
+
+ public int getActionIndex() {
+ if(errorType == Type.ACTION){
+ return index;
+ }
+ return 0;
+ }
+
+ public int getCol() {
+ return col;
+ }
+
+ public int getConditionIndex() {
+ if(errorType == Type.CONDITION){
+ return index;
+ }
+ return 0;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Type getErrorType() {
+ return errorType;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public int getRow() {
+ return row;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+/**
+ * The DTLoader loads decision tables into the EntityFactory. Warning messages
+ * are routed through a RSession object.
+ *
+ * @author paul snow
+ * Feb 12, 2007
+ *
+ */
+@SuppressWarnings({"unchecked","unused"})
+public class DTLoader implements IGenericXMLParser {
+
+ private transient String _tag;
+ private transient String _body;
+ private transient Map _attribs;
+
+ private final EntityFactory ef; // As tables are loaded, they need to be registered
+ // with the entity factory.
+ private final IRSession session; // Even though we are not building anything within
+ // a session, we need a session to print warning messages.
+ private final DTState state; // For error reporting.
+
+ private int context_cnt = 0; // Count of contexts
+ private int ia_cnt = 0; // Count of initial actions.
+ private int c_cnt = 0; // Count of conditions
+ private int a_cnt = 0; // Count of actions
+ private int col_cnt = 1; // Count of columns (We assume at least one column)
+ private int col = 0; // Current column
+
+ private boolean processing_fields = false; // This boolean is only set within the <attribute_fields> tag.
+ // Any tag within this tag is interpreted as an attribute of
+ // the decision table. The Table_type tag is treated special.
+ /**
+ * The limit here is many times too large for actual decision tables.
+ * In fact, one should throw an error if a table has more than 16 columns,
+ * or more than 16 actions. Tables larger than that are too hard to
+ * understand to be useful.
+ **/
+ static final int LIMIT = 100;
+
+ // Temp Space for collecting data for the decision tables
+ String context_formal [] = new String[LIMIT];
+ String context_postfix [] = new String[LIMIT];
+ String ia_formal [] = new String[LIMIT];
+ String ia_postfix [] = new String[LIMIT];
+ String ia_comment [] = new String[LIMIT];
+ String c_formal[] = new String[LIMIT];
+ String c_comment[] = new String[LIMIT];
+ String c_postfix[] = new String[LIMIT];
+ String c_table[][] = new String[LIMIT][LIMIT];
+ String a_formal[] = new String[LIMIT];
+ String a_comment[] = new String[LIMIT];
+ String a_postfix[] = new String[LIMIT];
+ String a_table[][] = new String[LIMIT][LIMIT];
+
+ RDecisionTable dt = null;
+
+ /**
+ * In order to load decision tables into an EntityFactory, we create
+ * a loader. The tables are loaded into the entityfactory, and warning
+ * messages will be routed through the session.
+ *
+ * @param _session
+ * @param _ef
+ */
+ public DTLoader(IRSession _session, EntityFactory _ef){
+ session = _session;
+ state = _session.getState();
+ ef = _ef;
+ }
+
+
+ public void end_decision_tables()throws Exception {
+ /**
+ * Now we build all the decision tables.
+ */
+ Iterator<RName> it = ef.getDecisionTableRNameIterator();
+ while(it.hasNext()){
+ try {
+ RDecisionTable dt = ef.getDecisionTable(it.next());
+ dt.build();
+
+ } catch (RulesException e) {
+ state.traceInfo("error", null,"Error building Decision Table "+dt+"\r\n"+e);
+ }
+ }
+ }
+
+
+ /**
+ * Handle the Decision Table setup and initialization.
+ */
+
+ /**
+ * Decision Table Name
+ * @throws RulesException
+ */
+ public void end_table_name() throws RulesException {
+ dt = ef.newDecisionTable(_body, session);
+
+ c_cnt = 0;
+ a_cnt = 0;
+ col_cnt = 1;
+ col = 0;
+ ia_cnt = 0;
+ context_cnt = 0;
+
+ c_table = new String[LIMIT][LIMIT];
+ a_table = new String[LIMIT][LIMIT];
+
+ }
+
+ /**
+ * All done gathering the info for the table. Now we need to
+ * pack it away into the actual decision table.
+ *
+ */
+ public void end_decision_table(){
+ /** Contexts do not have comments **/
+ dt.contexts = new String[context_cnt];
+ dt.contextsPostfix = new String[context_cnt];
+
+ /** Initial Actions have Comments, descriptions, and postfix **/
+ dt.initialActionsComment = new String[ia_cnt];
+ dt.initialActions = new String[ia_cnt];
+ dt.initialActionsPostfix = new String[ia_cnt];
+
+ /** The count of columns for Conditions and actions have to match **/
+ dt.maxcol = col_cnt;
+
+ /** Conditions have a comment, description, Postfix, and a truth table **/
+ dt.conditionsComment = new String[c_cnt];
+ dt.conditions = new String[c_cnt];
+ dt.conditionsPostfix = new String[c_cnt];
+ dt.conditiontable = new String[c_cnt][col_cnt];
+
+ /** Actions have a comment, description, Postfix, and a action table **/
+ dt.actionsComment = new String[a_cnt];
+ dt.actions = new String[a_cnt];
+ dt.actionsPostfix = new String[a_cnt];
+ dt.actiontable = new String[a_cnt][col_cnt];
+
+ //Move over the information for the contexts
+ for(int i=0;i<context_cnt;i++){
+ dt.contexts[i] = context_formal[i];
+ dt.contextsPostfix[i] = context_postfix[i];
+ }
+
+ //Move over the information for actions
+ for(int i=0;i<ia_cnt;i++){
+ dt.initialActions[i] =ia_formal[i];
+ dt.initialActionsPostfix[i] =ia_postfix[i];
+ dt.initialActionsComment[i] =ia_comment[i];
+ }
+
+ //Move over the information for the conditions
+ for(int i=0;i<c_cnt;i++){
+ dt.conditions[i] = c_formal[i];
+ dt.conditionsComment[i] = c_comment[i]==null?"":c_comment[i];
+ dt.conditionsPostfix[i] = c_postfix[i]==null?"":c_postfix[i];
+ for(int j=0;j<col_cnt;j++){
+ String v = c_table[i][j];
+ dt.conditiontable[i][j]= v==null ? " " : v ;
+ }
+ }
+
+ //Move over the information for the actions
+ for(int i=0;i<a_cnt;i++){
+ dt.actions[i] = a_formal[i];
+ dt.actionsComment[i] = a_comment[i]==null?"":a_comment[i];
+ dt.actionsPostfix[i] = a_postfix[i]==null?"":a_postfix[i];
+ for(int j=0;j<col_cnt;j++){
+ String v = a_table[i][j];
+ dt.actiontable[i][j]= v==null ? " " : v;
+ }
+ }
+ }
+
+ /**
+ * Set the filename on the Decision Table
+ */
+ public void end_xls_file(){
+ dt.setFilename(_body);
+ }
+
+ /** Turn on field processing when the <attribute_field> tag is encountered
+ *
+ */
+ public void begin_attribute_fields() {
+ processing_fields = true;
+ }
+ /**
+ * Turn off attribute field processing outside the </attribute_filed> tag
+ */
+ public void end_attribute_fields() {
+ processing_fields = false;
+ }
+
+ /**
+ * Mostly we just collect attribute fields. But if the attribute field is the
+ * table_type tag, then it has to have a value of FIRST, ALL, or BALANCED.
+ */
+ public void process_field() throws RulesException {
+ dt.fields.put(RName.getRName(_tag),_body);
+ if(_tag.equalsIgnoreCase("type")){
+ if(_body.equalsIgnoreCase("first")){
+ dt.setType(RDecisionTable.Type.FIRST);
+ }else if (_body.equalsIgnoreCase("all")){
+ dt.setType(RDecisionTable.Type.ALL);
+ }else if (_body.equalsIgnoreCase("balanced")){
+ dt.setType(RDecisionTable.Type.BALANCED);
+ }else {
+ throw new RulesException("Invalid","Decision Table Load","Bad Decision Table type Encountered: '"+_body+"'");
+ }
+ }
+ }
+
+
+ /*
+ * Handle each condition in turn.
+ *
+ */
+
+ public void begin_condition_details(){
+ col=0; // Start at the begining of the columns again.
+ }
+
+ public void end_context_description(){
+ context_formal[context_cnt] = _body;
+ }
+
+ public void end_context_postfix (){
+ context_postfix[context_cnt] = _body;
+ }
+
+ public void end_context_details (){
+ context_cnt++;
+ }
+
+ public void end_initial_action_description(){
+ ia_formal[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_comment(){
+ ia_comment[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_postfix () {
+ ia_postfix[ia_cnt] = _body;
+ }
+
+ public void end_initial_action_details () {
+ ia_cnt++;
+ }
+
+
+ public void end_condition_description(){
+ c_formal[c_cnt]=_body;
+ }
+
+ public void end_condition_postfix(){
+ c_postfix[c_cnt]=_body;
+ }
+
+ public void end_condition_comment(){
+ c_comment[c_cnt]=_body;
+ }
+
+ public void begin_condition_column() throws RulesException {
+ if(col>=col_cnt){
+ col_cnt++;
+ }
+ int theCol = Integer.parseInt((String)_attribs.get("column_number"))-1;
+ c_table[c_cnt][theCol]= (String) _attribs.get("column_value");
+ col++;
+ }
+
+ public void end_condition_details(){
+ c_cnt++;
+ }
+
+ /*
+ * Load Actions
+ */
+
+
+ public void begin_action_details(){
+ for(int i=0;i<col_cnt;i++){
+ a_table[a_cnt][i]="";
+ }
+ }
+
+ public void end_action_description(){
+ a_formal[a_cnt]=_body;
+ }
+
+ public void end_action_postfix(){
+ a_postfix[a_cnt]=_body;
+ }
+
+ public void end_action_comment(){
+ a_comment[a_cnt]=_body;
+ }
+
+ public void begin_action_column() {
+ int a_col = Integer.parseInt((String)_attribs.get("column_number"))-1;
+ if(a_col>=col_cnt){
+ throw new RuntimeException("Decision Table Loader: Too many columns found in "+dt.toString());
+ }
+ String a_v = (String)_attribs.get("column_value");
+
+ a_table[a_cnt][a_col]= a_v;
+ }
+
+ public void end_action_details() {
+ a_cnt++;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+
+ _tag = tag;
+ _attribs = attribs;
+ _body = null;
+ String tagname = "begin_"+tag;
+ try {
+ Method m = methodCache.get(tagname);
+ if(m==null){
+ m = this.getClass().getMethod(tagname,(Class [])null);
+ methodCache.put(tagname,m);
+ }
+ m.invoke(this,(Object [])null);
+ } catch (NoSuchMethodException e){ // Ignore undefined tags
+ } catch (InvocationTargetException e){ // Ignore errors thrown by Decision Table parsing
+ throw new RuntimeException("An Invocation Target Exception was thrown processing the Begin XML tag "+tag+
+ "\nError states: "+e.getCause());
+ } catch (Exception e) {
+ state.traceInfo("error", null,e.getCause().getMessage());
+ throw new RuntimeException("Error Parsing Decision Tables: "+e.getMessage());
+ }
+ }
+
+ HashMap<String,Method> methodCache = new HashMap<String,Method>();
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+
+ _tag = tag;
+ _attribs = attribs;
+ body = body.trim().replaceAll("[\\n\\r]"," ");
+ _body = body;
+ String tagname = "end_"+tag;
+ try {
+ Class[] classArr = null;
+ Object[] objArr = null;
+ Method m = methodCache.get(tagname);
+ if(m==null){
+ m = this.getClass().getMethod(tagname,classArr);
+ methodCache.put(tagname, m);
+ }
+ m.invoke(this, objArr);
+ } catch (NoSuchMethodException e){ // Ignore undefined tags
+ if(processing_fields){ // Unless we are in the attribute files section.
+ process_field();
+ }
+ } catch (InvocationTargetException e){ // Ignore errors thrown by Decision Table parsing
+ state.traceInfo("error", null,"An Invocation Target Exception was thrown processing the End XML tag "+tag+
+ "\nError states "+e.getCause());
+ } catch (Exception e) {
+ state.traceInfo("error", null,e.getCause().getMessage());
+ throw new RuntimeException("Error Parsing Decision Tables: "+e.getMessage());
+ }
+
+ }
+
+ /**
+ * Skip DTD stuff and other parsing things the Rules Engine doesn't
+ * care about.
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+public interface DTNode {
+ static class Coordinate {
+ int row;
+ int col;
+ Coordinate(int row, int col){
+ this.row = row;
+ this.col = col;
+ }
+ public int getCol() {
+ return col;
+ }
+ public void setCol(int col) {
+ this.col = col;
+ }
+ public int getRow() {
+ return row;
+ }
+ public void setRow(int row) {
+ this.row = row;
+ }
+ }
+
+ public int getRow();
+
+ /**
+ * Returns a clone of this node, and all nodes below (if it
+ * has subnodes).
+ * @return
+ */
+ public DTNode cloneDTNode();
+
+ public int countColumns();
+
+ void execute(DTState state) throws RulesException;
+ Coordinate validate();
+
+ /**
+ * For two DTNodes are equal if every path through both nodes
+ * execute exactly the same set of Actions.
+ * @param node
+ * @return
+ */
+ boolean equalsNode(DTNode node);
+ /**
+ * Returns an ANode which represents the execution of every
+ * path through the given DTNode. If different paths through
+ * the DTNode execute different actions, this method returns
+ * a null. Note that ANodes always return themselves (i.e.
+ * there is only one execution path through an ANode).
+ */
+ ANode getCommonANode();
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+public class DecisionTableTypeTest {
+
+ int maxRow=0,maxCol=0;
+ String ctable [][] = new String[128][128];
+ String atable [][] = new String[128][128];
+ RDecisionTable dt;
+
+ public DecisionTableTypeTest(IRSession session, RuleSet rs) throws RulesException{
+
+ dt = new RDecisionTable(session, rs, "test");
+
+ String ctable[][] = {
+ { "y", "n", "n", "y", "d", "a" },
+ { "n", "n", "y", " ", " ", " " },
+ { "y", "y", "y", "n", " ", " " },
+ { "y", "y", " ", " ", " ", " " },
+ { " ", " ", "y", " ", " ", " " },
+ { "y", " ", " ", " ", " ", " " },
+
+ };
+ dt.conditiontable = ctable;
+
+ String atable[][] = {
+ { "x", " ", " ", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", " ", " ", "x", "x", " " },
+ { " ", " ", " ", " ", "x", " " },
+ { " ", " ", " ", "x", " ", "x" },
+ };
+ dt.maxcol = ctable[0].length;
+ dt.actiontable = atable;
+ dt.rconditions = new IRObject[ctable.length];
+ dt.ractions = new IRObject[atable.length];
+
+ String cps[] = new String[ctable.length];
+ for (int i = 0; i < cps.length; i++)
+ cps[i] = "{ 'Condition " + i + "' }";
+
+ String aps[] = new String[atable.length];
+ for (int i = 0; i < aps.length; i++)
+ aps[i] = "{ 'Action " + i + "' }";
+
+ dt.conditions = cps;
+ dt.conditionsPostfix = cps;
+ dt.actions = aps;
+ dt.actionsPostfix = aps;
+ dt.setType(RDecisionTable.Type.FIRST);
+ }
+
+ public static void main(String[] args) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = "DTRules.xml";
+ if(args.length>0){
+ file = args[0];
+ }
+
+ try {
+ RulesDirectory rd = new RulesDirectory(path,file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ IRSession session = rs.newSession();
+ DecisionTableTypeTest test;
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.FIRST);
+ test.dt.build();
+ test.printtable ();
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.ALL);
+ test.dt.build();
+ test.printtable ();
+
+
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
+
+ }
+
+ void printtable(){
+ maxRow = maxCol = 0;
+ filltable(0,0,dt.decisiontree);
+
+ System.out.print(" ");
+ for(int i=0;i<maxCol;i++){
+ System.out.print(i+((i<10)?" ":" "));
+ }
+ System.out.println();
+ for(int i=0;i<maxRow;i++){
+ System.out.print(dt.conditions[i]+" ");
+ for(int j=0; j<maxCol;j++){
+ System.out.print(ctable[i][j]==null?"- ":ctable[i][j]+" ");
+ }
+ System.out.println();
+ }
+ System.out.println("--------------------------------------");
+ for(int i=0;i<dt.actions.length;i++){
+ System.out.print(dt.actions[i]+" ");
+ for(int j=0;j<maxCol;j++){
+ System.out.print(atable[i][j]==null?" ":"X ");
+ }
+ System.out.println();
+ }
+ Iterator<ICompilerError> errors = dt.getErrorList().iterator();
+ while(errors.hasNext()){
+ ICompilerError error = errors.next();
+ System.out.println(error.getMessage()+
+ " on "+"Row " + error.getRow()+" Column "+error.getCol());
+
+
+ }
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.decisiontables;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.dtrules.decisiontables.DTNode.Coordinate;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+/**
+ * Decision Tables are the classes that hold the Rules for a set of Policy
+ * implemented using DTRules. There are three types: <br><br>
+ *
+ * BALANCED -- These decision tables expect all branches to be defined in the condition table <br>
+ * ALL -- Evaluates all the columns, then executes all the actions, in the order they
+ * are specified, for all columns whose conditions are met.<br>
+ * FIRST -- Effectively evaluates each column, and executes only the first Column whose
+ * conditions are met.<br>
+ * @author paul snow
+ * Mar 1, 2007
+ *
+ */
+public class RDecisionTable extends ARObject {
+
+ private final RName dtname; // The decision table's name.
+
+ private String filename = null; // Filename of Excel file where the table is defined,
+ // if this decision table is defined in Excel.
+
+ enum UnbalancedType { FIRST, ALL }; // Unbalanced Table Types.
+ public static enum Type {
+ BALANCED { void build(RDecisionTable dt) {dt.buildBalanced(); }},
+ FIRST { void build(RDecisionTable dt) {dt.buildUnbalanced(UnbalancedType.FIRST); }},
+ ALL { void build(RDecisionTable dt) {dt.buildUnbalanced(UnbalancedType.ALL); }};
+ abstract void build(RDecisionTable dt);
+ }
+
+ public Type type = Type.BALANCED; // By default, all decision tables are balanced.
+
+ public static final int MAXCOL = 16; // The Maximum number of columns in a decision table.
+
+ int maxcol = 1; // The number of columns in this decision table.
+
+ private final RuleSet ruleset; // A decision table must belong to a particular ruleset
+
+ public final Map<RName,String> fields = new HashMap<RName, String>(); // Holds meta information about this decision table.
+
+ private boolean compiled=false; // The decision table isn't compiled
+ // until fully constructed. And
+ // it won't be if compilation fails.
+ String [][] conditiontable;
+ String [] conditions; // The conditions in formal. The formal langauge is compiled to get the postfix
+ String [] conditionsPostfix; // The conditions in postfix. derived from the formal
+ String [] conditionsComment; // A comment per condition.
+ IRObject [] rconditions; // Each compiled condition
+
+ String [][] actiontable;
+ String [] actions;
+ String [] actionsComment;
+ String [] actionsPostfix;
+ IRObject [] ractions; // Each compiled action
+
+
+ String [] initialActions; // A list of actions to be executed each time the
+ // decision table is executed before the conditions
+ // are evaluated.
+ IRObject [] rinitialActions;
+ String [] initialActionsPostfix; // Compiled Initial Actions
+ String [] initialActionsComment; // Comment for Initial Actions
+ String [] contexts; // Contexts in which to execute this table.
+ String [] contextsPostfix; // The Postfix for each context statement.
+ String contextsrc; // For Tracing...
+ IRObject rcontext; // lists of entities. It is best if this is done within the table than
+ // by the calling table.
+
+ List<ICompilerError> errorlist = new ArrayList<ICompilerError>();
+ DTNode decisiontree=null;
+
+ private int numberOfRealColumns = 0; // Number of real columns (as unbalanced tables can have
+ // far more columns than they appear to have).
+
+ public int getNumberOfRealColumns() {
+ if(decisiontree==null)return 0;
+ return decisiontree.countColumns();
+ }
+
+ /**
+ * Check for errors in the decision table. Returns the column
+ * and row of a problem if one is found. If nothing is wrong,
+ * a null is returned.
+ * @return
+ */
+ public Coordinate validate(){
+ if(decisiontree==null){
+ if(actions !=null && actions.length==0)return null;
+ return new Coordinate(0,0);
+ }
+ return decisiontree.validate();
+ }
+
+ BalanceTable balanceTable = null; // Helper class to build a balanced or optimized version
+ // of this decision table.
+
+ public boolean isCompiled(){return compiled;}
+
+
+
+ public String getFilename() {
+ return filename;
+ }
+
+ public void setFilename(String filename) {
+ this.filename = filename;
+ }
+
+ @Override
+ public IRObject clone(IRSession s) throws RulesException {
+ RDecisionTable dt = new RDecisionTable(s,ruleset, dtname.stringValue());
+ dt.numberOfRealColumns = numberOfRealColumns;
+ dt.conditiontable = conditiontable.clone();
+ dt.conditions = conditions.clone();
+ dt.conditionsPostfix = conditionsPostfix.clone();
+ dt.conditionsComment = conditionsComment.clone();
+ dt.rconditions = rconditions.clone();
+ dt.actiontable = actiontable.clone();
+ dt.actions = actions.clone();
+ dt.actionsComment = actionsComment.clone();
+ dt.actionsPostfix = actionsPostfix.clone();
+ dt.ractions = ractions.clone();
+ dt.rinitialActions = rinitialActions.clone();
+ dt.initialActions = initialActions.clone();
+ dt.initialActionsComment = initialActionsComment.clone();
+ dt.initialActionsPostfix = initialActionsPostfix.clone();
+ dt.contexts = contexts.clone();
+ dt.contextsPostfix = contextsPostfix.clone();
+ dt.contextsrc = contextsrc;
+ dt.rcontext = rcontext.clone(s);
+ return dt;
+ }
+ /**
+ * Changes the type of the given decision table. The table is rebuilt.
+ * @param type
+ * @return Returns a list of errors which occurred when the type was changed.
+ */
+ public void setType(Type type) {
+ this.type = type;
+ }
+ /**
+ * This routine compiles the Context statements for the
+ * decision table into a single executable array.
+ * It must embed into this array a call to executeTable
+ * (which avoids this context building for the table).
+ */
+ private void buildContexts(){
+ // Nothing to do if no extra contexts are specfied.
+ if(contextsPostfix==null || contextsPostfix.length==0) return;
+
+ // This is the call to executeTable against this decisiontable
+ // that we are going to embed into our executable array.
+ contextsrc = "/"+getName().stringValue()+" executeTable ";
+
+ boolean keep = false;
+ for(int i=contextsPostfix.length-1;i>=0;i--){
+ if(contextsPostfix[i]!=null){
+ contextsrc = "{ "+contextsrc+" } "+contextsPostfix[i];
+ keep = true;
+ }
+ }
+ if(keep == true){
+ try {
+ rcontext = RString.compile(ruleset, contextsrc, true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError (
+ ICompilerError.Type.CONTEXT,
+ "Formal Compiler Error: "+e,
+ contextsrc,0));
+ }
+ }
+ }
+
+ /**
+ * Build this decision table according to its type.
+ *
+ */
+ public void build(){
+ errorlist.clear();
+ decisiontree = null;
+ buildContexts();
+ /**
+ * If a context or contexts are specified for this decision table,
+ * compile the context formal into postfix.
+ */
+ type.build(this);
+ }
+
+ /**
+ * Return the name of this decision table.
+ * @return
+ */
+ public RName getName(){
+ return dtname;
+ }
+
+ /**
+ * Renames this decision table.
+ * @param session
+ * @param newname
+ * @throws RulesException
+ */
+ public void rename(IRSession session, RName newname)throws RulesException{
+ ruleset.getEntityFactory(session).deleteDecisionTable(dtname);
+ ruleset.getEntityFactory(session).newDecisionTable(newname, session);
+ }
+
+ /**
+ * Create a Decision Table
+ * @param tables
+ * @param name
+ * @throws RulesException
+ */
+
+ public RDecisionTable(IRSession session, RuleSet _ruleset, String name) throws RulesException{
+ ruleset = _ruleset;
+ dtname = RName.getRName(name,true);
+ EntityFactory ef = ruleset.getEntityFactory(session);
+ RDecisionTable dttable =ef.findDecisionTable(RName.getRName(name));
+ if(dttable != null){
+ new CompilerError(CompilerError.Type.TABLE,"Duplicate Decision Tables Found",0,0);
+ }
+ }
+
+ /**
+ * Compile each condition and action. We mark the decision table as
+ * uncompiled if any error is detected. However, we still attempt to
+ * compile all conditions and all actions.
+ */
+ public List<ICompilerError> compile(){
+ compiled = true; // Assume the compile will work.
+ rconditions = new IRObject[conditionsPostfix.length];
+ ractions = new IRObject[actionsPostfix.length];
+ rinitialActions = new IRObject[initialActionsPostfix.length];
+
+ for(int i=0; i< initialActions.length; i++){
+ try {
+ rinitialActions[i] = RString.compile(ruleset, initialActionsPostfix[i],true);
+ } catch (Exception e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.INITIALACTION,
+ "Postfix Interpretation Error: "+e,
+ initialActionsPostfix[i],
+ i
+ )
+ );
+ compiled = false;
+ rinitialActions[i]=RNull.getRNull();
+ }
+ }
+
+ for(int i=0;i<rconditions.length;i++){
+ try {
+ rconditions[i]= RString.compile(ruleset, conditionsPostfix[i],true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.CONDITION,
+ "Postfix Interpretation Error: "+e,
+ conditionsPostfix[i],
+ i
+ )
+ );
+ compiled=false;
+ rconditions[i]=RNull.getRNull();
+ }
+ }
+ for(int i=0;i<ractions.length;i++){
+ try {
+ ractions[i]= RString.compile(ruleset, actionsPostfix[i],true);
+ } catch (RulesException e) {
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.ACTION,
+ "Postfix Interpretation Error: "+e,
+ actionsPostfix[i],
+ i
+ )
+ );
+ compiled=false;
+ ractions[i]=RNull.getRNull();
+ }
+ }
+ return errorlist;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ RDecisionTable last = state.getCurrentTable();
+ state.setCurrentTable(this);
+ try {
+ int estk = state.edepth();
+ int dstk = state.ddepth();
+ int cstk = state.cdepth();
+
+ state.pushframe();
+
+ if(rcontext==null){
+ executeTable(state);
+ }else{
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("context", "execute='"+contextsrc+"'");
+ try {
+ rcontext.execute(state);
+ } catch (RulesException e) {
+ e.setSection("Context", 0);
+ throw e;
+ }
+ state.traceTagEnd("context", null);
+ }else{
+ rcontext.execute(state);
+ }
+ }
+ state.popframe();
+
+ if(estk!= state.edepth() ||
+ dstk!= state.ddepth() ||
+ cstk!= state.cdepth() ){
+ throw new RulesException("Stacks Not balanced","DecisionTables",
+ "Error while executing table: "+getName().stringValue() +"\n" +
+ (estk!= state.edepth() ? "Entity Stack before "+estk+" after "+state.edepth()+"\n":"")+
+ (dstk!= state.ddepth() ? "Data Stack before "+dstk+" after "+state.ddepth()+"\n":"")+
+ (cstk!= state.cdepth() ? "Control Stack before "+cstk+" after "+state.cdepth()+"\n":""));
+ }
+ } catch (RulesException e) {
+ e.addDecisionTable(this.getName().stringValue(), this.getFilename());
+ state.setCurrentTable(last);
+ throw e;
+ }
+ state.setCurrentTable(last);
+ }
+
+ /**
+ * A decision table is executed by simply executing the
+ * binary tree underneath the table.
+ */
+ public void executeTable(DTState state) throws RulesException {
+ if(compiled==false){
+ throw new RulesException(
+ "UncompiledDecisionTable",
+ "RDecisionTable.execute",
+ "Attempt to execute an uncompiled decision table: "+dtname.stringValue()
+ );
+ }
+
+ boolean trace = state.testState(DTState.TRACE);
+ int edepth = state.edepth(); // Get the initial depth of the entity stack
+ // so we can toss any extra entities added...
+ if(trace){
+ state.traceTagBegin("decisiontable","tID='"+state.tracePt()+"' name='"+dtname+"'");
+ if(state.testState(DTState.VERBOSE)){
+ state.traceTagBegin("entity_stack", null);
+ for(int i=0;i<state.edepth();i++){
+ state.traceInfo("entity", "id='"+state.getes(i).getID()+"'", state.getes(i).stringValue());
+ }
+ state.traceTagEnd("entity_stack",null);
+ }
+ state.traceTagBegin("initialActions", null);
+ for( int i=0; rinitialActions!=null && i<rinitialActions.length; i++){
+ try{
+ rinitialActions[i].execute(state);
+ }catch(RulesException e){
+ e.setSection("Initial Actions", i+1);
+ throw e;
+ }
+ }
+ state.traceTagEnd("initialActions", null);
+ if(decisiontree!=null)decisiontree.execute(state);
+ state.traceTagEnd ("decisiontable",null);
+
+ }else{
+ for( int i=0; rinitialActions!=null && i<rinitialActions.length; i++){
+ state.setCurrentTableSection("InitialActions", i);
+ try{
+ rinitialActions[i].execute(state);
+ }catch(RulesException e){
+ e.setSection("Initial Actions", i+1);
+ throw e;
+ }
+ }
+ if(decisiontree!=null)decisiontree.execute(state);
+ }
+ while(state.edepth() > edepth)state.entitypop(); // Pop off extra entities.
+ }
+
+ /**
+ * Builds (if necessary) the internal representation of the decision table,
+ * then validates that structure.
+ * @return true if the structure builds and is valid; false otherwise.
+ */
+ public List<ICompilerError> getErrorList() {
+ if(decisiontree==null){
+ errorlist.clear();
+ build();
+ }
+ return errorlist;
+ }
+
+
+
+
+ /**
+ * Builds the decision tree, which is a binary tree of "DTNode"'s which can be executed
+ * directly. This defines the execution of a Decision Table.
+ * <br><br>
+ * The way we build this binary tree is we walk down each column, tracing
+ * that column's path through the decision tree. Once we are at the end of the column,
+ * we add on the actions. This algorithm assumes that a decision table describes
+ * a complete decision tree, i.e. there is no set of posible condition states which
+ * are not explicitly handled by the decision table.
+ *
+ */
+ void buildBalanced() {
+ compile();
+ if(conditiontable[0].length == 0 || // If we have no conditions, or
+ conditiontable[0][0].equals("*")){ // If *, we just execute all actions
+ decisiontree = ANode.newANode(this,0); // checked in the first column
+ return;
+ }
+
+ decisiontree = new CNode(this,0,0, rconditions[0]); // Allocate a root node.
+
+ for(int col=0;col<maxcol;col++){ // For each column, we are going to run down the
+ // column building that path through the tree.
+ boolean laststep = conditiontable[0][col].equalsIgnoreCase("y"); // Set the test for the root condition.
+ CNode last = (CNode) decisiontree; // The last node will start as the root.
+
+ for(int i=1; i<conditiontable.length; i++){ // Now go down the rest of the conditions.
+ String t = conditiontable[i][col]; // Get this conditions truth table entry.
+ boolean yes = t.equalsIgnoreCase("y");
+ boolean invalid = false;
+ if(yes || t.equalsIgnoreCase("n")){ // If this condition should be considered...
+ CNode here=null;
+ try {
+ if(laststep){
+ here = (CNode) last.iftrue;
+ }else{
+ here = (CNode) last.iffalse;
+ }
+ if(here == null){ // Missing a CNode? Create it!
+ here = new CNode(this,col,i,rconditions[i]);
+ if(laststep){
+ last.iftrue = here;
+ }else{
+ last.iffalse = here;
+ }
+ }
+ } catch (RuntimeException e) {
+ invalid = true;
+ }
+ if(invalid || here.conditionNumber != i ){
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.TABLE,
+ "Condition Table Compile Error ",
+ i,col
+ )
+ );
+ return;
+ }
+ last = here;
+ laststep = yes;
+ }
+ }
+ if(laststep){ // Once we have traced the column, add the actions.
+ last.iftrue=ANode.newANode(this,col);
+ }else{
+ last.iffalse=ANode.newANode(this,col);
+ }
+
+ }
+ DTNode.Coordinate rowCol = decisiontree.validate();
+ if(rowCol!=null){
+ errorlist.add(
+ new CompilerError(ICompilerError.Type.TABLE,"Condition Table isn't balanced.",rowCol.row,rowCol.col)
+ );
+ compiled = false;
+ }
+ }
+
+ boolean newline=true;
+
+ private void printattrib(PrintStream p, String tag, String body){
+ if(!newline){p.println();}
+ p.print("<"); p.print(tag); p.print(">");
+ p.print(body);
+ p.print("</"); p.print(tag); p.print(">");
+ newline = false;
+ }
+
+ private void openTag(PrintStream p,String tag){
+ if(!newline){p.println();}
+ p.print("<"); p.print(tag); p.print(">");
+ newline=false;
+ }
+
+ /**
+ * Write the XML representation of this decision table to the given outputstream.
+ * @param o Output stream where the XML for this decision table will be written.
+ */
+ public void writeXML(PrintStream p){
+ p.println("<decision_table>");
+ newline = true;
+ printattrib(p,"table_name",dtname.stringValue());
+ Iterator<RName> ifields = fields.keySet().iterator();
+ while(ifields.hasNext()){
+ RName name = ifields.next();
+ printattrib(p,name.stringValue(),fields.get(name));
+ }
+ openTag(p, "conditions");
+ for(int i=0; i< conditions.length; i++){
+ openTag(p, "condition_details");
+ printattrib(p,"condition_number",(i+1)+"");
+ printattrib(p,"condition_description",GenericXMLParser.encode(conditions[i]));
+ printattrib(p,"condition_postfix",GenericXMLParser.encode(conditionsPostfix[i]));
+ printattrib(p,"condition_comment",GenericXMLParser.encode(conditionsComment[i]));
+ p.println();
+ newline=true;
+ for(int j=0; j<maxcol; j++){
+ p.println("<condition_column column_number=\""+(j+1)+"\" column_value=\""+conditiontable[i][j]+"\" />");
+ }
+ p.println("</condition_details>");
+ }
+ p.println("</conditions>");
+ openTag(p, "actions");
+ for(int i=0; i< actions.length; i++){
+ openTag(p, "action_details");
+ printattrib(p,"action_number",(i+1)+"");
+ printattrib(p,"action_description",GenericXMLParser.encode(actions[i]));
+ printattrib(p,"action_postfix",GenericXMLParser.encode(actionsPostfix[i]));
+ printattrib(p,"action_comment",GenericXMLParser.encode(actionsComment[i]));
+ p.println();
+ newline=true;
+ for(int j=0; j<maxcol; j++){
+ if(actiontable[i][j].length()>0){
+ p.println("<action_column column_number=\""+(j+1)+"\" column_value=\""+actiontable[i][j]+"\" />");
+ }
+ }
+ p.println("</action_details>");
+ }
+ p.println("</actions>");
+ p.println("</decision_table>");
+ }
+
+
+ /**
+ * All Decision Tables are executable.
+ */
+ public boolean isExecutable() {
+ return true;
+ }
+
+ /**
+ * The string value of the decision table is simply its name.
+ */
+ public String stringValue() {
+ String number = fields.get("ipad_id");
+ if(number==null)number = "";
+ return number+" "+dtname.stringValue();
+ }
+
+ /**
+ * The string value of the decision table is simply its name.
+ */
+ public String toString() {
+ return stringValue();
+ }
+
+ /**
+ * Return the postFix value
+ */
+ public String postFix() {
+ return dtname.stringValue();
+ }
+
+ /**
+ * The type is Decision Table.
+ */
+ public int type() {
+ return iDecisiontable;
+ }
+
+ /**
+ * @return the actions
+ */
+ public String[] getActions() {
+ return actions;
+ }
+
+ /**
+ * @return the actiontable
+ */
+ public String[][] getActiontable() {
+ return actiontable;
+ }
+
+ /**
+ * @return the conditions
+ */
+ public String[] getConditions() {
+ return conditions;
+ }
+
+ /**
+ * @return the conditiontable
+ */
+ public String[][] getConditiontable() {
+ return conditiontable;
+ }
+
+ public String getDecisionTableId(){
+ return fields.get(RName.getRName("table_number"));
+ }
+
+ public void setDecisionTableId(String decisionTableId){
+ fields.put(RName.getRName("table_number"),decisionTableId);
+ }
+
+ public String getPurpose(){
+ return fields.get(RName.getRName("purpose"));
+ }
+
+ public void setPurpose(String purpose){
+ fields.put(RName.getRName("purpose"),purpose);
+ }
+
+ public String getComments(){
+ return fields.get(RName.getRName("comments"));
+ }
+
+ public void setComments(String comments){
+ fields.put(RName.getRName("comments"),comments);
+ }
+
+ public String getReference(){
+ return fields.get(RName.getRName("policy_reference"));
+ }
+
+ public void setReference(String reference){
+ fields.put(RName.getRName("policy_reference"),reference);
+ }
+
+ /**
+ * @return the dtname
+ */
+ public String getDtname() {
+ return dtname.stringValue();
+ }
+
+
+ /**
+ * @return the ractions
+ */
+ public IRObject[] getRactions() {
+ return ractions;
+}
+ /**
+ * @param ractions the ractions to set
+ */
+ public void setRactions(IRObject[] ractions) {
+ this.ractions = ractions;
+ }
+
+ /**
+ * @return the rconditions
+ */
+ public IRObject[] getRconditions() {
+ return rconditions;
+ }
+
+ /**
+ * @param rconditions the rconditions to set
+ */
+ public void setRconditions(IRObject[] rconditions) {
+ this.rconditions = rconditions;
+ }
+
+ /**
+ * @param actions the actions to set
+ */
+ public void setActions(String[] actions) {
+ this.actions = actions;
+ }
+
+ /**
+ * @param actiontable the actiontable to set
+ */
+ public void setActiontable(String[][] actiontable) {
+ this.actiontable = actiontable;
+ }
+
+ /**
+ * @param conditions the conditions to set
+ */
+ public void setConditions(String[] conditions) {
+ this.conditions = conditions;
+ }
+
+ /**
+ * @param conditiontable the conditiontable to set
+ */
+ public void setConditiontable(String[][] conditiontable) {
+ this.conditiontable = conditiontable;
+ }
+
+
+ /**
+ * @return the actionsComment
+ */
+ public final String[] getActionsComment() {
+ return actionsComment;
+ }
+
+
+ /**
+ * @param actionsComment the actionsComment to set
+ */
+ public final void setActionsComment(String[] actionsComment) {
+ this.actionsComment = actionsComment;
+ }
+
+
+ /**
+ * @return the actionsPostfix
+ */
+ public final String[] getActionsPostfix() {
+ return actionsPostfix;
+ }
+
+
+ /**
+ * @param actionsPostfix the actionsPostfix to set
+ */
+ public final void setActionsPostfix(String[] actionsPostfix) {
+ this.actionsPostfix = actionsPostfix;
+ }
+
+
+ /**
+ * @return the conditionsComment
+ */
+ public final String[] getConditionsComment() {
+ return conditionsComment;
+ }
+
+
+ /**
+ * @param conditionsComment the conditionsComment to set
+ */
+ public final void setConditionsComment(String[] conditionsComment) {
+ this.conditionsComment = conditionsComment;
+ }
+
+
+ /**
+ * @return the conditionsPostfix
+ */
+ public final String[] getConditionsPostfix() {
+ return conditionsPostfix;
+ }
+
+
+ /**
+ * @param conditionsPostfix the conditionsPostfix to set
+ */
+ public final void setConditionsPostfix(String[] conditionsPostfix) {
+ this.conditionsPostfix = conditionsPostfix;
+ }
+
+ /**
+ * A little helpper function that inserts a new column in a table
+ * of strings organized as String table [row][column]; Inserts blanks
+ * in all new entries, so this works for both conditions and actions.
+ * @param table
+ * @param col
+ */
+ private static void insert(String[][]table, int maxcol, final int col){
+ for(int i=0; i<maxcol; i++){
+ for(int j=15; j> col; j--){
+ table[i][j]=table[i][j-1];
+ }
+ table[i][col]=" ";
+ }
+ }
+ /**
+ * Insert a new column at the given column number (Zero based)
+ * @param col The zero based column number for the new column
+ * @throws RulesException
+ */
+ public void insert(int col) throws RulesException {
+ if(maxcol>=16){
+ throw new RulesException("TableTooBig","insert","Attempt to insert more than 16 columns in a Decision Table");
+ }
+ insert(conditiontable,maxcol,col);
+ insert(actiontable,maxcol,col);
+ }
+
+ /**
+ * Balances an unbalanced decision table. The additional columns have
+ * no actions added. There are two approaches to balancing tables. One
+ * is to have executed all columns whose conditions are met. The other is
+ * to execute only the first column whose conditions are met. This
+ * routine executes all columns whose conditions are met.
+ */
+ public void buildUnbalanced(UnbalancedType type) {
+
+ compile();
+
+ if(
+ conditiontable.length == 0 ||
+ conditiontable[0].length == 0 || // If we have no conditions, or
+ conditiontable[0][0].equals("*")){ // If *, we just execute all actions
+ decisiontree = ANode.newANode(this,0); // checked in the first column
+ return;
+ }
+
+ if(conditions.length<1){
+ errorlist.add(
+ new CompilerError(
+ ICompilerError.Type.CONDITION,
+ "You have to have at least one condition in a decision table",
+ 0,0)
+ );
+ }
+ if( conditiontable[0].length==0 || conditiontable[0][0].trim().equals("*"))return;
+ /**
+ *
+ */
+ CNode top = new CNode(this,1,0,this.rconditions[0]);
+ int defaultCol = -1; // The Index of the Default Column
+ int allCol = -1; // The Index of the "All" Column (executed on all conditions)
+ for(int col=0;col<maxcol;col++){ // Look at each column.
+ boolean nonemptycolumn = false;
+ for(int row=0; !nonemptycolumn && row<conditions.length; row++){
+ String v = conditiontable[row][col]; // Get the value from the condition table
+ nonemptycolumn = !v.equals("-") && !v.equals(" ");
+ }
+ if(nonemptycolumn){
+ try {
+ processCol(type,top,0,col); // Process all other columns.
+ } catch (Exception e) {
+ /** Any error detected is recorded in the errorlist. Nothing to do here **/
+ }
+ }
+ }
+ ANode defaults;
+ if(defaultCol >= 0){
+ defaults = ANode.newANode(this,defaultCol);
+ }else{
+ defaults = new ANode(this);
+ }
+ addDefaults(top,defaults); // Add defaults to all unmapped branches
+ if(allCol >= 0) addAll(top, ANode.newANode(this,allCol)); // Add to all branches the All actions
+ decisiontree = optimize(top); // Optimize the given tree.
+ }
+
+ /**
+ * Replace any untouched branches in the tree with a pointer
+ * to the defaults for this table. We only replace nulls.
+ * @param node
+ * @param defaults
+ * @return
+ */
+ private DTNode addDefaults(DTNode node, ANode defaults){
+ if(node == null ) return defaults;
+ if(node instanceof ANode)return node;
+ CNode cnode = (CNode)node;
+ cnode.iffalse = addDefaults(cnode.iffalse,defaults);
+ cnode.iftrue = addDefaults(cnode.iftrue, defaults);
+ return node;
+ }
+
+ private void addAll(DTNode node, ANode all){
+ if(node.getClass()==ANode.class){
+ ((ANode)node).addNode(all);
+ }else{
+ addAll( ((CNode)node).iffalse ,all);
+ addAll( ((CNode)node).iftrue ,all);
+ }
+ }
+
+ /**
+ * Replaces the given DTNode with the optimized DTNode.
+ * @param node
+ * @return
+ */
+ private DTNode optimize(DTNode node){
+ ANode opt = node.getCommonANode();
+ if(opt!=null){
+ return opt;
+ }
+ CNode cnode = (CNode) node;
+ cnode.iftrue = optimize(cnode.iftrue);
+ cnode.iffalse = optimize(cnode.iffalse);
+ if(cnode.iftrue.equalsNode(cnode.iffalse)){
+ return cnode.iftrue;
+ }
+ return cnode;
+ }
+
+ /**
+ * Build a path through the decision tables for a particular column.
+ * This routine throws an exception, but the calling routine just ignores it.
+ * That way we don't flood the error list with lots of duplicate errors.
+ * @param here
+ * @param row
+ * @param col
+ * @return
+ */
+ private DTNode processCol(UnbalancedType code, DTNode here, int row, int col) throws Exception{
+ if(row >= conditions.length){ // Ah, end of the column!
+ ANode thisCol = ANode.newANode(this, col); // Get a new ANode for the column
+
+ if(here!=null && code == UnbalancedType.FIRST){ // If we execute only the First, we are done!
+ thisCol = (ANode) here;
+ }
+ if(here!=null && code == UnbalancedType.ALL){ // If Some path lead here, fold the
+ thisCol.addNode((ANode)here); // old stuff in with this column.
+ }
+ return thisCol; // Return the mix!
+ }
+
+ String v = conditiontable[row][col]; // Get the value from the condition table
+ boolean dcare = v.equals("-") || v.equals(" "); // Standardize Don't cares.
+
+ if(!v.equalsIgnoreCase("y") && !v.equalsIgnoreCase("n") && !dcare){
+ errorlist.add(
+ new CompilerError (
+ ICompilerError.Type.CONTEXT,
+ "Bad value in Condition Table '"+v+"' at row "+(row+1)+" column "+(col+1),
+ v,0));
+ }
+ if((here==null || here.getRow()!= row ) && dcare){ // If we are a don't care, but not on a row
+ return processCol(code,here,row+1,col); // that matches us, we skip this row for now.
+ }
+
+ if(here==null){ // If this node is null, and I need
+ here = new CNode(this,col,row,rconditions[row]); // a condition node, create it!
+ }else if (here!=null && here.getRow()!= row ){ // If this is the wrong node, and I need
+ CNode t = new CNode(this,col,row,rconditions[row]); // a condition node, create a new one and insert it.
+ t.iffalse = here; // Put the node I have on the false tree
+ t.iftrue = here.cloneDTNode(); // and its clone on the true path.
+ here = t; // Continue with the new node.
+ }
+
+ if(v.equalsIgnoreCase("y") || dcare){ // If 'y' or a don't care,
+ DTNode next = ((CNode) here).iftrue; // Recurse on the True Branch.
+ ((CNode) here).iftrue = processCol(code,next,row+1,col);
+ }
+ if (v.equalsIgnoreCase("n")|| dcare){ // If 'n' or a don't care,
+ DTNode next = ((CNode) here).iffalse; // Recurse on the False branch. Note that
+ ((CNode) here).iffalse = processCol(code,next,row+1,col); // Don't care branches both ways.
+ }
+ return here; // Return the Condition node.
+ }
+
+ /**
+ * In the case of an unbalanced decision table, this method returns a balanced
+ * decision table using one of the two unbalanced rules: FIRST (which executes only
+ * the first column whose conditions are matched) and ALL (which executes all columns
+ * whose conditions are matched). If the decision table is balanced, this method returns
+ * an "optimized" decision table where all possible additional "don't cares" are inserted.
+ *
+ * @return
+ */
+ RDecisionTable balancedTable(IRSession session) throws RulesException{
+ if(balanceTable==null)balanceTable = new BalanceTable(this);
+ return balanceTable.balancedTable(session);
+ }
+
+ public BalanceTable getBalancedTable() throws RulesException {
+ return new BalanceTable(this);
+ }
+
+ public Iterator<RDecisionTable> DecisionTablesCalled(){
+ ArrayList<RDecisionTable> tables = new ArrayList<RDecisionTable>();
+ ArrayList<RArray> stack = new ArrayList<RArray>();
+ for(int i=0;i<ractions.length;i++){
+ addTables(ractions[i],stack,tables);
+ }
+ return tables.iterator();
+ }
+
+ private void addTables(IRObject action,List<RArray> stack, List<RDecisionTable> tables){
+ if(action==null)return;
+ if(action.type()==iArray){
+ RArray array = (RArray)action;
+ if(stack.contains(array))return; // We have already been here.
+ stack.add(array);
+ try { // As this is an array, arrayValue() will not ever throw an exception
+ @SuppressWarnings({"unchecked"})
+ Iterator objects = array.arrayValue().iterator();
+ while(objects.hasNext()){
+ addTables((IRObject) objects.next(),stack,tables);
+ }
+ } catch (RulesException e) { }
+ }
+ if(action.type()==iDecisiontable && !tables.contains(action)){
+ tables.add((RDecisionTable)action);
+ }
+ }
+ /**
+ * Returns the list of Decision Tables called by this Decision Table
+ * @return
+ */
+ ArrayList<RDecisionTable> decisionTablesCalled(){
+ ArrayList<RDecisionTable> calledTables = new ArrayList<RDecisionTable>();
+
+ addlist(calledTables, rinitialActions);
+ addlist(calledTables, rconditions);
+ addlist(calledTables, ractions);
+
+ return calledTables;
+ }
+ /**
+ * We do a recursive search down each IRObject in these lists, looking for
+ * references to Decision Tables. We only add references to Decision Tables
+ * to the list of called tables if the list of called tables doesn't yet have
+ * that reference.
+ *
+ * @param calledTables
+ * @param list
+ */
+ private void addlist(ArrayList<RDecisionTable> calledTables, IRObject [] list){
+ for(int i=0; i<list.length; i++){
+ ArrayList<RDecisionTable> tables = new ArrayList<RDecisionTable>();
+ ArrayList<RArray> stack = new ArrayList<RArray>();
+ getTables(stack, tables, list[i]);
+ for(RDecisionTable table : tables){
+ if(!calledTables.contains(table))calledTables.add(table);
+ }
+ }
+ }
+ /**
+ * Here we do a recursive search of all the constructs in an IROBject. This
+ * is because some IRObjects are arrays, so we search them as well.
+ * @param obj
+ * @return
+ */
+ private ArrayList<RDecisionTable> getTables(ArrayList<RArray>stack, ArrayList<RDecisionTable> tables, IRObject obj){
+
+ if(obj instanceof RDecisionTable) tables.add((RDecisionTable) obj);
+ if(obj instanceof RArray && !stack.contains(obj)){
+ stack.add((RArray) obj);
+ for(IRObject obj2 : (RArray) obj){
+ getTables(stack,tables,obj2);
+ }
+ }
+ return tables;
+ }
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/entity
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+REntityEntry.java
+file
+
+
+
+
+2008-08-25T03:49:14.484375Z
+ce2ac6f2606d80a5127648ccec34a704
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+IREntity.java
+file
+
+
+
+
+2008-08-24T03:13:19.671875Z
+7b308a8facf7aedd11e191c0ac3a654f
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+REntity.java
+file
+
+
+
+
+2008-08-24T03:14:20.515625Z
+a8e33c6c78bcaf8cebe5132b84da91a6
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+
+public interface IREntity extends IRObject{
+
+ /**
+ * This is the attribute name used by DTRules to map data from
+ * XML files into Rules Engine Entitites.
+ *
+ */
+ public final RName mappingKey = RName.getRName("mapping*key");
+ /**
+ * Returns if the Entity is read only or not
+ */
+ public boolean isReadOnly();
+ /**
+ * Returns an iterator for the attributes of an REntity. Each Key
+ * is itself an RName.
+ */
+ public abstract Iterator<RName> getAttributeIterator();
+
+ /**
+ * Remove the attribute of the given name from this Entity. Should only be
+ * used by Rules Maintanence code, not by runtime code.
+ * @param attrib attribute name to be removed.
+ */
+ public abstract void removeAttribute(RName attrib);
+
+ /**
+ * Add the attribute defined by this REntityEntry to this Entity. The assumption
+ * is that everything in the entry is set up correctly, and only the index to the
+ * value needs to be adjusted (and then only if the attribute isn't defined already).
+ *
+ * @param entry Entry providing the meta data for a new attribute.
+ */
+ public void addAttribute(REntityEntry entry);
+
+ /**
+ * This adds an attribute into the REntity. This is called by the Entity
+ * construction during the loading of the Entity Description Dictionary.
+ *
+ * @param defaultvalue
+ * @param writable
+ * @param type
+ * @return Error string if the add failed, or a null on success.
+ */
+ public String addAttribute( RName attributeName, String defaulttxt, IRObject defaultvalue,boolean writable, boolean readable, int type, String subtype);
+
+ /**
+ * Returns the name of this entity.
+ */
+ public abstract RName getName();
+
+ /**
+ * Here is where we set a value of an attribute within an Entity. We take the
+ * attribute name, look up that attribute and insure that the value type matches
+ * the type expected by the attribute entry. All types accept a RNull value.
+ *
+ * @param attrib
+ * @param value
+ * @throws RulesException
+ */
+ public abstract void put(RName attrib, IRObject value)
+ throws RulesException;
+
+ /**
+ * Returns an IRObject if this Entity defines an attribute of the given name.
+ * Otherwise it returns a null. This method should be avoided if a RName is
+ * easily available.
+ * @param attrib
+ * @return
+ */
+ public IRObject get(String attribName);
+
+ /**
+ * Returns an IRObject if this Entity defines an attribute of the given name.
+ * Otherwise it returns a null.
+ * @param attrib
+ * @return
+ */
+ public abstract IRObject get(RName attrib);
+
+ /**
+ * Returns the indexed value of a key/value pair. Sometimes we look at the
+ * EntityEntry before we grab the object. This avoids an extra hash lookup.
+ * @param i
+ * @return
+ */
+ public abstract IRObject get(int i);
+
+ /**
+ * This method returns the Entry for an attribute. An Entry allows the caller
+ * to see the type and other information about the attribute in addition to its
+ * value. If the attribute is undefined, a null is returned.
+ * @param attrib
+ * @return
+ */
+ public abstract REntityEntry getEntry(RName attrib);
+
+ /**
+ * Then sometimes they change their mind and want the value from an REntityEntry
+ * @param index
+ * @return
+ */
+ public abstract IRObject getValue(int index);
+
+ /**
+ * Returns the ID number for this instance of the entity. Entities with
+ * an ID of zero are reference entities.
+ * @return
+ */
+ public int getID();
+
+ /**
+ * Checks to see if the given attribute is defined by this entity.
+ * @param attName
+ * @return
+ */
+ public boolean containsAttribute(RName attName);
+
+ /**
+ * Sets a value into the values array. Should not be called directly,
+ * but only through DTState. We should refactor to enforce this.
+ */
+ public void set(int i, IRObject v);
+
+ /**
+ * Writes the XML representation of this Entity to the given printstream.
+ * All the attributes are written along with their default values. The self
+ * referential attribute is not written.
+ * @param p printstream to which the XML representation of this Entity is written.
+ */
+ public void writeXML(PrintStream p) throws RulesException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+
+/**
+ * Entities serve as the dictionaries of the Rules Engine. These
+ * Dictionaries are typed Hashtables. In other words, you can't
+ * just put any old object into an Entity. There has to be an
+ * attribute with the appropriate name and type in order to put
+ * a particular object with that name into an Entity.
+ * <br><br>
+ * This structure catches many data entry and program structure
+ * errors, as well as provides for a number of convienent automatic
+ * data conversions (if the compiler writer cares to provide such
+ * facilities).
+ *
+ * @author Paul Snow
+ *
+ */
+public class REntity extends ARObject implements IREntity {
+
+ public void removeAttribute(RName attrib) {
+ attributes.remove(attrib);
+ }
+
+ /** This attribute's name */
+ final RName name;
+ boolean readonly;
+
+ HashMap<RName,REntityEntry> attributes;
+ ArrayList<IRObject> values = new ArrayList<IRObject>();
+
+ /**
+ * A readonly entity cannot be modified at run time.
+ */
+ public boolean isReadOnly(){ return readonly; }
+
+ /**
+ * All reference Entities (i.e. those from which we clone instances) have
+ * an id of zero. Clones have an id that is non zero, and unique.
+ */
+ final int id;
+
+ /**
+ * Returns the ID number for this instance of the entity. Entities with
+ * an ID of zero are reference entities.
+ * @return
+ */
+ public int getID(){ return id;}
+
+ /**
+ * Returns an interator that provides all the names of all the attributes for this entity.
+ */
+ public Iterator<RName> getAttributeIterator(){
+ return attributes.keySet().iterator();
+ }
+ /**
+ * Checks to see if the given attribute is defined by this entity.
+ * @param attName
+ * @return
+ */
+ public boolean containsAttribute(RName attName){
+ return attributes.containsKey(attName);
+ }
+
+ /**
+ * Create a clone of an Entity.
+ *
+ */
+ public REntity( boolean _readonly, REntity entity, IRSession s) throws RulesException{
+ id = s.getUniqueID();
+ readonly = _readonly;
+ name = entity.name;
+ attributes = entity.attributes;
+ values = new ArrayList<IRObject>(entity.values);
+ for(int i=0;i<values.size();i++){
+ IRObject value = values.get(i);
+ if(value.type()!=iEntity){ // Entities are copied by reference.
+ values.set(i,value.clone(s));
+ }else{
+ values.set(i,value); // The clone references the same entity
+ }
+ }
+ put(name,this); //Patch up the self reference to point to self.
+ put(mappingKey,RNull.getRNull()); //
+ }
+
+ /**
+ * Regular Constructor. This should only be called when building the EntityFactory.
+ * However, we make it public so the EntityFactory can be defined in the Session
+ * package. We might like to reconsider that decision some time in the future.
+ *
+ * @param _name
+ */
+ public REntity( int id, boolean _readonly, RName _name) {
+ this.id = id;
+ readonly = _readonly;
+ name = _name;
+ attributes = new HashMap<RName,REntityEntry>();
+ this.addAttribute(_name, "", this, false, true, type(),null); // Add a reference to self!
+ this.addAttribute(mappingKey,"",RNull.getRNull(),false, true, iString,null);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#getName()
+ */
+ public RName getName(){
+ return name;
+ }
+
+ /**
+ * Adds this REntityEntry to this Entity. If an EntityEntry already exists, it will
+ * be replaced by this new one, no questions asked. The assumption is that one is
+ * editing the Attributes of the Entity, and the latest is the the right one to keep.
+ *
+ * @param entry The new Attribute meta data.
+ *
+ */
+ public void addAttribute(REntityEntry entry){
+ REntityEntry oldentry = getEntry(entry.attribute);
+ if(oldentry!=null){ // If the attribute already exists
+ entry.index = oldentry.index; // replace the old one (keep their index)
+ }else{
+ entry.index = values.size(); // If the attribute is new, make a new
+ values.add(RNull.getRNull()); // value index.
+ }
+ if(entry.defaultvalue==null){ // Update with the default value.
+ values.set(entry.index, RNull.getRNull());
+ }else{
+ values.set(entry.index, entry.defaultvalue);
+ }
+
+ attributes.put(entry.attribute,entry); // Put the new Entity Entry into this Entity.
+
+ }
+
+ /**
+ * This adds an attribute into the REntity. This is called by the Entity
+ * construction during the loading of the Entity Description Dictionary.
+ *
+ * @param defaultvalue Default value for this tag
+ * @param writable If true, the attribute is writable by decision tables
+ * @param readable If true, the attribute is readable by decision tables
+ * @param type
+ * @return null if successful, and an Error string if it failed.
+ */
+ public String addAttribute(RName attributeName,
+ String defaulttxt,
+ IRObject defaultvalue,
+ boolean writable,
+ boolean readable,
+ int type,
+ String subtype ){
+ REntityEntry entry = getEntry(attributeName);
+ if(entry==null){
+ int index = values.size();
+ if(defaultvalue==null){
+ values.add(RNull.getRNull());
+ }else{
+ values.add(defaultvalue);
+ }
+ REntityEntry newEntry = new REntityEntry(this,attributeName,defaulttxt, defaultvalue,writable,readable,type,subtype,index);
+
+ attributes.put(attributeName,newEntry);
+ return null;
+ }
+ if(entry.type!=type){
+ String type1 ="";
+ String type2 ="";
+ try{
+ type1="("+ RSession.typeInt2Str(entry.type)+") ";
+ }catch(RulesException e){}
+ try{
+ type2="("+ RSession.typeInt2Str(type)+")";
+ }catch(RulesException e){}
+
+ return "The entity '"+name.stringValue()+
+ "' has an attribute '"+attributeName.stringValue()+
+ "' with two types: "+type1+" and "+ type2+ "\n";
+ }
+ return null; // Entry already matches what we already have.
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#put(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject)
+ */
+ public void put(RName attrib, IRObject value) throws RulesException {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ if(entry==null)throw new RulesException("Undefined", "REntity.put()", "Undefined Attribute "+attrib+" in Entity: "+name);
+ if(value.type()!= iNull && entry.type != value.type()){
+ switch(entry.type) {
+ case iInteger : value = value.rIntegerValue(); break;
+ case iDouble : value = value.rDoubleValue(); break;
+ case iBoolean : value = value.rBooleanValue(); break;
+ //case iDecisiontable : value = value.rDecisiontableValue(); break;
+ case iEntity : value = value.rEntityValue(); break;
+ //case iMark : value = value.rMarkValue(); break;
+ case iName : value = value.rNameValue(); break;
+ //case iOperator : value = value.rOperatorValue(); break;
+ case iString : value = value.rStringValue(); break;
+ case iTime : value = value.rTimeValue(); break;
+ }
+ }
+ values.set(entry.index,value);
+ }
+
+ /**
+ * Looks up the name of an attribute,
+ * and returns the associated value.
+ * If no value is defined, returns a null.
+ */
+ public IRObject get(String attribName)
+ {
+ return get(RName.getRName(attribName));
+ }
+
+ /**
+ * Looks up the given name, and returns the associated value. If
+ * no value is defined, returns a null.
+ */
+ public IRObject get(RName attrib) {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ if(entry==null)return null;
+ return (IRObject) values.get(entry.index);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#get(int)
+ */
+ public IRObject get(int i) {
+ return (IRObject) values.get(i);
+ }
+
+ /**
+ * Sets a value in the values array. Should only be used
+ * RARELY outside of REntity.
+ * @param i
+ * @param v
+ */
+ public void set(int i, IRObject v){
+ values.set(i, v);
+ }
+ /**
+ * Returns an object that describes all the information we track about an
+ * Entity Attribute (the key to get its value). If the attribute is undefined,
+ * then a null is returned.
+ */
+ public REntityEntry getEntry(RName attrib) {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ return entry;
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#getValue(int)
+ */
+ public IRObject getValue(int index) {
+ return (IRObject) values.get(index);
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#postFix()
+ */
+ public String postFix() {
+ return "/"+name.stringValue()+" "+id+" createEntity ";
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#stringValue()
+ */
+ public String stringValue() {
+ return name.stringValue();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#type()
+ */
+ public int type() {
+ return iEntity;
+ }
+
+ public String toString(){
+ String v = name.stringValue()+" = {";
+ Iterator<RName> ia = getAttributeIterator();
+ while(ia.hasNext()){
+ RName n = ia.next();
+ IRObject o = get(n);
+ if(o==null){ // Protect ourselves from nulls.
+ o = RNull.getRNull();
+ }
+ v +=n.stringValue()+" = "+get(n).stringValue()+" ";
+ }
+ v +="}";
+ return v;
+
+ }
+
+ public IRObject clone(IRSession s) throws RulesException {
+ if(readonly)return this;
+ return new REntity(false,this,s);
+ }
+
+ /**
+ * Returns itself
+ */
+ public IREntity rEntityValue() throws RulesException {
+ return this;
+ }
+
+ public void writeXML(PrintStream p) throws RulesException {
+ Iterator<RName> attribs = getAttributeIterator();
+ p.println();
+ while(attribs.hasNext()){
+ RName attrib = attribs.next();
+ if(attrib.equals(name))continue; // Skip the self reference.
+ REntityEntry entry = attributes.get(attrib);
+ p.print("<entity attribute=\"");
+ p.print(attrib.stringValue());
+ p.print("\" type =\"");
+ p.print(RSession.typeInt2Str(entry.type));
+ p.print("\" cdd_default_value=\"");
+ p.print(entry.defaulttxt);
+ p.print("\" cdd_i_c=\"");
+ p.print(entry.writable?"c":"i");
+ p.print("\" parseStr=\"\">");
+ p.print(name.stringValue());
+ p.println("</entity>");
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.RSession;
+
+/**
+ *
+ * A Entry holds the attribute type and attribute value as held in an
+ * Entity. Past implementations of the Rules Engine used a separate
+ * Attribute and Value hashmaps. However, too many operations require
+ * both an inspection of the attribute as well as the value. So now
+ * I have one hashmap for the attribute, which provides an index into
+ * an ArrayList to get the value.
+ *
+ * @author Paul Snow
+ *
+ */
+public class REntityEntry {
+ public REntity entity; // The entity involved.
+ public RName attribute; // The name of this attribute.
+ public String defaulttxt; // Text for the default value.
+ public IRObject defaultvalue; // Every Entry has default value, which may be null.
+ public boolean writable; // We allow Entries to be locked.
+ public boolean readable; // We allow some Entries to be write only.
+ public int type; // The type value, i.e. integer, float, etc. as defined
+ // by IRObject
+ public String subtype; // The Subtype (for some kinds of attributes)...
+ public int index; // Index into the values array to get the current
+ // value for this attribute.
+ public String typeValue;
+
+ /**
+ * Allows the insertion of the REntityEntry into an Entity after the
+ * fact.
+ * @param newIndex The index into the values array where the value of this attribute can be found.
+ */
+ void updateIndex(int newIndex){
+ index = newIndex;
+ }
+
+ REntityEntry(
+ REntity _entity,
+ RName _attribute,
+ String _defaulttxt,
+ IRObject _defaultvalue,
+ boolean _writable,
+ boolean _readable,
+ int _type,
+ String _subtype,
+ int _index){
+ attribute = _attribute;
+ defaulttxt = _defaulttxt;
+ defaultvalue = _defaultvalue;
+ writable = _writable;
+ readable = _readable;
+ type = _type;
+ subtype = _subtype;
+ index = _index;
+ }
+
+ @Override
+ public String toString() {
+ String thetype="";
+ try{
+ thetype = "("+RSession.typeInt2Str(type)+")";
+ }catch(Exception e){}
+ return thetype +" default: "+defaulttxt;
+ }
+
+ /**
+ * @return the attribute
+ */
+ public RName getAttribute() {
+ return attribute;
+ }
+
+ /**
+ * @param attribute the attribute to set
+ */
+ public void setAttribute(RName attribute) {
+ this.attribute = attribute;
+ }
+
+ /**
+ * @return the defaulttxt
+ */
+ public String getDefaulttxt() {
+ return defaulttxt;
+ }
+
+ /**
+ * @param defaulttxt the defaulttxt to set
+ */
+ public void setDefaulttxt(String defaulttxt) {
+ this.defaulttxt = defaulttxt;
+ }
+
+ /**
+ * @return the defaultvalue
+ */
+ public IRObject getDefaultvalue() {
+ return defaultvalue;
+ }
+
+ /**
+ * @param defaultvalue the defaultvalue to set
+ */
+ public void setDefaultvalue(IRObject defaultvalue) {
+ this.defaultvalue = defaultvalue;
+ }
+
+ /**
+ * @return the type
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * @param type the type to set
+ */
+ public void setType(int type) throws RulesException {
+ this.type = type;
+ setTypeValue(RSession.typeInt2Str(type));
+ }
+
+ /**
+ * @return the writable
+ */
+ public boolean isWritable() {
+ return writable;
+ }
+
+ /**
+ * @param writable the writable to set
+ */
+ public void setWritable(boolean writable) {
+ this.writable = writable;
+ }
+
+ public String getTypeValue() throws RulesException {
+ if(typeValue==null)typeValue=RSession.typeInt2Str(type);
+ return typeValue;
+ }
+
+ public void setTypeValue(String typeValue) throws RulesException{
+ this.typeValue = typeValue;
+ setType(RSession.typeStr2Int(typeValue,entity.getName().stringValue(),attribute.stringValue()));
+ }
+
+ public String getAttributeStrValue() {
+ return attribute.stringValue();
+ }
+
+ public void setAttributeStrValue(String attributeStrValue) {
+ setAttribute(RName.getRName(attributeStrValue));
+ }
+
+ public final int getIndex() {
+ return index;
+ }
+
+ public final void setIndex(int index) {
+ this.index = index;
+ }
+
+ /**
+ * @return the subtype
+ */
+ public String getSubtype() {
+ return subtype;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import java.io.PrintStream;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+
+public interface IREntity extends IRObject{
+
+ /**
+ * This is the attribute name used by DTRules to map data from
+ * XML files into Rules Engine Entitites.
+ *
+ */
+ public final RName mappingKey = RName.getRName("mapping*key");
+ /**
+ * Returns if the Entity is read only or not
+ */
+ public boolean isReadOnly();
+ /**
+ * Returns an iterator for the attributes of an REntity. Each Key
+ * is itself an RName.
+ */
+ public abstract Iterator<RName> getAttributeIterator();
+
+ /**
+ * Remove the attribute of the given name from this Entity. Should only be
+ * used by Rules Maintanence code, not by runtime code.
+ * @param attrib attribute name to be removed.
+ */
+ public abstract void removeAttribute(RName attrib);
+
+ /**
+ * Add the attribute defined by this REntityEntry to this Entity. The assumption
+ * is that everything in the entry is set up correctly, and only the index to the
+ * value needs to be adjusted (and then only if the attribute isn't defined already).
+ *
+ * @param entry Entry providing the meta data for a new attribute.
+ */
+ public void addAttribute(REntityEntry entry);
+
+ /**
+ * This adds an attribute into the REntity. This is called by the Entity
+ * construction during the loading of the Entity Description Dictionary.
+ *
+ * @param defaultvalue
+ * @param writable
+ * @param type
+ * @return Error string if the add failed, or a null on success.
+ */
+ public String addAttribute( RName attributeName, String defaulttxt, IRObject defaultvalue,boolean writable, boolean readable, int type, String subtype);
+
+ /**
+ * Returns the name of this entity.
+ */
+ public abstract RName getName();
+
+ /**
+ * Here is where we set a value of an attribute within an Entity. We take the
+ * attribute name, look up that attribute and insure that the value type matches
+ * the type expected by the attribute entry. All types accept a RNull value.
+ *
+ * @param attrib
+ * @param value
+ * @throws RulesException
+ */
+ public abstract void put(RName attrib, IRObject value)
+ throws RulesException;
+
+ /**
+ * Returns an IRObject if this Entity defines an attribute of the given name.
+ * Otherwise it returns a null. This method should be avoided if a RName is
+ * easily available.
+ * @param attrib
+ * @return
+ */
+ public IRObject get(String attribName);
+
+ /**
+ * Returns an IRObject if this Entity defines an attribute of the given name.
+ * Otherwise it returns a null.
+ * @param attrib
+ * @return
+ */
+ public abstract IRObject get(RName attrib);
+
+ /**
+ * Returns the indexed value of a key/value pair. Sometimes we look at the
+ * EntityEntry before we grab the object. This avoids an extra hash lookup.
+ * @param i
+ * @return
+ */
+ public abstract IRObject get(int i);
+
+ /**
+ * This method returns the Entry for an attribute. An Entry allows the caller
+ * to see the type and other information about the attribute in addition to its
+ * value. If the attribute is undefined, a null is returned.
+ * @param attrib
+ * @return
+ */
+ public abstract REntityEntry getEntry(RName attrib);
+
+ /**
+ * Then sometimes they change their mind and want the value from an REntityEntry
+ * @param index
+ * @return
+ */
+ public abstract IRObject getValue(int index);
+
+ /**
+ * Returns the ID number for this instance of the entity. Entities with
+ * an ID of zero are reference entities.
+ * @return
+ */
+ public int getID();
+
+ /**
+ * Checks to see if the given attribute is defined by this entity.
+ * @param attName
+ * @return
+ */
+ public boolean containsAttribute(RName attName);
+
+ /**
+ * Sets a value into the values array. Should not be called directly,
+ * but only through DTState. We should refactor to enforce this.
+ */
+ public void set(int i, IRObject v);
+
+ /**
+ * Writes the XML representation of this Entity to the given printstream.
+ * All the attributes are written along with their default values. The self
+ * referential attribute is not written.
+ * @param p printstream to which the XML representation of this Entity is written.
+ */
+ public void writeXML(PrintStream p) throws RulesException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+
+/**
+ * Entities serve as the dictionaries of the Rules Engine. These
+ * Dictionaries are typed Hashtables. In other words, you can't
+ * just put any old object into an Entity. There has to be an
+ * attribute with the appropriate name and type in order to put
+ * a particular object with that name into an Entity.
+ * <br><br>
+ * This structure catches many data entry and program structure
+ * errors, as well as provides for a number of convienent automatic
+ * data conversions (if the compiler writer cares to provide such
+ * facilities).
+ *
+ * @author Paul Snow
+ *
+ */
+public class REntity extends ARObject implements IREntity {
+
+ public void removeAttribute(RName attrib) {
+ attributes.remove(attrib);
+ }
+
+ /** This attribute's name */
+ final RName name;
+ boolean readonly;
+
+ HashMap<RName,REntityEntry> attributes;
+ ArrayList<IRObject> values = new ArrayList<IRObject>();
+
+ /**
+ * A readonly entity cannot be modified at run time.
+ */
+ public boolean isReadOnly(){ return readonly; }
+
+ /**
+ * All reference Entities (i.e. those from which we clone instances) have
+ * an id of zero. Clones have an id that is non zero, and unique.
+ */
+ final int id;
+
+ /**
+ * Returns the ID number for this instance of the entity. Entities with
+ * an ID of zero are reference entities.
+ * @return
+ */
+ public int getID(){ return id;}
+
+ /**
+ * Returns an interator that provides all the names of all the attributes for this entity.
+ */
+ public Iterator<RName> getAttributeIterator(){
+ return attributes.keySet().iterator();
+ }
+ /**
+ * Checks to see if the given attribute is defined by this entity.
+ * @param attName
+ * @return
+ */
+ public boolean containsAttribute(RName attName){
+ return attributes.containsKey(attName);
+ }
+
+ /**
+ * Create a clone of an Entity.
+ *
+ */
+ public REntity( boolean _readonly, REntity entity, IRSession s) throws RulesException{
+ id = s.getUniqueID();
+ readonly = _readonly;
+ name = entity.name;
+ attributes = entity.attributes;
+ values = new ArrayList<IRObject>(entity.values);
+ for(int i=0;i<values.size();i++){
+ IRObject value = values.get(i);
+ if(value.type()!=iEntity){ // Entities are copied by reference.
+ values.set(i,value.clone(s));
+ }else{
+ values.set(i,value); // The clone references the same entity
+ }
+ }
+ put(name,this); //Patch up the self reference to point to self.
+ put(mappingKey,RNull.getRNull()); //
+ }
+
+ /**
+ * Regular Constructor. This should only be called when building the EntityFactory.
+ * However, we make it public so the EntityFactory can be defined in the Session
+ * package. We might like to reconsider that decision some time in the future.
+ *
+ * @param _name
+ */
+ public REntity( int id, boolean _readonly, RName _name) {
+ this.id = id;
+ readonly = _readonly;
+ name = _name;
+ attributes = new HashMap<RName,REntityEntry>();
+ this.addAttribute(_name, "", this, false, true, type(),null); // Add a reference to self!
+ this.addAttribute(mappingKey,"",RNull.getRNull(),false, true, iString,null);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#getName()
+ */
+ public RName getName(){
+ return name;
+ }
+
+ /**
+ * Adds this REntityEntry to this Entity. If an EntityEntry already exists, it will
+ * be replaced by this new one, no questions asked. The assumption is that one is
+ * editing the Attributes of the Entity, and the latest is the the right one to keep.
+ *
+ * @param entry The new Attribute meta data.
+ *
+ */
+ public void addAttribute(REntityEntry entry){
+ REntityEntry oldentry = getEntry(entry.attribute);
+ if(oldentry!=null){ // If the attribute already exists
+ entry.index = oldentry.index; // replace the old one (keep their index)
+ }else{
+ entry.index = values.size(); // If the attribute is new, make a new
+ values.add(RNull.getRNull()); // value index.
+ }
+ if(entry.defaultvalue==null){ // Update with the default value.
+ values.set(entry.index, RNull.getRNull());
+ }else{
+ values.set(entry.index, entry.defaultvalue);
+ }
+
+ attributes.put(entry.attribute,entry); // Put the new Entity Entry into this Entity.
+
+ }
+
+ /**
+ * This adds an attribute into the REntity. This is called by the Entity
+ * construction during the loading of the Entity Description Dictionary.
+ *
+ * @param defaultvalue Default value for this tag
+ * @param writable If true, the attribute is writable by decision tables
+ * @param readable If true, the attribute is readable by decision tables
+ * @param type
+ * @return null if successful, and an Error string if it failed.
+ */
+ public String addAttribute(RName attributeName,
+ String defaulttxt,
+ IRObject defaultvalue,
+ boolean writable,
+ boolean readable,
+ int type,
+ String subtype ){
+ REntityEntry entry = getEntry(attributeName);
+ if(entry==null){
+ int index = values.size();
+ if(defaultvalue==null){
+ values.add(RNull.getRNull());
+ }else{
+ values.add(defaultvalue);
+ }
+ REntityEntry newEntry = new REntityEntry(this,attributeName,defaulttxt, defaultvalue,writable,readable,type,subtype,index);
+
+ attributes.put(attributeName,newEntry);
+ return null;
+ }
+ if(entry.type!=type){
+ String type1 ="";
+ String type2 ="";
+ try{
+ type1="("+ RSession.typeInt2Str(entry.type)+") ";
+ }catch(RulesException e){}
+ try{
+ type2="("+ RSession.typeInt2Str(type)+")";
+ }catch(RulesException e){}
+
+ return "The entity '"+name.stringValue()+
+ "' has an attribute '"+attributeName.stringValue()+
+ "' with two types: "+type1+" and "+ type2+ "\n";
+ }
+ return null; // Entry already matches what we already have.
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#put(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject)
+ */
+ public void put(RName attrib, IRObject value) throws RulesException {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ if(entry==null)throw new RulesException("Undefined", "REntity.put()", "Undefined Attribute "+attrib+" in Entity: "+name);
+ if(value.type()!= iNull && entry.type != value.type()){
+ switch(entry.type) {
+ case iInteger : value = value.rIntegerValue(); break;
+ case iDouble : value = value.rDoubleValue(); break;
+ case iBoolean : value = value.rBooleanValue(); break;
+ //case iDecisiontable : value = value.rDecisiontableValue(); break;
+ case iEntity : value = value.rEntityValue(); break;
+ //case iMark : value = value.rMarkValue(); break;
+ case iName : value = value.rNameValue(); break;
+ //case iOperator : value = value.rOperatorValue(); break;
+ case iString : value = value.rStringValue(); break;
+ case iTime : value = value.rTimeValue(); break;
+ }
+ }
+ values.set(entry.index,value);
+ }
+
+ /**
+ * Looks up the name of an attribute,
+ * and returns the associated value.
+ * If no value is defined, returns a null.
+ */
+ public IRObject get(String attribName)
+ {
+ return get(RName.getRName(attribName));
+ }
+
+ /**
+ * Looks up the given name, and returns the associated value. If
+ * no value is defined, returns a null.
+ */
+ public IRObject get(RName attrib) {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ if(entry==null)return null;
+ return (IRObject) values.get(entry.index);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#get(int)
+ */
+ public IRObject get(int i) {
+ return (IRObject) values.get(i);
+ }
+
+ /**
+ * Sets a value in the values array. Should only be used
+ * RARELY outside of REntity.
+ * @param i
+ * @param v
+ */
+ public void set(int i, IRObject v){
+ values.set(i, v);
+ }
+ /**
+ * Returns an object that describes all the information we track about an
+ * Entity Attribute (the key to get its value). If the attribute is undefined,
+ * then a null is returned.
+ */
+ public REntityEntry getEntry(RName attrib) {
+ REntityEntry entry = (REntityEntry)attributes.get(attrib);
+ return entry;
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#getValue(int)
+ */
+ public IRObject getValue(int index) {
+ return (IRObject) values.get(index);
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#postFix()
+ */
+ public String postFix() {
+ return "/"+name.stringValue()+" "+id+" createEntity ";
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#stringValue()
+ */
+ public String stringValue() {
+ return name.stringValue();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.entity.IREntity#type()
+ */
+ public int type() {
+ return iEntity;
+ }
+
+ public String toString(){
+ String v = name.stringValue()+" = {";
+ Iterator<RName> ia = getAttributeIterator();
+ while(ia.hasNext()){
+ RName n = ia.next();
+ IRObject o = get(n);
+ if(o==null){ // Protect ourselves from nulls.
+ o = RNull.getRNull();
+ }
+ v +=n.stringValue()+" = "+get(n).stringValue()+" ";
+ }
+ v +="}";
+ return v;
+
+ }
+
+ public IRObject clone(IRSession s) throws RulesException {
+ if(readonly)return this;
+ return new REntity(false,this,s);
+ }
+
+ /**
+ * Returns itself
+ */
+ public IREntity rEntityValue() throws RulesException {
+ return this;
+ }
+
+ public void writeXML(PrintStream p) throws RulesException {
+ Iterator<RName> attribs = getAttributeIterator();
+ p.println();
+ while(attribs.hasNext()){
+ RName attrib = attribs.next();
+ if(attrib.equals(name))continue; // Skip the self reference.
+ REntityEntry entry = attributes.get(attrib);
+ p.print("<entity attribute=\"");
+ p.print(attrib.stringValue());
+ p.print("\" type =\"");
+ p.print(RSession.typeInt2Str(entry.type));
+ p.print("\" cdd_default_value=\"");
+ p.print(entry.defaulttxt);
+ p.print("\" cdd_i_c=\"");
+ p.print(entry.writable?"c":"i");
+ p.print("\" parseStr=\"\">");
+ p.print(name.stringValue());
+ p.println("</entity>");
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.entity;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.RSession;
+
+/**
+ *
+ * A Entry holds the attribute type and attribute value as held in an
+ * Entity. Past implementations of the Rules Engine used a separate
+ * Attribute and Value hashmaps. However, too many operations require
+ * both an inspection of the attribute as well as the value. So now
+ * I have one hashmap for the attribute, which provides an index into
+ * an ArrayList to get the value.
+ *
+ * @author Paul Snow
+ *
+ */
+public class REntityEntry {
+ public REntity entity; // The entity involved.
+ public RName attribute; // The name of this attribute.
+ public String defaulttxt; // Text for the default value.
+ public IRObject defaultvalue; // Every Entry has default value, which may be null.
+ public boolean writable; // We allow Entries to be locked.
+ public boolean readable; // We allow some Entries to be write only.
+ public int type; // The type value, i.e. integer, float, etc. as defined
+ // by IRObject
+ public String subtype; // The Subtype (for some kinds of attributes)...
+ public int index; // Index into the values array to get the current
+ // value for this attribute.
+ public String typeValue;
+
+ /**
+ * Allows the insertion of the REntityEntry into an Entity after the
+ * fact.
+ * @param newIndex The index into the values array where the value of this attribute can be found.
+ */
+ void updateIndex(int newIndex){
+ index = newIndex;
+ }
+
+ REntityEntry(
+ REntity _entity,
+ RName _attribute,
+ String _defaulttxt,
+ IRObject _defaultvalue,
+ boolean _writable,
+ boolean _readable,
+ int _type,
+ String _subtype,
+ int _index){
+ attribute = _attribute;
+ defaulttxt = _defaulttxt;
+ defaultvalue = _defaultvalue;
+ writable = _writable;
+ readable = _readable;
+ type = _type;
+ subtype = _subtype;
+ index = _index;
+ }
+
+ @Override
+ public String toString() {
+ String thetype="";
+ try{
+ thetype = "("+RSession.typeInt2Str(type)+")";
+ }catch(Exception e){}
+ return thetype +" default: "+defaulttxt;
+ }
+
+ /**
+ * @return the attribute
+ */
+ public RName getAttribute() {
+ return attribute;
+ }
+
+ /**
+ * @param attribute the attribute to set
+ */
+ public void setAttribute(RName attribute) {
+ this.attribute = attribute;
+ }
+
+ /**
+ * @return the defaulttxt
+ */
+ public String getDefaulttxt() {
+ return defaulttxt;
+ }
+
+ /**
+ * @param defaulttxt the defaulttxt to set
+ */
+ public void setDefaulttxt(String defaulttxt) {
+ this.defaulttxt = defaulttxt;
+ }
+
+ /**
+ * @return the defaultvalue
+ */
+ public IRObject getDefaultvalue() {
+ return defaultvalue;
+ }
+
+ /**
+ * @param defaultvalue the defaultvalue to set
+ */
+ public void setDefaultvalue(IRObject defaultvalue) {
+ this.defaultvalue = defaultvalue;
+ }
+
+ /**
+ * @return the type
+ */
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * @param type the type to set
+ */
+ public void setType(int type) throws RulesException {
+ this.type = type;
+ setTypeValue(RSession.typeInt2Str(type));
+ }
+
+ /**
+ * @return the writable
+ */
+ public boolean isWritable() {
+ return writable;
+ }
+
+ /**
+ * @param writable the writable to set
+ */
+ public void setWritable(boolean writable) {
+ this.writable = writable;
+ }
+
+ public String getTypeValue() throws RulesException {
+ if(typeValue==null)typeValue=RSession.typeInt2Str(type);
+ return typeValue;
+ }
+
+ public void setTypeValue(String typeValue) throws RulesException{
+ this.typeValue = typeValue;
+ setType(RSession.typeStr2Int(typeValue,entity.getName().stringValue(),attribute.stringValue()));
+ }
+
+ public String getAttributeStrValue() {
+ return attribute.stringValue();
+ }
+
+ public void setAttributeStrValue(String attributeStrValue) {
+ setAttribute(RName.getRName(attributeStrValue));
+ }
+
+ public final int getIndex() {
+ return index;
+ }
+
+ public final void setIndex(int index) {
+ this.index = index;
+ }
+
+ /**
+ * @return the subtype
+ */
+ public String getSubtype() {
+ return subtype;
+ }
+
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/infrastructure
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-07-14T12:43:20.770450Z
+10322
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RulesException.java
+file
+
+
+
+
+2008-07-13T04:44:51.406250Z
+a9963b6ff8dad5ba94f3abc4e8688478
+2008-07-14T12:43:20.770450Z
+10322
+psnow
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.infrastructure;
+
+import javax.rules.RuleException;
+
+public class RulesException extends RuleException {
+ String errortype;
+ String location;
+ String message;
+ String decisionTable="";
+ String postfix = null;
+ String filename = null;
+ String section = null;
+ int number;
+
+ public void setPostfix(String s){
+ if(postfix == null){
+ postfix = s;
+ }
+ }
+
+ public String getPostfix(){
+ return postfix;
+ }
+
+ /**
+ * Get the DecisionTable under execution at the time the error
+ * occurred. Returns a null if unknown.
+ * @return
+ */
+ public String getDecisionTable() {
+ return decisionTable;
+ }
+
+ /**
+ * Set the decisionTable under execution when the error occurred.
+ * @param decisionTable
+ */
+ public void addDecisionTable(String decisionTable, String filename) {
+ if(filename==null)filename="";
+ if(this.decisionTable.length()==0){
+ this.decisionTable = decisionTable+" \n";
+ }else {
+ this.decisionTable = this.decisionTable+" called by: "+decisionTable+" \t("+filename+")\n";
+ }
+ if(this.filename == null) this.filename = filename;
+ }
+
+ public RulesException(String type, String _location, String _message ){
+ super("Location :"+_location+" type: "+type+" error: "+_message);
+ location = _location;
+ errortype = type;
+ message = _message;
+ }
+
+ static final long serialVersionUID = 0;
+
+ /**
+ * Provide my view of a Rules Exception;
+ */
+ public String toString() {
+
+ return
+ (decisionTable!="" ? "\nDecision Table: "+decisionTable:"\n") +
+ "File name: "+filename+"\n"+
+ ((section!= null) ? ("Section: "+section + " " + number +"\n"):"")+
+ ((postfix!= null) ? ("Postfix: "+postfix+"\n"):"")+
+ "Location: '"+location+"'\n" +
+ "Type: '"+errortype+"'\n" +
+ "Error: '"+message+"'\n" ;
+ }
+
+ /**
+ * @return the section
+ */
+ public String getSection() {
+ return section;
+ }
+
+ /**
+ * @param section the section to set
+ */
+ public void setSection(String section, int number) {
+ if(this.section == null){
+ this.section = section;
+ this.number = number;
+ }
+ }
+
+ /**
+ * @return the number
+ */
+ public int getNumber() {
+ return number;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.infrastructure;
+
+import javax.rules.RuleException;
+
+public class RulesException extends RuleException {
+ String errortype;
+ String location;
+ String message;
+ String decisionTable="";
+ String postfix = null;
+ String filename = null;
+ String section = null;
+ int number;
+
+ public void setPostfix(String s){
+ if(postfix == null){
+ postfix = s;
+ }
+ }
+
+ public String getPostfix(){
+ return postfix;
+ }
+
+ /**
+ * Get the DecisionTable under execution at the time the error
+ * occurred. Returns a null if unknown.
+ * @return
+ */
+ public String getDecisionTable() {
+ return decisionTable;
+ }
+
+ /**
+ * Set the decisionTable under execution when the error occurred.
+ * @param decisionTable
+ */
+ public void addDecisionTable(String decisionTable, String filename) {
+ if(filename==null)filename="";
+ if(this.decisionTable.length()==0){
+ this.decisionTable = decisionTable+" \n";
+ }else {
+ this.decisionTable = this.decisionTable+" called by: "+decisionTable+" \t("+filename+")\n";
+ }
+ if(this.filename == null) this.filename = filename;
+ }
+
+ public RulesException(String type, String _location, String _message ){
+ super("Location :"+_location+" type: "+type+" error: "+_message);
+ location = _location;
+ errortype = type;
+ message = _message;
+ }
+
+ static final long serialVersionUID = 0;
+
+ /**
+ * Provide my view of a Rules Exception;
+ */
+ public String toString() {
+
+ return
+ (decisionTable!="" ? "\nDecision Table: "+decisionTable:"\n") +
+ "File name: "+filename+"\n"+
+ ((section!= null) ? ("Section: "+section + " " + number +"\n"):"")+
+ ((postfix!= null) ? ("Postfix: "+postfix+"\n"):"")+
+ "Location: '"+location+"'\n" +
+ "Type: '"+errortype+"'\n" +
+ "Error: '"+message+"'\n" ;
+ }
+
+ /**
+ * @return the section
+ */
+ public String getSection() {
+ return section;
+ }
+
+ /**
+ * @param section the section to set
+ */
+ public void setSection(String section, int number) {
+ if(this.section == null){
+ this.section = section;
+ this.number = number;
+ }
+ }
+
+ /**
+ * @return the number
+ */
+ public int getNumber() {
+ return number;
+ }
+
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/interpreter
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RArray.java
+file
+
+
+
+
+2008-08-21T13:30:47.515625Z
+0291f97de0d27a9a8e10d40d10df9e14
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+RBoolean.java
+file
+
+
+
+
+2008-08-21T21:07:59.203125Z
+2127d4569579a98faacc2b26f3f77452
+2008-08-22T15:39:42.122890Z
+11315
+psnow
+\f
+IRObject.java
+file
+
+
+
+
+2008-08-24T02:27:10.750000Z
+06d2282a6f1d96d16ab75b591494e347
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RName.java
+file
+
+
+
+
+2008-09-04T04:46:56.421875Z
+223e11330a9bbd6a7bc22dec3da63af5
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7989
+\f
+RTable.java
+file
+
+
+
+
+2008-09-08T18:19:27.156250Z
+1a52bd394be923fed2f606c2ea0cab2f
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7360
+\f
+RMark.java
+file
+
+
+
+
+2008-05-15T17:27:58.453125Z
+331f7f573b7f5d506e82a29e80428ba5
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+RXmlValue.java
+file
+
+
+
+
+2008-08-25T04:59:03.000000Z
+64c88c89738c317bb2870716fabc8a22
+2008-08-25T15:24:13.257771Z
+11349
+psnow
+\f
+RInteger.java
+file
+
+
+
+
+2008-08-24T00:37:21.218750Z
+3f9dc1cf30e6d04b9afb10a1b33f3ab0
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+Token.java
+file
+
+
+
+
+2008-05-15T17:27:58.296875Z
+ac8395feef0bc60089bbd3a8874b175c
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+RTime.java
+file
+
+
+
+
+2008-08-25T05:27:50.890625Z
+891fff80ae33663324d591ab54543633
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+SimpleTokenizer.java
+file
+
+
+
+
+2008-09-08T15:56:12.453125Z
+b0052129a701b3f86501f57a563ec7fc
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4100
+\f
+RString.java
+file
+
+
+
+
+2008-08-24T00:31:49.015625Z
+3a6138ba3ebf9332f116de2c23a66e8e
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+ARObject.java
+file
+
+
+
+
+2008-08-24T02:29:56.609375Z
+60decc6e1ab86e61abc841ff446b3699
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RNull.java
+file
+
+
+
+
+2008-05-15T17:27:58.453125Z
+01695dc491a18f96fcfd6ba238dd9a1a
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+RDouble.java
+file
+
+
+
+
+2008-08-24T00:31:48.718750Z
+4eb13bdce1e8af2558d2b597a8d9a11c
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+operators
+dir
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+public abstract class ARObject implements IRObject {
+
+ /**
+ * No point in implementing this here. Every Object that has
+ * an array representation needs to implement it themselves.
+ */
+ public RArray rArrayValue() throws RulesException {
+ throw new RulesException("Conversion Error","ARObject","No Time value exists for "+this.stringValue());
+ }
+
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ public RTime rTimeValue() throws RulesException {
+ return RTime.getRTime(timeValue());
+ }
+
+ public Date timeValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Time value exists for: "+this);
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(this);
+ }
+
+ public IRObject getExecutable(){
+ return this;
+ }
+
+ public IRObject getNonExecutable() {
+ return this;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return o==this;
+ }
+
+ public boolean isExecutable() {
+ return false;
+ }
+
+ public String postFix() {
+ return toString();
+ }
+
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+ public IRObject rclone() {
+ return (IRObject) this;
+ }
+
+ /** Conversion Methods. Default is to throw a RulesException **/
+
+ public int intValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Array value exists for "+this);
+ }
+
+ public boolean booleanValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Boolean value exists for "+this);
+ }
+
+ public double doubleValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No double value exists for "+this);
+ }
+
+ public IREntity rEntityValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Entity value exists for "+this);
+ }
+ @SuppressWarnings({"unchecked"})
+ public HashMap hashMapValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public long longValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Long value exists for "+this);
+ }
+
+ public RName rNameValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public RInteger rIntegerValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public int compare(IRObject irObject) throws RulesException {
+ throw new RulesException("Undefined","No Supported","Compared Not suppoted for this object"+this);
+ }
+
+ /**
+ * By default, objects clone themselves by simply returnning themselves.
+ * This is because the clone of a number or boolean etc. is itself.
+ */
+ public IRObject clone(IRSession s) throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#rTableValue()
+ */
+ public RTable rTableValue() throws RulesException {
+ throw new RulesException("Undefined","Not Supported","No Table value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#tableValue()
+ */
+ @SuppressWarnings({"unchecked"})
+ public HashMap tableValue() throws RulesException {
+ throw new RulesException("Undefined","Not Supported","No Table value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#rXmlValue()
+ */
+ public RXmlValue rXmlValue() throws RulesException {
+ throw new RulesException("Conversion Error","","No XmlValue value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#xmlTagValue()
+ */
+ public XMLTag xmlTagValue() throws RulesException {
+ throw new RulesException("Conversion Error","","No XmlValue value exists for "+this);
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+@SuppressWarnings({"unchecked"})
+public interface IRObject {
+
+ public IRObject clone(IRSession s) throws RulesException;
+
+ // *************** NOTE !!!!!!
+ // You can't put static methods on an interface. So the String to integer conversion
+ // for types is a static method on the RSession class.
+
+ final String rBoolean = "boolean",
+ rString = "string",
+ rInteger = "integer",
+ rFloat = "float",
+ rEntity = "entity",
+ rName = "name",
+ rArray = "array",
+ rDecisiontable = "decisiontable",
+ rNull = "null",
+ rMark = "mark",
+ rOperator = "operator",
+ rTime = "time",
+ rTable = "table",
+ rXmlValue = "xmlvalue";
+
+ final String types[] = { rBoolean, rString, rInteger, rFloat,
+ rEntity, rName, rArray, rDecisiontable,
+ rNull, rMark, rOperator, rTime,
+ rTable, rXmlValue};
+
+ final int iBoolean = 0,
+ iString = 1,
+ iInteger = 2,
+ iDouble = 3,
+ iEntity = 4,
+ iName = 5,
+ iArray = 6,
+ iDecisiontable = 7,
+ iNull = 8,
+ iMark = 9,
+ iOperator = 10,
+ iTime = 11,
+ iTable = 12,
+ iXmlValue = 13;
+
+
+ void execute(DTState state) throws RulesException;
+
+ public IRObject getExecutable();
+
+ public IRObject getNonExecutable();
+
+ public boolean equals(IRObject o) throws RulesException;
+
+ public boolean isExecutable();
+
+ /**
+ * By default, the toString() method for most Objects should provide
+ * a representation of the object that can be used as the postFix value.
+ * The stringValue should provide simply the data for the object. Thus
+ * If I want to append the a String and a Date to create a new string,
+ * I should append the results from their stringValue() implementation.
+ * <br><br>
+ * If I needed the postfix (and thus the quotes and maybe other ) then
+ * call postFix(). But if the postFix is going to match either stringValue()
+ * or toString, it is going to match toString().
+ * <br><br>
+ * @return
+ */
+ public String stringValue();
+ public RString rStringValue();
+
+ public String postFix();
+
+ public int type();
+
+ public IRObject rclone();
+
+ public XMLTag xmlTagValue() throws RulesException;
+ public long longValue () throws RulesException;
+ public int intValue () throws RulesException;
+ public RInteger rIntegerValue() throws RulesException;
+ public double doubleValue () throws RulesException;
+ public RDouble rDoubleValue() throws RulesException;
+ public ArrayList<IRObject> arrayValue () throws RulesException;
+ public RArray rArrayValue() throws RulesException;
+ public boolean booleanValue () throws RulesException;
+ public RBoolean rBooleanValue() throws RulesException;
+ public HashMap hashMapValue () throws RulesException;
+ public RXmlValue rXmlValue () throws RulesException;
+ public IREntity rEntityValue () throws RulesException;
+ public RName rNameValue () throws RulesException;
+ public RTime rTimeValue () throws RulesException;
+ public Date timeValue () throws RulesException;
+ public RTable rTableValue() throws RulesException;
+ public HashMap tableValue() throws RulesException;
+ public int compare(IRObject irObject) throws RulesException;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+/**
+ * Immplements Arrays for Decision Tables. Because we can't tag references,
+ * we do the same trick here that we do for RNames, i.e. we create an executable
+ * and a non-executable version of each array. However, we only create one
+ * ArrayList.
+ * <br><br>
+ * If dups is true, we allow duplicate references in the array. Sometimes it
+ * is pleasent to have an array whose values are all unique. In that case, create
+ * an array with dups set to false. <br>
+ * <br>
+ * @author ps24876
+ *
+ */
+@SuppressWarnings("unchecked")
+public class RArray extends ARObject implements Collection<IRObject> {
+ final ArrayList<IRObject> array;
+ final RArray pair;
+ final boolean executable;
+ final boolean dups;
+ final int id;
+
+
+
+
+
+ /* (non-Javadoc)
+ * @see java.util.Collection#addAll(java.util.Collection)
+ */
+ public boolean addAll(Collection<? extends IRObject> arg0) {
+ return array.addAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#clear()
+ */
+ public void clear() {
+ array.clear();
+
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean contains(Object arg0) {
+ if(arg0 instanceof IRObject) {
+ for(IRObject o: array){
+ try{ // Really this isn't possible.
+ if (o.equals((IRObject)arg0))return true;
+ }catch(RulesException e){}
+ }
+ }
+ return false;
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#containsAll(java.util.Collection)
+ */
+ public boolean containsAll(Collection<?> arg0) {
+ return array.containsAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#isEmpty()
+ */
+ public boolean isEmpty() {
+ return array.isEmpty();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#iterator()
+ */
+ public Iterator<IRObject> iterator() {
+ return array.iterator();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#remove(java.lang.Object)
+ */
+ public boolean remove(Object arg0) {
+ return array.remove(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(Collection<?> arg0) {
+ return array.removeAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(Collection<?> arg0) {
+ return retainAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#toArray()
+ */
+ public Object[] toArray() {
+ return array.toArray();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#toArray(T[])
+ */
+ public <T> T[] toArray(T[] arg0) {
+ return array.toArray( arg0);
+ }
+ /**
+ * Returns the id of this array. Used by debuggers to analyze trace files
+ * @return ID of the array
+ */
+ public int getID(){ return id; }
+ /**
+ * Constructor to create the core structure for an RArray.
+ * @param bogus
+ * @param exectuable
+ */
+ protected RArray(int id, boolean duplicates, ArrayList thearray, RArray otherpair, boolean executable){
+ this.id = id;
+ this.array = thearray;
+ this.executable = executable;
+ this.pair = otherpair;
+ this.dups = duplicates;
+ }
+
+ public RArray(int id, boolean duplicates, boolean executable){
+ this.id = id;
+ array = new ArrayList();
+ this.executable = executable;
+ dups = duplicates;
+ pair = new RArray(id,dups, array, this, !executable);
+ }
+
+ public RArray(int id, boolean duplicates, ArrayList thearray, boolean executable){
+ this.id = id;
+ this.array = thearray;
+ this.executable = executable;
+ dups = duplicates;
+ pair = new RArray(id,dups,thearray,this,!executable);
+ }
+
+ public Iterator getIterator(){ return array.iterator(); }
+
+ public int type() {
+ return iArray;
+ }
+ public boolean add(IRObject v){
+ if(!dups && array.contains(v))return false;
+ return array.add(v);
+ }
+ public void add(int index,IRObject v){
+ array.add(index,v);
+ }
+ public void delete(int index){
+ array.remove(index);
+ }
+ public void remove(IRObject v){
+ array.remove(v);
+ }
+ public IRObject get(int index) throws RulesException{
+ if(index<0 || index>= array.size()){
+ throw new RulesException("Undefined","RArray","Index out of bounds");
+ }
+ return (IRObject) array.get(index);
+ }
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ return array;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ if(o.type() != iArray) return false;
+ return ((RArray)o).array == array;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0; // A debugging aid.
+ for(IRObject obj : this){
+ if(obj.type()==iArray || !obj.isExecutable()){
+ state.datapush(obj);
+ }else{
+ try{
+ obj.execute(state);
+ }catch(RulesException e){
+ e.setPostfix(this.postFix());
+ throw e;
+ }
+ }
+ cnt++;
+ }
+
+ }
+
+ public IRObject getExecutable() {
+ if(executable)return this;
+ return pair;
+ }
+
+ public IRObject getNonExecutable() {
+ if(!executable)return this;
+ return pair;
+ }
+
+ public boolean isExecutable() {
+ return executable;
+ }
+
+ public String postFix() {
+ StringBuffer result = new StringBuffer();
+ result.append(executable?"{":"[");
+ for (IRObject obj : array){
+ result.append(obj.postFix());
+ result.append(" ");
+ }
+ result.append(executable?"}":"]");
+ return result.toString();
+ }
+
+ public String stringValue() {
+ StringBuffer result = new StringBuffer();
+ result.append(isExecutable()?"{ ":"[ ");
+ for(IRObject obj : array){
+ result.append(obj.stringValue());
+ result.append(" ");
+ }
+ result.append(isExecutable()?"}":"]");
+ return result.toString();
+ }
+ public String toString() {
+ return stringValue();
+ }
+
+ /**
+ * returns the clone of this object
+ */
+ public IRObject clone(IRSession session) {
+ ArrayList<IRObject> newArray = new ArrayList<IRObject>();
+ newArray.addAll(array);
+ return new RArray(session.getUniqueID(), dups, newArray, executable);
+ }
+
+ public RArray rArrayValue() throws RulesException {
+ return this;
+ }
+
+ /*
+ * Returns the size of the array.
+ */
+ public int size()
+ {
+ return this.array.size();
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class RBoolean extends ARObject {
+
+ /**
+ * Provides all the supported conversions of a String to a boolean value.
+ * @param value
+ * @return
+ * @throws RulesException
+ */
+ public static boolean booleanValue(String value)throws RulesException {
+ String v = value.trim();
+ if(v.equalsIgnoreCase("true") ||
+ v.equalsIgnoreCase("y") ||
+ v.equalsIgnoreCase("t") ||
+ v.equalsIgnoreCase("yes")){
+ return true;
+ }else if(v.equalsIgnoreCase("false") ||
+ v.equalsIgnoreCase("n") ||
+ v.equalsIgnoreCase("f") ||
+ v.equalsIgnoreCase("no")){
+ return false;
+ }
+ throw new RulesException("typecheck","String Conversion to Boolean","No boolean value for this string: "+value);
+ }
+ /**
+ * Really, there is no reason for more that two instances of Boolean objects
+ * in the Rules Engine world.
+ */
+ private static RBoolean trueValue = new RBoolean(true);
+ private static RBoolean falseValue = new RBoolean(false);
+ /**
+ * The value of this boolean object.
+ */
+ public final boolean value;
+ /**
+ * A private constructor to avoid any creation of boolean values besides
+ * the two (true and false)
+ * @param _value
+ */
+ private RBoolean(boolean _value){
+ value = _value;
+ }
+ /**
+ * Report that this is indeed a boolean object.
+ */
+ public int type() {
+ return iBoolean;
+ }
+ /**
+ * Return the proper boolean object for the given boolean value.
+ * @param value
+ * @return
+ */
+ public static RBoolean getRBoolean(boolean value){
+ if(value)return trueValue;
+ return falseValue;
+ }
+
+ /**
+ * Attempt to convert the string, and return the proper boolean object.
+ * @param value
+ * @return
+ * @throws RulesException
+ */
+ public static RBoolean getRBoolean(String value) throws RulesException {
+ return getRBoolean(booleanValue(value));
+ }
+ /**
+ * Return my value.
+ */
+ public boolean booleanValue() throws RulesException {
+ return value;
+ }
+ /**
+ * We *COULD* simply do an object equality test...
+ */
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.booleanValue();
+ }
+ /**
+ * Return the string value for this boolean.
+ */
+ public String stringValue() {
+ if(value)return "true";
+ return "false";
+ }
+ /**
+ * Return the string value for this boolean
+ */
+ public String toString() {
+ return stringValue();
+ }
+ /**
+ * The postfix is nothing more than the string value for this boolean.
+ */
+ public String postFix() {
+ return stringValue();
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+/**
+ * @author Paul Snow
+ *
+ */
+public class RDouble extends ARObject {
+ final double value;
+
+ static RDouble mone = new RDouble(-1.0);
+ static RDouble zero = new RDouble(0.0);
+ static RDouble one = new RDouble(1.0);
+
+ private RDouble(double v){
+ value = v;
+ }
+
+ static public double getDoubleValue(String s) throws RulesException {
+ if(s==null || s.trim().length()==0){
+ return 0.0D;
+ }
+ try {
+ double v = Double.parseDouble(s);
+ return v;
+ } catch (NumberFormatException e) {
+ throw new RulesException("Conversion Error","RDouble.getDoubleValue()","Could not covert the string '"+s+"' to a double: "+e.getMessage());
+ }
+ }
+ /**
+ * Parses the given string, and returns an RDouble Object
+ * @param s String to parse
+ * @return RDouble value for the given string
+ * @throws RulesException
+ */
+ static public RDouble getRDoubleValue(String s) throws RulesException {
+ return getRDoubleValue(getDoubleValue(s));
+ }
+
+
+
+ static public RDouble getRDoubleValue(double v){
+ if(v == -1.0) return mone;
+ if(v == 0.0) return zero;
+ if(v == 1.0) return one;
+
+ return new RDouble(v);
+ }
+
+ static public RDouble getRDoubleValue(int v){
+ return getRDoubleValue((double) v);
+ }
+
+ static public RDouble getRDoubleValue(long v){
+ return getRDoubleValue((double) v);
+ }
+
+ public RDouble rDoubleValue() {
+ return this;
+ }
+
+ public double doubleValue() {
+ return value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public RInteger rIntegerValue() {
+ return RInteger.getRIntegerValue((long)value);
+ }
+
+ /**
+ * Returns the type for this object.
+ */
+ public int type() {
+ return iDouble;
+ }
+
+ public String stringValue() {
+ return Double.toString(value);
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ return (this.value==irObject.doubleValue())?0:((this.value<irObject.doubleValue())?-1:0);
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.doubleValue();
+ }
+
+ public String toString() {
+ return Double.toString(value);
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+/**
+ * Integers are longs.
+ * @author ps24876
+ *
+ */
+public class RInteger extends ARObject {
+ final long value;
+
+ static RInteger mone = new RInteger(-1);
+ static RInteger zero = new RInteger( 0);
+ static RInteger one = new RInteger( 1);
+
+ private RInteger(long i){
+ value = i;
+ }
+
+ /**
+ * Parses the given string, and returns an RInteger Object
+ * @param s String to parse
+ * @return RInteger value for the given string
+ * @throws RulesException
+ */
+ static public long getIntegerValue(String s) throws RulesException {
+ if(s==null || (s = s.trim()).length()==0 || s.equalsIgnoreCase("null")){
+ return 0L;
+ }
+ try {
+ long v = Long.parseLong(s);
+ return v;
+ } catch (NumberFormatException e) {
+ throw new RulesException("Conversion Error","RInteger.getIntegerValue()","Could not covert the string '"+s+"' to an integer: "+e.getMessage());
+ }
+ }
+
+ static public RInteger getRIntegerValue(String s) throws RulesException {
+ return getRIntegerValue(getIntegerValue(s));
+ }
+
+ static public RInteger getRIntegerValue(long i){
+
+ if(i == -1) return mone;
+ if(i == 0) return zero;
+ if(i == 1) return one;
+ return new RInteger(i);
+ }
+
+ static public RInteger getRIntegerValue(double i){
+ return getRIntegerValue((long) i);
+ }
+
+ static public RInteger getRIntegerValue(int i){
+ return getRIntegerValue((long) i);
+ }
+
+ public int type() {
+ return iInteger;
+ }
+
+ public double doubleValue() {
+ return (double)value;
+ }
+
+ public int intValue() {
+ return (int)value;
+ }
+
+ public long longValue() throws RulesException {
+ return (long) value;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.intValue();
+ }
+
+ public String postFix() {
+ return stringValue();
+ }
+
+ public RInteger rIntegerValue() throws RulesException {
+ return this;
+ }
+
+ public String stringValue() {
+ String str = Long.toString(value);
+ return str;
+ }
+
+ public String toString(){
+ return stringValue();
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ return (this.value==irObject.intValue())?0:((this.value<irObject.intValue())?-1:0);
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+/**
+ * A Mark object is used as a place holder on the data stack.
+ * arraytomark then pops all elements upto but not including the
+ * mark, and puts them into an array.
+ *
+ * @author paul snow
+ *
+ */
+public class RMark extends ARObject {
+
+ static RMark themark = new RMark();
+
+ private RMark(){}
+
+ static public RMark getMark() { return themark; }
+
+ public String stringValue() {
+ return "Mark";
+ }
+
+ public int type() {
+ return iMark;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.HashMap;
+import java.util.regex.Pattern;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings({"unchecked"})
+public class RName extends ARObject {
+
+ final RName entity;
+ final String name;
+ final boolean executable;
+ final int hashcode;
+ final RName partner; // RNames are created in pairs, executable and non-executable.
+
+ static HashMap names = new HashMap();
+
+ /**
+ * This constructor should only be called by the other RName constructor.
+ * It is used to build its partner. RNames are always created in pairs,
+ * one executable and one non-executable.
+ *
+ * @param _name
+ * @param _executable
+ * @param _hashcode
+ * @param _partner
+ */
+ private RName(RName _entity, String _name, boolean _executable, int _hashcode, RName _partner){
+ entity = _entity;
+ name = _name;
+ executable = _executable;
+ hashcode = _hashcode;
+ partner = _partner;
+ }
+ /**
+ * This constructor should only be called by the getRName method. This
+ * constructor always creates two RNames, the one requested and its partner.
+ *
+ * @param _name
+ * @param _executable
+ * @param _hashcode
+ */
+ private RName(RName _entity, String _name, boolean _executable, int _hashcode ){
+ entity = _entity;
+ name = _name;
+ executable = _executable;
+ hashcode = _hashcode;
+ partner = new RName(_entity, _name,!_executable,_hashcode,this);
+ }
+
+ static Pattern spaces = Pattern.compile(" ");
+ /**
+ * When you don't really care about the executable nature of the
+ * name, then use this accessor. We parse looking for the slash to
+ * determine a literal, so by default (i.e. no slash given), we
+ * return executable names. This constructor also pareses to handle
+ * the "dot" syntax.
+ * @exception RuntimeException is thrown if the Syntax is incorrect.
+ * @param _name String from which to create a name
+ * @return The Name object
+ */
+ static public RName getRName(String _name){
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = spaces.matcher(_name.trim()).replaceAll("_");
+ boolean executable = !(_name.indexOf('/')==0);
+ if(!executable){
+ _name = _name.substring(1); // Remove the slash.
+ }
+ int dot = _name.indexOf('.');
+
+ if(dot>=0){
+ String entity = _name.substring(0,dot);
+ if(dot == 0 || dot+1 == _name.length() || _name.indexOf(dot+1,'.')>=0){
+ throw new RuntimeException("Invalid Name Syntax: ("+_name+")");
+ }
+ String name = _name.substring(dot+1);
+ return getRName(RName.getRName(entity),name,executable);
+ }
+ return getRName(null, _name, executable);
+ }
+ /**
+ * We cache the creation of RNames so as to not create new copies
+ * of RNames that we don't have to create. (RNames are reusable)
+ * <br><br>
+ * Thus one calls one of the getRName functions, and one cannot call our
+ * constructors directly.
+ * <br><br>
+ * Returns a null if a RName cannot be found/created.
+ *
+ * @param _name
+ * @return
+ */
+ static public RName getRName(String _name, boolean _executable) {
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = _name.trim().replaceAll(" ","_");
+ return getRName(null,_name,_executable);
+ }
+
+ static Pattern space = Pattern.compile(" ");
+ /**
+ * We cache the creation of RNames so as to not create new copies
+ * of RNames that we don't have to create. (RNames are reusable)
+ * <br><br>
+ * Thus one calls one of the getRName functions, and one cannot call our
+ * constructors directly.
+ *
+ * @param _name
+ * @return
+ */
+ static public RName getRName(RName _entity, String _name, boolean _executable) {
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = space.matcher(_name).replaceAll("_");
+ // If we already have the RName, we are done.
+ String lname = _name.toLowerCase();
+ String cname = _name;
+ if(_entity!=null){
+ cname = _entity.stringValue().toLowerCase()+"."+lname;
+ }
+ RName rn = (RName) names.get(cname);
+ if(rn == null ) {
+ rn = new RName(_entity ,_name,_executable, lname.hashCode());
+ names.put(cname,rn);
+ }
+ if(_executable) return (RName) rn.getExecutable();
+ return (RName) rn.getNonExecutable();
+ }
+ /**
+ * Returns the entity component of the name, which is null if none
+ * was specfied when the name was created.
+ *
+ * @return
+ */
+ public RName getEntityName(){
+ return entity;
+ }
+
+ public boolean equals(Object arg0) {
+ if(arg0.getClass()!=RName.class)return false;
+ boolean f = name.equalsIgnoreCase(((RName)arg0).name);
+ return f;
+ }
+
+ public int hashCode() {
+ return hashcode;
+ }
+
+ /**
+ * Compare this RName with another Rules Engine Object. RNames
+ * are only equal to other RNames.
+ */
+ public boolean equals(IRObject o) {
+ if(o.type()!=IRObject.iName)return false;
+ return equals((Object)o);
+ }
+ static int cnt= 0;
+ /**
+ * The execution of an RName looks up that RName in the Entity
+ * Stack. If the object found there is an Array, it is pushed
+ * to the Entity Stack. If the object found there is not an
+ * array, and it is not executable, then it is pushed. Otherwise
+ * (not an array, and executable) the object is executed.
+ */
+ public void execute(DTState state) throws RulesException {
+ cnt++;
+ IRObject o = state.find(this); // Does a lookup of the name on the Entity Stack
+ if(o==null){
+ throw new RulesException("Undefined","RName","The Name '"+name+"' was not defined by any Entity on the Entity Stack");
+ }
+ if(o.isExecutable()){
+ o.execute(state);
+ }else{
+ state.datapush(o);
+ }
+ }
+
+ public IRObject getExecutable() {
+ return executable ? this : partner ;
+ }
+
+ public IRObject getNonExecutable() {
+ return executable ? partner : this ;
+ }
+
+ public boolean isExecutable() {
+ return executable;
+ }
+
+
+ /**
+ * Returns the postfix version of the name.
+ */
+ public String postFix() {
+ return executable ? stringValue() : "/"+stringValue();
+ }
+
+ /**
+ * Returns the value of the name unadorned by the leading slash, even
+ * if the name is a literal.
+ */
+ public String stringValue() {
+ if(entity!=null){
+ return entity.stringValue()+"."+name;
+ }
+ return name;
+ }
+
+ /**
+ * Returns the nicest format for debugging, i.e. the Postfix version which
+ * has the slash if the name is a literal name.
+ */
+ public String toString(){
+ return postFix();
+ }
+
+ public int type() {
+ return iName;
+ }
+
+ @Override
+ public int compare(IRObject obj) throws RulesException {
+ String v = obj.stringValue();
+ return name.compareToIgnoreCase(v);
+ }
+ /**
+ * Returns myself
+ */
+ public RName rNameValue() throws RulesException {
+ return this;
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rStringValue()
+ */
+ @Override
+ public RString rStringValue() {
+ return RString.newRString(name);
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class RNull extends ARObject {
+
+ /**
+ * returns 0 if both are equal. -1 Otherwise. A Null is considered
+ * less than anything else. We do this just so sorting arrays were
+ * some values are null doesn't blow up.
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ if(irObject.equals(this))return 0; // A Null is equal to other nulls.
+ return -1; // A Null is less than anything else.
+ }
+
+
+
+ static RNull theNullObject = new RNull();
+ /**
+ * Nobody needs the constructor.
+ *
+ */
+ private RNull(){}
+
+ /**
+ * Returns the RNull object. There is no need for more than
+ * one of these objects.
+ * @return
+ */
+ public static RNull getRNull(){ return theNullObject; }
+
+ /**
+ * A Null is only equal to the null object
+ */
+ public boolean equals(IRObject o) {
+ return o.type()==iNull;
+ }
+
+ public String stringValue() {
+ return "null";
+ }
+
+ /**
+ * A Null is only equal to the null object, i.e. any
+ * Null object. They are all equal.
+ */
+ public boolean equals(Object arg0) {
+ return arg0.getClass().equals(this.getClass());
+ }
+
+ /**
+ * We override toString() to simply return "null".
+ * Because we do this, we override hashcode() as well.
+ */
+ public String toString() {
+ return "null";
+ }
+
+ public int hashCode() {
+ return 0;
+ }
+
+ public int type() {
+ return iNull;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.operators.ROperator;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RuleSet;
+
+/**
+ * @author Paul Snow
+ *
+ */
+public class RString extends ARObject {
+
+ RString pair;
+ String value;
+ boolean executable = false;
+
+ public double doubleValue() throws RulesException {
+ double d;
+ try {
+ d = Double.parseDouble(value);
+ } catch (NumberFormatException e) {
+ return super.doubleValue();
+ }
+ return d;
+ }
+
+ @Override
+ public int intValue() throws RulesException {
+ int i;
+ try {
+ i = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return super.intValue();
+ }
+ return i;
+ }
+
+ @Override
+ public long longValue() throws RulesException {
+ long l;
+ try {
+ l = Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return super.longValue();
+ }
+ return l;
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(longValue());
+ }
+
+ @Override
+ public RName rNameValue() throws RulesException {
+ return RName.getRName(value);
+ }
+
+ @Override
+ public RString rStringValue() {
+ return this;
+ }
+
+ private RString(String v,boolean executable,RString pair){
+ value = v;
+ this.pair = pair;
+ this.executable = executable;
+ }
+ /**
+ * Return a non Executable string
+ * @param v
+ * @return
+ */
+ static public RString newRString(String v){
+ return newRString(v,false);
+ }
+ /**
+ * Return an RString of the given executable nature.
+ * @param v
+ * @param executable
+ * @return
+ */
+ static public RString newRString(String v, boolean executable){
+ RString s = new RString(v,executable,null);
+ s.pair = new RString(v,!executable,s);
+ return s;
+ }
+
+ @Override
+ public IRObject getExecutable() {
+ if(isExecutable()){
+ return this;
+ }else{
+ return pair;
+ }
+ }
+
+ @Override
+ public IRObject getNonExecutable() {
+ if(isExecutable()){
+ return pair;
+ }else{
+ return this;
+ }
+ }
+
+ /**
+ * Returns a boolean value if the String can be reasonably
+ * interpreted as a boolean.
+ *
+ * @Override
+ */
+ public boolean booleanValue() throws RulesException {
+ return RBoolean.booleanValue(value);
+ }
+
+ /**
+ *
+ */
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ /**
+ * Returns String type.
+ * @see com.dtrules.interpreter.IRObject#type()
+ */
+ public int type() {
+ return iString;
+ }
+
+ /**
+ * Here we look to see if we can do a compile time lookup of
+ * an object. If we can't, we just return the object unchanged.
+ * But if we can, then we return the value we looked up. That
+ * saves many, many runtime lookups.
+ */
+ static IRObject lookup(RuleSet ruleset, RName name){
+ IRObject v = ROperator.getPrimitives().get(name); // First check if it is an operator
+ if(v==null){ // No? Then
+ try { // look for a decision table.
+ v = ruleset.getEntityFactory(null).getDecisionTable(name);
+ } catch (RulesException e) { } // Any error just means the name isn't
+ } // a decision table. Not a problem.
+ if(v==null || v.type()== iArray) return name;
+ return v;
+ }
+
+ /**
+ * Compiles the String and returns the executable Array Object
+ * that results. Unless the compilation fails, at which time
+ * we throw an exception.
+ *
+ * @return
+ * @throws RulesException
+ */
+ static public IRObject compile(RuleSet rs, String v, boolean executable) throws RulesException{
+
+ if(v==null)v=""; // Allow the compiling of null strings (we just don't do anything).
+
+ SimpleTokenizer tokenizer = new SimpleTokenizer(v);
+
+ IRObject result = compile(rs, tokenizer, v, executable, 0);
+ return result;
+ }
+
+ /**
+ * The compiles of Strings are recursive. When we see a [ or {,
+ * we recurse. Then on a close bracket ] or } we return the
+ * non-executable or executable array. The RString checks to make
+ * sure it is the right type, and throws an error if it isn't.
+ * The recursive depth is checked by compile();
+ * @param tokenizer
+ * @return
+ * @throws RulesException
+ */
+ static private IRObject compile(RuleSet ruleset, SimpleTokenizer tokenizer, String v, boolean executable, int depth) throws RulesException {
+ try{
+ RArray result = new RArray(0,true,executable);
+ Token token;
+ while((token=tokenizer.nextToken())!=null){
+ if(token.getType()== Token.Type.STRING) {
+ IRObject rs = RString.newRString(token.strValue);
+ result.add(rs);
+ }else if(token.getType()== Token.Type.LSQUARE) {
+ IRObject o = compile(ruleset,tokenizer, v, false, depth+1);
+ result.add(o);
+ }else if(token.getType()== Token.Type.RSQUARE) {
+ if(depth==0 || executable){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing <<"+v+">> \nThe token ']' was unexpected.");
+
+ }
+ return result;
+ }else if(token.getType()== Token.Type.LCURLY) {
+ IRObject o = compile(ruleset,tokenizer,v,true, depth+1);
+ result.add(o);
+ }else if(token.getType()== Token.Type.RCURLY) {
+ if(depth==0 || !executable){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing <<"+v+">> \nThe token '}' was unexpected.");
+
+ }
+ return result;
+ }else if(token.getType()== Token.Type.NAME) {
+ if(token.nameValue.isExecutable()){ // All executable names are checked for compile time lookup.
+ IRObject prim = lookup(ruleset,token.nameValue);
+ if(prim == null){ // If this name is not a primitive, then
+ result.add(token.nameValue); // then add the name as it is to the array.
+ }else{
+ result.add(prim); // Otherwise, compile the reference to the operator.
+ }
+ }else{
+ result.add(token.nameValue);
+ }
+
+ }else if (token.getType() == Token.Type.DATE){
+ result.add(token.datevalue);
+
+ }else if (token.getType()== Token.Type.INT) {
+ RInteger i = RInteger.getRIntegerValue(token.longValue);
+ result.add(i);
+ }else if (token.getType()== Token.Type.REAL) {
+ RDouble d = RDouble.getRDoubleValue(token.doubleValue);
+ result.add(d);
+ }
+ }
+ if(depth!=0){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing << " + v + " >>\n missing a " + (executable ? "}" : "]"));
+
+ }
+ return (IRObject) result;
+ } catch (RuntimeException e) {
+ throw new RulesException("Undefined","String Compile","Error compiling string: '"+v+"'\n"+e);
+ }
+
+ }
+ /**
+ * Compiles this String and returns the object.
+ * @param executable
+ * @return
+ * @throws RulesException
+ */
+ public IRObject compile(RuleSet ruleset, boolean executable) throws RulesException{
+ return compile(ruleset, value,executable);
+ }
+
+ @Override
+ public boolean isExecutable() {
+ return executable;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ if(isExecutable()){
+ IRObject o = compile(state.getSession().getRuleSet(),value,true);
+ o.execute(state);
+ }else{
+ state.datapush(this);
+ }
+ }
+
+ public String stringValue() {
+ return value;
+ }
+ public String toString(){
+ return "\""+value+"\"";
+ }
+
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ int f = this.value.compareTo(irObject.stringValue());
+ if(f<0)return -1;
+ if(f>0)return 1;
+ return f;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return value.equals(o.stringValue());
+ }
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.RuleSet;
+
+public class RTable extends ARObject {
+ private final int resultType;
+ private final int id;
+ private RName tablename;
+ private RString description;
+
+ private final HashMap<RName, IRObject> table = new HashMap<RName,IRObject>();
+
+ /**
+ * Get the description of this table
+ * @return the description
+ */
+ public RString getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the description of this table
+ */
+ public void setDescription(RString description){
+ this.description = description;
+ }
+
+ /**
+ * Return the Unique ID for this table.
+ * @return the id
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Return the type of result found in this table.
+ * @return the resultType
+ */
+ public int getResultType() {
+ return resultType;
+ }
+
+ /**
+ * Return the HashMap for primary dimension of this table
+ * @return the table
+ */
+ public HashMap<RName, IRObject> getTable() {
+ return table;
+ }
+
+ /**
+ * @return the tablename
+ */
+ public RName getTablename() {
+ return tablename;
+ }
+
+ public boolean containsKey (RName key){
+ return table.containsKey(key);
+ }
+
+ public boolean containsValue (IRObject value){
+ return table.containsValue(value);
+ }
+
+ private RTable(EntityFactory ef,
+ RName tablename,
+ String description,
+ int resultType) throws RulesException {
+ this.tablename = tablename;
+ this.resultType = resultType;
+ this.id = ef.getUniqueID();
+ this.description = RString.newRString(description);
+ }
+ /**
+ * Factory method for creating an RTable
+ * @param state
+ * @param tablename
+ * @param description
+ * @param resultType
+ * @return
+ */
+ static public RTable newRTable(EntityFactory ef, RName tablename, String description, int resultType) throws RulesException{
+ return new RTable(ef,tablename,description,resultType);
+ }
+ /**
+ * This routine assumes that the string defines an Array of the
+ * form:
+ * {
+ * { key1 value1 }
+ * { key2 value2 }
+ * ...
+ * { keyn valuen }
+ * }
+ * This routine compiles the given string, then calls the
+ * set routine that takes an array of key value pairs and sets
+ * them into the RTable
+ *
+ * @param values
+ */
+ public void setValues(RuleSet rs, String values)throws RulesException{
+ RArray array = RString.compile(rs, values, false).rArrayValue();
+ setValues(array);
+ }
+ /**
+ * This routine assumes that an Array of the
+ * form:
+ * {
+ * { key1 value1 }
+ * { key2 value2 }
+ * ...
+ * { keyn valuen }
+ * }
+ * This routine takes an array of key value pairs and sets
+ * them into the RTable
+ *
+ * @param values
+ */
+ public void setValues(RArray values) throws RulesException{
+ for(IRObject irpair : values){
+ RArray pair = irpair.rArrayValue();
+ if(pair.size()!=2){
+ throw new RulesException(
+ "Invalid_Table_Value",
+ "RTable.setValues",
+ "setValues expected an array of arrays giving pairs of values to assert into the Table");
+ }
+ RName key = pair.get(0).rNameValue();
+ IRObject value = pair.get(1);
+ setValue(key, value);
+ }
+ }
+
+ /**
+ * Set a value with the given set of keys into the given table.
+ * @param keys
+ * @param value
+ * @throws RulesException
+ */
+ @SuppressWarnings("unchecked")
+ public void setValue(DTState state, RName[]keys, IRObject value) throws RulesException{
+ IRObject v = this;
+ for(int i=0;i<keys.length-1; i++){
+ if(v.type()!=iTable){
+ throw new RulesException("OutOfBounds","RTable","Invalid Number of Keys used with Table "+this.stringValue());
+ }
+ RTable table = v.rTableValue();
+ IRObject next = table.getValue(keys[i]);
+ if(next == null){
+ next = newRTable(state.getSession().getEntityFactory(),this.tablename,this.description.stringValue(),this.resultType);
+ table.setValue(keys[i], next);
+ }
+ v = (IRObject) next;
+ }
+ v.rTableValue().setValue(keys[keys.length-1], value);
+ }
+
+ public void setValue(RName key, IRObject value) throws RulesException{
+ table.put(key, value);
+ }
+
+ public IRObject getValue(RName key) throws RulesException {
+ IRObject v = this.table.get(key);
+ if(v==null)return RNull.getRNull();
+ return v;
+ }
+
+ public IRObject getValue(RName[]keys) throws RulesException {
+ IRObject v = this;
+ for(int i=0;i<keys.length; i++){
+ if(v.type()!=iTable){
+ throw new RulesException("OutOfBounds","RTable","Invalid Number of Keys used with Table "+this.stringValue());
+ }
+ RTable table = v.rTableValue();
+ IRObject next = table.getValue(keys[i]);
+ if(next == null){
+ return RNull.getRNull();
+ }
+ v = (IRObject) next;
+ }
+ return v;
+ }
+
+ public RArray getKeys (DTState state){
+ ArrayList <RName> keys = new ArrayList<RName>(table.keySet());
+ int id = state.getSession().getUniqueID();
+ return new RArray(id, true, keys,false);
+ }
+
+ public String stringValue() {
+ return tablename.stringValue();
+ }
+
+ public int type() {
+ return iTable;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rTableValue()
+ */
+ @Override
+ public RTable rTableValue() throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#tableValue()
+ */
+ @SuppressWarnings({"unchecked"})
+ public HashMap tableValue() throws RulesException {
+ return table;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+public class RTime extends ARObject {
+ final Date time;
+ public int type() {
+ return iTime;
+ }
+
+ @Override
+ public double doubleValue() throws RulesException {
+ return time.getTime();
+ }
+
+ @Override
+ public long longValue() throws RulesException {
+ return time.getTime();
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(time.getTime());
+ }
+
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(time.getTime());
+ }
+
+ @Override
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+
+
+ private RTime(Date t){
+ time = t;
+ }
+
+ public static SimpleDateFormat [] formats ={
+ new SimpleDateFormat("MM/dd/yyyy"),
+ new SimpleDateFormat("MM-dd-yyyy"),
+ };
+
+ public static Date getDate(String s){
+ for(int i=0;i<formats.length;i++){
+ try {
+ Date d = formats[i].parse(s);
+ return d;
+ } catch (ParseException e) { } // Didn't work? just try again
+ }
+ return null;
+ }
+
+ /**
+ * Returns a Null if no valid RDate can be parsed from
+ * the string representation
+ * @param s
+ * @return
+ */
+ public static RTime getRDate(String s) throws RulesException {
+ Date d = getDate(s);
+ if(d==null){
+ throw new RulesException("Bad Date Format","getRDate","Could not parse: '"+s+"' as a Date or Time value");
+ }
+ return new RTime(d);
+ }
+
+ public static RTime getRTime(Date t){
+ return new RTime(t);
+ }
+
+ @Override
+ public String toString(){
+ SimpleDateFormat f = new SimpleDateFormat("MM/dd/yyyy hh:mm aa");
+ return f.format(time);
+ }
+
+ public String stringValue() {
+ return time.toString();
+ }
+
+ public int getYear(DTState state) throws RulesException{
+ if(time==null){
+ throw new RulesException("Undefined", "getYear()", "No valid date available");
+ }
+ state.calendar.setTime(time);
+ return state.calendar.get(Calendar.YEAR);
+ }
+ /**
+ * Returns self.
+ */
+ @Override
+ public RTime rTimeValue() throws RulesException {
+ return this;
+ }
+
+ /**
+ * Returns the time's date object.
+ */
+ @Override
+ public Date timeValue() throws RulesException {
+ return time;
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ @Override
+ public int compare(IRObject irObject) throws RulesException {
+ return this.time.compareTo(irObject.timeValue());
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return time.equals(o.timeValue());
+ }
+
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.Date;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+
+/**
+ * @author paul snow
+ *
+ * An XmlValue object represents a node in the XML input stream that
+ * supplied data to the Rules Engine. It provides a way to update
+ * and modify that XML based on rules defined in Decision Tables.
+ *
+ */
+public class RXmlValue extends ARObject {
+ XMLTag tag;
+ DTState state;
+ int id;
+
+ public RXmlValue(DTState state, XMLTag tag){
+ this.tag = tag;
+ id = state.getSession().getUniqueID();
+ }
+
+ /**
+ * Sets the value of an Attribute on the tag for this RXmlValue.
+ *
+ * @param attribute
+ * @param value
+ */
+ public void setAttribute(String attribute, String value){
+ tag.getAttribs().put(attribute, value);
+ }
+
+ /**
+ * Gets the value of an Attribute on the tag for this RXmlValue.
+ * Returns a null if the Attribute isn't defined on this tag.
+ * @param attribute
+ * @param value
+ */
+ public String getAttribute(String attribute){
+ if(!tag.getAttribs().containsKey(attribute)){
+ return null;
+ }
+ return tag.getAttribs().get(attribute).toString();
+ }
+
+ /**
+ * The following are all the accessors that are suppored
+ * for working with RXmlValue objects
+ */
+
+ /**
+ * The string value of an XMLTag is its body value
+ */
+ public String stringValue() {
+ return tag.getBody().toString();
+ }
+ public int type() {
+ return iXmlValue;
+ }
+
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ ArrayList<IRObject> a = new ArrayList<IRObject>();
+ if(tag.getTags().size()>0){
+ for(XMLTag t : tag.getTags()){
+ a.add(new RXmlValue(state,t));
+ }
+ }
+ return a;
+ }
+
+ @Override
+ public boolean booleanValue() throws RulesException {
+ return RBoolean.booleanValue(tag.getBody().toString());
+ }
+
+ @Override
+ public double doubleValue() throws RulesException {
+ return RDouble.getDoubleValue(tag.getBody().toString());
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return rStringValue().equals(o);
+ }
+
+ @Override
+ public int intValue() throws RulesException {
+ return (int)RInteger.getIntegerValue(tag.getBody().toString());
+ }
+
+
+ @Override
+ public long longValue() throws RulesException {
+ return RInteger.getIntegerValue(tag.getBody().toString());
+ }
+
+ @Override
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(longValue());
+ }
+
+ @Override
+ public RName rNameValue() throws RulesException {
+ return RName.getRName(stringValue(),false);
+ }
+
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+ public RTime rTimeValue() throws RulesException {
+ return RTime.getRTime(timeValue());
+ }
+
+ public Date timeValue() throws RulesException {
+ return RTime.getDate(tag.getBody().toString());
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rXmlValue()
+ */
+ @Override
+ public RXmlValue rXmlValue() throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#xmlTagValue()
+ */
+ @Override
+ public XMLTag xmlTagValue() throws RulesException {
+ return tag;
+ }
+
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+import java.util.Date;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class SimpleTokenizer {
+ private StringBuffer buff;
+ private int index;
+
+ static RTime t;
+ static {
+ try{
+ t = RTime.getRDate("12/31/2000");
+ }catch(RulesException e){}
+ }
+
+ public SimpleTokenizer (String input){
+ buff = new StringBuffer(input);
+ index = 0;
+ }
+ /**
+ * Tosses whitespace (anything less than 32). Returns true if any
+ * whitespace was found, and false otherwise. The end of string counts
+ * as whitespace.
+ * @return
+ */
+ private boolean tossWhite(){
+ if(index>=buff.length())return true;
+ char c = buff.charAt(index);
+ if(c>' ')return false;
+ while(hasChar() && buff.charAt(index)<=32)index++;
+ return true;
+ }
+ /**
+ * Returns true if any characters remain in the buffer.
+ * @return
+ */
+ private boolean hasChar(){
+ return index < buff.length();
+ }
+ /**
+ * Returns the next character in the buffer. Returns a space on end
+ * of string.
+ * @return
+ */
+ char getChar(){
+ if(index>=buff.length())return ' ';
+ char c = buff.charAt(index++);
+ return c;
+ }
+
+ /**
+ * Parses out a token at a time, and returns null on the end of input.
+ * @return
+ */
+ public Token nextToken() throws RulesException {
+ tossWhite();
+ if(!hasChar())return null;
+ int start = index;
+ char c = getChar();
+ switch(c){
+ case '"': case '\'': return parseString(c);
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '(':
+ case ')': return new Token(c);
+ }
+ while(getChar()>32);
+ return buildToken(buff.substring(start, index));
+ }
+ /**
+ * We assume the first quote has been
+ * parsed already. We parse till we find the delim char.
+ * We then build
+ * @param delim
+ * @return
+ */
+ Token parseString(char delim){
+ char c = ' ';
+ int start = index;
+ while(hasChar()){
+ if(getChar()==delim){
+ if(start>index-1){
+ return new Token("",Token.Type.STRING);
+ }
+ return new Token(buff.substring(start,index-1),Token.Type.STRING);
+ }
+ }
+ throw new RuntimeException("String is missing the closing quote: ("+c+")");
+ }
+ /**
+ * We attempt to convert v to a long.
+ * Then we attempt to convert v to a float.
+ * Then we try parsing it as a date.
+ * Then we build a name.
+ * @param v
+ * @return
+ */
+ Token buildToken(String v){
+ try {
+ Long longValue = Long.parseLong(v.replaceAll(",", ""));
+ return new Token(longValue);
+ } catch (NumberFormatException e) {}
+ try {
+ Double doubleValue = Double.parseDouble(v.replaceAll(",",""));
+ return new Token(doubleValue);
+ } catch (NumberFormatException e) {}
+ Date t = RTime.getDate(v);
+ if(t!=null){
+ return new Token(RTime.getRTime(t));
+ }
+
+ return new Token(RName.getRName(v));
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+class Token {
+
+ public enum Type {
+ INT,
+ REAL,
+ DATE,
+ LPAREN,
+ RPAREN,
+ LCURLY,
+ RCURLY,
+ LSQUARE,
+ RSQUARE,
+ NAME,
+ STRING,
+ };
+
+ Type type;
+ String strValue;
+ Long longValue;
+ Double doubleValue;
+ RTime datevalue;
+ RName nameValue;
+
+ public Type getType(){
+ return type;
+ }
+
+ Token(char c) {
+ strValue = String.valueOf(c);
+ switch(c){
+ case '[': type = Type.LSQUARE; break;
+ case ']': type = Type.RSQUARE; break;
+ case '{': type = Type.LCURLY; break;
+ case '}': type = Type.RCURLY; break;
+ case '(': type = Type.LPAREN; break;
+ case ')': type = Type.RPAREN; break;
+ default :
+ nameValue = RName.getRName(String.valueOf(c));
+ type = Type.NAME;
+ }
+ }
+
+ Object getValue(){
+ if(type == Type.INT)return longValue;
+ if(type == Type.REAL)return doubleValue;
+ if(type == Type.STRING)return strValue;
+ if(type == Type.LSQUARE)return "[";
+ if(type == Type.RSQUARE)return "]";
+ if(type == Type.LCURLY)return "{";
+ if(type == Type.RCURLY)return "}";
+ if(type == Type.LPAREN)return "(";
+ if(type == Type.RPAREN)return ")";
+ if(type == Type.NAME)return "/"+nameValue.stringValue();
+ return "?";
+ }
+
+ Token(RTime t){
+ datevalue = t;
+ type = Type.DATE;
+ }
+
+ Token(String s,Type t){
+ strValue = s;
+ type = t;
+ }
+ Token(long v){
+ longValue = v;
+ type = Type.INT;
+ }
+
+ Token(Double v){
+ doubleValue = v;
+ type = Type.REAL;
+ }
+
+ Token(RName n){
+ nameValue = n;
+ type = Type.NAME;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+public abstract class ARObject implements IRObject {
+
+ /**
+ * No point in implementing this here. Every Object that has
+ * an array representation needs to implement it themselves.
+ */
+ public RArray rArrayValue() throws RulesException {
+ throw new RulesException("Conversion Error","ARObject","No Time value exists for "+this.stringValue());
+ }
+
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ public RTime rTimeValue() throws RulesException {
+ return RTime.getRTime(timeValue());
+ }
+
+ public Date timeValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Time value exists for: "+this);
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(this);
+ }
+
+ public IRObject getExecutable(){
+ return this;
+ }
+
+ public IRObject getNonExecutable() {
+ return this;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return o==this;
+ }
+
+ public boolean isExecutable() {
+ return false;
+ }
+
+ public String postFix() {
+ return toString();
+ }
+
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+ public IRObject rclone() {
+ return (IRObject) this;
+ }
+
+ /** Conversion Methods. Default is to throw a RulesException **/
+
+ public int intValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Array value exists for "+this);
+ }
+
+ public boolean booleanValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Boolean value exists for "+this);
+ }
+
+ public double doubleValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No double value exists for "+this);
+ }
+
+ public IREntity rEntityValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Entity value exists for "+this);
+ }
+ @SuppressWarnings({"unchecked"})
+ public HashMap hashMapValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public long longValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Long value exists for "+this);
+ }
+
+ public RName rNameValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public RInteger rIntegerValue() throws RulesException {
+ throw new RulesException("Undefined","Conversion Error","No Integer value exists for "+this);
+ }
+
+ public int compare(IRObject irObject) throws RulesException {
+ throw new RulesException("Undefined","No Supported","Compared Not suppoted for this object"+this);
+ }
+
+ /**
+ * By default, objects clone themselves by simply returnning themselves.
+ * This is because the clone of a number or boolean etc. is itself.
+ */
+ public IRObject clone(IRSession s) throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#rTableValue()
+ */
+ public RTable rTableValue() throws RulesException {
+ throw new RulesException("Undefined","Not Supported","No Table value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#tableValue()
+ */
+ @SuppressWarnings({"unchecked"})
+ public HashMap tableValue() throws RulesException {
+ throw new RulesException("Undefined","Not Supported","No Table value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#rXmlValue()
+ */
+ public RXmlValue rXmlValue() throws RulesException {
+ throw new RulesException("Conversion Error","","No XmlValue value exists for "+this);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.IRObject#xmlTagValue()
+ */
+ public XMLTag xmlTagValue() throws RulesException {
+ throw new RulesException("Conversion Error","","No XmlValue value exists for "+this);
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+@SuppressWarnings({"unchecked"})
+public interface IRObject {
+
+ public IRObject clone(IRSession s) throws RulesException;
+
+ // *************** NOTE !!!!!!
+ // You can't put static methods on an interface. So the String to integer conversion
+ // for types is a static method on the RSession class.
+
+ final String rBoolean = "boolean",
+ rString = "string",
+ rInteger = "integer",
+ rFloat = "float",
+ rEntity = "entity",
+ rName = "name",
+ rArray = "array",
+ rDecisiontable = "decisiontable",
+ rNull = "null",
+ rMark = "mark",
+ rOperator = "operator",
+ rTime = "time",
+ rTable = "table",
+ rXmlValue = "xmlvalue";
+
+ final String types[] = { rBoolean, rString, rInteger, rFloat,
+ rEntity, rName, rArray, rDecisiontable,
+ rNull, rMark, rOperator, rTime,
+ rTable, rXmlValue};
+
+ final int iBoolean = 0,
+ iString = 1,
+ iInteger = 2,
+ iDouble = 3,
+ iEntity = 4,
+ iName = 5,
+ iArray = 6,
+ iDecisiontable = 7,
+ iNull = 8,
+ iMark = 9,
+ iOperator = 10,
+ iTime = 11,
+ iTable = 12,
+ iXmlValue = 13;
+
+
+ void execute(DTState state) throws RulesException;
+
+ public IRObject getExecutable();
+
+ public IRObject getNonExecutable();
+
+ public boolean equals(IRObject o) throws RulesException;
+
+ public boolean isExecutable();
+
+ /**
+ * By default, the toString() method for most Objects should provide
+ * a representation of the object that can be used as the postFix value.
+ * The stringValue should provide simply the data for the object. Thus
+ * If I want to append the a String and a Date to create a new string,
+ * I should append the results from their stringValue() implementation.
+ * <br><br>
+ * If I needed the postfix (and thus the quotes and maybe other ) then
+ * call postFix(). But if the postFix is going to match either stringValue()
+ * or toString, it is going to match toString().
+ * <br><br>
+ * @return
+ */
+ public String stringValue();
+ public RString rStringValue();
+
+ public String postFix();
+
+ public int type();
+
+ public IRObject rclone();
+
+ public XMLTag xmlTagValue() throws RulesException;
+ public long longValue () throws RulesException;
+ public int intValue () throws RulesException;
+ public RInteger rIntegerValue() throws RulesException;
+ public double doubleValue () throws RulesException;
+ public RDouble rDoubleValue() throws RulesException;
+ public ArrayList<IRObject> arrayValue () throws RulesException;
+ public RArray rArrayValue() throws RulesException;
+ public boolean booleanValue () throws RulesException;
+ public RBoolean rBooleanValue() throws RulesException;
+ public HashMap hashMapValue () throws RulesException;
+ public RXmlValue rXmlValue () throws RulesException;
+ public IREntity rEntityValue () throws RulesException;
+ public RName rNameValue () throws RulesException;
+ public RTime rTimeValue () throws RulesException;
+ public Date timeValue () throws RulesException;
+ public RTable rTableValue() throws RulesException;
+ public HashMap tableValue() throws RulesException;
+ public int compare(IRObject irObject) throws RulesException;
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+/**
+ * Immplements Arrays for Decision Tables. Because we can't tag references,
+ * we do the same trick here that we do for RNames, i.e. we create an executable
+ * and a non-executable version of each array. However, we only create one
+ * ArrayList.
+ * <br><br>
+ * If dups is true, we allow duplicate references in the array. Sometimes it
+ * is pleasent to have an array whose values are all unique. In that case, create
+ * an array with dups set to false. <br>
+ * <br>
+ * @author ps24876
+ *
+ */
+@SuppressWarnings("unchecked")
+public class RArray extends ARObject implements Collection<IRObject> {
+ final ArrayList<IRObject> array;
+ final RArray pair;
+ final boolean executable;
+ final boolean dups;
+ final int id;
+
+
+
+
+
+ /* (non-Javadoc)
+ * @see java.util.Collection#addAll(java.util.Collection)
+ */
+ public boolean addAll(Collection<? extends IRObject> arg0) {
+ return array.addAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#clear()
+ */
+ public void clear() {
+ array.clear();
+
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#contains(java.lang.Object)
+ */
+ public boolean contains(Object arg0) {
+ if(arg0 instanceof IRObject) {
+ for(IRObject o: array){
+ try{ // Really this isn't possible.
+ if (o.equals((IRObject)arg0))return true;
+ }catch(RulesException e){}
+ }
+ }
+ return false;
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#containsAll(java.util.Collection)
+ */
+ public boolean containsAll(Collection<?> arg0) {
+ return array.containsAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#isEmpty()
+ */
+ public boolean isEmpty() {
+ return array.isEmpty();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#iterator()
+ */
+ public Iterator<IRObject> iterator() {
+ return array.iterator();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#remove(java.lang.Object)
+ */
+ public boolean remove(Object arg0) {
+ return array.remove(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(Collection<?> arg0) {
+ return array.removeAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(Collection<?> arg0) {
+ return retainAll(arg0);
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#toArray()
+ */
+ public Object[] toArray() {
+ return array.toArray();
+ }
+ /* (non-Javadoc)
+ * @see java.util.Collection#toArray(T[])
+ */
+ public <T> T[] toArray(T[] arg0) {
+ return array.toArray( arg0);
+ }
+ /**
+ * Returns the id of this array. Used by debuggers to analyze trace files
+ * @return ID of the array
+ */
+ public int getID(){ return id; }
+ /**
+ * Constructor to create the core structure for an RArray.
+ * @param bogus
+ * @param exectuable
+ */
+ protected RArray(int id, boolean duplicates, ArrayList thearray, RArray otherpair, boolean executable){
+ this.id = id;
+ this.array = thearray;
+ this.executable = executable;
+ this.pair = otherpair;
+ this.dups = duplicates;
+ }
+
+ public RArray(int id, boolean duplicates, boolean executable){
+ this.id = id;
+ array = new ArrayList();
+ this.executable = executable;
+ dups = duplicates;
+ pair = new RArray(id,dups, array, this, !executable);
+ }
+
+ public RArray(int id, boolean duplicates, ArrayList thearray, boolean executable){
+ this.id = id;
+ this.array = thearray;
+ this.executable = executable;
+ dups = duplicates;
+ pair = new RArray(id,dups,thearray,this,!executable);
+ }
+
+ public Iterator getIterator(){ return array.iterator(); }
+
+ public int type() {
+ return iArray;
+ }
+ public boolean add(IRObject v){
+ if(!dups && array.contains(v))return false;
+ return array.add(v);
+ }
+ public void add(int index,IRObject v){
+ array.add(index,v);
+ }
+ public void delete(int index){
+ array.remove(index);
+ }
+ public void remove(IRObject v){
+ array.remove(v);
+ }
+ public IRObject get(int index) throws RulesException{
+ if(index<0 || index>= array.size()){
+ throw new RulesException("Undefined","RArray","Index out of bounds");
+ }
+ return (IRObject) array.get(index);
+ }
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ return array;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ if(o.type() != iArray) return false;
+ return ((RArray)o).array == array;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0; // A debugging aid.
+ for(IRObject obj : this){
+ if(obj.type()==iArray || !obj.isExecutable()){
+ state.datapush(obj);
+ }else{
+ try{
+ obj.execute(state);
+ }catch(RulesException e){
+ e.setPostfix(this.postFix());
+ throw e;
+ }
+ }
+ cnt++;
+ }
+
+ }
+
+ public IRObject getExecutable() {
+ if(executable)return this;
+ return pair;
+ }
+
+ public IRObject getNonExecutable() {
+ if(!executable)return this;
+ return pair;
+ }
+
+ public boolean isExecutable() {
+ return executable;
+ }
+
+ public String postFix() {
+ StringBuffer result = new StringBuffer();
+ result.append(executable?"{":"[");
+ for (IRObject obj : array){
+ result.append(obj.postFix());
+ result.append(" ");
+ }
+ result.append(executable?"}":"]");
+ return result.toString();
+ }
+
+ public String stringValue() {
+ StringBuffer result = new StringBuffer();
+ result.append(isExecutable()?"{ ":"[ ");
+ for(IRObject obj : array){
+ result.append(obj.stringValue());
+ result.append(" ");
+ }
+ result.append(isExecutable()?"}":"]");
+ return result.toString();
+ }
+ public String toString() {
+ return stringValue();
+ }
+
+ /**
+ * returns the clone of this object
+ */
+ public IRObject clone(IRSession session) {
+ ArrayList<IRObject> newArray = new ArrayList<IRObject>();
+ newArray.addAll(array);
+ return new RArray(session.getUniqueID(), dups, newArray, executable);
+ }
+
+ public RArray rArrayValue() throws RulesException {
+ return this;
+ }
+
+ /*
+ * Returns the size of the array.
+ */
+ public int size()
+ {
+ return this.array.size();
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class RBoolean extends ARObject {
+
+ /**
+ * Provides all the supported conversions of a String to a boolean value.
+ * @param value
+ * @return
+ * @throws RulesException
+ */
+ public static boolean booleanValue(String value)throws RulesException {
+ String v = value.trim();
+ if(v.equalsIgnoreCase("true") ||
+ v.equalsIgnoreCase("y") ||
+ v.equalsIgnoreCase("t") ||
+ v.equalsIgnoreCase("yes")){
+ return true;
+ }else if(v.equalsIgnoreCase("false") ||
+ v.equalsIgnoreCase("n") ||
+ v.equalsIgnoreCase("f") ||
+ v.equalsIgnoreCase("no")){
+ return false;
+ }
+ throw new RulesException("typecheck","String Conversion to Boolean","No boolean value for this string: "+value);
+ }
+ /**
+ * Really, there is no reason for more that two instances of Boolean objects
+ * in the Rules Engine world.
+ */
+ private static RBoolean trueValue = new RBoolean(true);
+ private static RBoolean falseValue = new RBoolean(false);
+ /**
+ * The value of this boolean object.
+ */
+ public final boolean value;
+ /**
+ * A private constructor to avoid any creation of boolean values besides
+ * the two (true and false)
+ * @param _value
+ */
+ private RBoolean(boolean _value){
+ value = _value;
+ }
+ /**
+ * Report that this is indeed a boolean object.
+ */
+ public int type() {
+ return iBoolean;
+ }
+ /**
+ * Return the proper boolean object for the given boolean value.
+ * @param value
+ * @return
+ */
+ public static RBoolean getRBoolean(boolean value){
+ if(value)return trueValue;
+ return falseValue;
+ }
+
+ /**
+ * Attempt to convert the string, and return the proper boolean object.
+ * @param value
+ * @return
+ * @throws RulesException
+ */
+ public static RBoolean getRBoolean(String value) throws RulesException {
+ return getRBoolean(booleanValue(value));
+ }
+ /**
+ * Return my value.
+ */
+ public boolean booleanValue() throws RulesException {
+ return value;
+ }
+ /**
+ * We *COULD* simply do an object equality test...
+ */
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.booleanValue();
+ }
+ /**
+ * Return the string value for this boolean.
+ */
+ public String stringValue() {
+ if(value)return "true";
+ return "false";
+ }
+ /**
+ * Return the string value for this boolean
+ */
+ public String toString() {
+ return stringValue();
+ }
+ /**
+ * The postfix is nothing more than the string value for this boolean.
+ */
+ public String postFix() {
+ return stringValue();
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+/**
+ * @author Paul Snow
+ *
+ */
+public class RDouble extends ARObject {
+ final double value;
+
+ static RDouble mone = new RDouble(-1.0);
+ static RDouble zero = new RDouble(0.0);
+ static RDouble one = new RDouble(1.0);
+
+ private RDouble(double v){
+ value = v;
+ }
+
+ static public double getDoubleValue(String s) throws RulesException {
+ if(s==null || s.trim().length()==0){
+ return 0.0D;
+ }
+ try {
+ double v = Double.parseDouble(s);
+ return v;
+ } catch (NumberFormatException e) {
+ throw new RulesException("Conversion Error","RDouble.getDoubleValue()","Could not covert the string '"+s+"' to a double: "+e.getMessage());
+ }
+ }
+ /**
+ * Parses the given string, and returns an RDouble Object
+ * @param s String to parse
+ * @return RDouble value for the given string
+ * @throws RulesException
+ */
+ static public RDouble getRDoubleValue(String s) throws RulesException {
+ return getRDoubleValue(getDoubleValue(s));
+ }
+
+
+
+ static public RDouble getRDoubleValue(double v){
+ if(v == -1.0) return mone;
+ if(v == 0.0) return zero;
+ if(v == 1.0) return one;
+
+ return new RDouble(v);
+ }
+
+ static public RDouble getRDoubleValue(int v){
+ return getRDoubleValue((double) v);
+ }
+
+ static public RDouble getRDoubleValue(long v){
+ return getRDoubleValue((double) v);
+ }
+
+ public RDouble rDoubleValue() {
+ return this;
+ }
+
+ public double doubleValue() {
+ return value;
+ }
+
+ public int intValue() {
+ return (int) value;
+ }
+
+
+ public long longValue() {
+ return (long) value;
+ }
+
+ public RInteger rIntegerValue() {
+ return RInteger.getRIntegerValue((long)value);
+ }
+
+ /**
+ * Returns the type for this object.
+ */
+ public int type() {
+ return iDouble;
+ }
+
+ public String stringValue() {
+ return Double.toString(value);
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ return (this.value==irObject.doubleValue())?0:((this.value<irObject.doubleValue())?-1:0);
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.doubleValue();
+ }
+
+ public String toString() {
+ return Double.toString(value);
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+/**
+ * Integers are longs.
+ * @author ps24876
+ *
+ */
+public class RInteger extends ARObject {
+ final long value;
+
+ static RInteger mone = new RInteger(-1);
+ static RInteger zero = new RInteger( 0);
+ static RInteger one = new RInteger( 1);
+
+ private RInteger(long i){
+ value = i;
+ }
+
+ /**
+ * Parses the given string, and returns an RInteger Object
+ * @param s String to parse
+ * @return RInteger value for the given string
+ * @throws RulesException
+ */
+ static public long getIntegerValue(String s) throws RulesException {
+ if(s==null || (s = s.trim()).length()==0 || s.equalsIgnoreCase("null")){
+ return 0L;
+ }
+ try {
+ long v = Long.parseLong(s);
+ return v;
+ } catch (NumberFormatException e) {
+ throw new RulesException("Conversion Error","RInteger.getIntegerValue()","Could not covert the string '"+s+"' to an integer: "+e.getMessage());
+ }
+ }
+
+ static public RInteger getRIntegerValue(String s) throws RulesException {
+ return getRIntegerValue(getIntegerValue(s));
+ }
+
+ static public RInteger getRIntegerValue(long i){
+
+ if(i == -1) return mone;
+ if(i == 0) return zero;
+ if(i == 1) return one;
+ return new RInteger(i);
+ }
+
+ static public RInteger getRIntegerValue(double i){
+ return getRIntegerValue((long) i);
+ }
+
+ static public RInteger getRIntegerValue(int i){
+ return getRIntegerValue((long) i);
+ }
+
+ public int type() {
+ return iInteger;
+ }
+
+ public double doubleValue() {
+ return (double)value;
+ }
+
+ public int intValue() {
+ return (int)value;
+ }
+
+ public long longValue() throws RulesException {
+ return (long) value;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return value == o.intValue();
+ }
+
+ public String postFix() {
+ return stringValue();
+ }
+
+ public RInteger rIntegerValue() throws RulesException {
+ return this;
+ }
+
+ public String stringValue() {
+ String str = Long.toString(value);
+ return str;
+ }
+
+ public String toString(){
+ return stringValue();
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ return (this.value==irObject.intValue())?0:((this.value<irObject.intValue())?-1:0);
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+/**
+ * A Mark object is used as a place holder on the data stack.
+ * arraytomark then pops all elements upto but not including the
+ * mark, and puts them into an array.
+ *
+ * @author paul snow
+ *
+ */
+public class RMark extends ARObject {
+
+ static RMark themark = new RMark();
+
+ private RMark(){}
+
+ static public RMark getMark() { return themark; }
+
+ public String stringValue() {
+ return "Mark";
+ }
+
+ public int type() {
+ return iMark;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+
+import java.util.HashMap;
+import java.util.regex.Pattern;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings({"unchecked"})
+public class RName extends ARObject {
+
+ final RName entity;
+ final String name;
+ final boolean executable;
+ final int hashcode;
+ final RName partner; // RNames are created in pairs, executable and non-executable.
+
+ static HashMap names = new HashMap();
+
+ /**
+ * This constructor should only be called by the other RName constructor.
+ * It is used to build its partner. RNames are always created in pairs,
+ * one executable and one non-executable.
+ *
+ * @param _name
+ * @param _executable
+ * @param _hashcode
+ * @param _partner
+ */
+ private RName(RName _entity, String _name, boolean _executable, int _hashcode, RName _partner){
+ entity = _entity;
+ name = _name;
+ executable = _executable;
+ hashcode = _hashcode;
+ partner = _partner;
+ }
+ /**
+ * This constructor should only be called by the getRName method. This
+ * constructor always creates two RNames, the one requested and its partner.
+ *
+ * @param _name
+ * @param _executable
+ * @param _hashcode
+ */
+ private RName(RName _entity, String _name, boolean _executable, int _hashcode ){
+ entity = _entity;
+ name = _name;
+ executable = _executable;
+ hashcode = _hashcode;
+ partner = new RName(_entity, _name,!_executable,_hashcode,this);
+ }
+
+ static Pattern spaces = Pattern.compile(" ");
+ /**
+ * When you don't really care about the executable nature of the
+ * name, then use this accessor. We parse looking for the slash to
+ * determine a literal, so by default (i.e. no slash given), we
+ * return executable names. This constructor also pareses to handle
+ * the "dot" syntax.
+ * @exception RuntimeException is thrown if the Syntax is incorrect.
+ * @param _name String from which to create a name
+ * @return The Name object
+ */
+ static public RName getRName(String _name){
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = spaces.matcher(_name.trim()).replaceAll("_");
+ boolean executable = !(_name.indexOf('/')==0);
+ if(!executable){
+ _name = _name.substring(1); // Remove the slash.
+ }
+ int dot = _name.indexOf('.');
+
+ if(dot>=0){
+ String entity = _name.substring(0,dot);
+ if(dot == 0 || dot+1 == _name.length() || _name.indexOf(dot+1,'.')>=0){
+ throw new RuntimeException("Invalid Name Syntax: ("+_name+")");
+ }
+ String name = _name.substring(dot+1);
+ return getRName(RName.getRName(entity),name,executable);
+ }
+ return getRName(null, _name, executable);
+ }
+ /**
+ * We cache the creation of RNames so as to not create new copies
+ * of RNames that we don't have to create. (RNames are reusable)
+ * <br><br>
+ * Thus one calls one of the getRName functions, and one cannot call our
+ * constructors directly.
+ * <br><br>
+ * Returns a null if a RName cannot be found/created.
+ *
+ * @param _name
+ * @return
+ */
+ static public RName getRName(String _name, boolean _executable) {
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = _name.trim().replaceAll(" ","_");
+ return getRName(null,_name,_executable);
+ }
+
+ static Pattern space = Pattern.compile(" ");
+ /**
+ * We cache the creation of RNames so as to not create new copies
+ * of RNames that we don't have to create. (RNames are reusable)
+ * <br><br>
+ * Thus one calls one of the getRName functions, and one cannot call our
+ * constructors directly.
+ *
+ * @param _name
+ * @return
+ */
+ static public RName getRName(RName _entity, String _name, boolean _executable) {
+ // Fix the name; trim and then replace internal spaces with '_'.
+ _name = space.matcher(_name).replaceAll("_");
+ // If we already have the RName, we are done.
+ String lname = _name.toLowerCase();
+ String cname = _name;
+ if(_entity!=null){
+ cname = _entity.stringValue().toLowerCase()+"."+lname;
+ }
+ RName rn = (RName) names.get(cname);
+ if(rn == null ) {
+ rn = new RName(_entity ,_name,_executable, lname.hashCode());
+ names.put(cname,rn);
+ }
+ if(_executable) return (RName) rn.getExecutable();
+ return (RName) rn.getNonExecutable();
+ }
+ /**
+ * Returns the entity component of the name, which is null if none
+ * was specfied when the name was created.
+ *
+ * @return
+ */
+ public RName getEntityName(){
+ return entity;
+ }
+
+ public boolean equals(Object arg0) {
+ if(arg0.getClass()!=RName.class)return false;
+ boolean f = name.equalsIgnoreCase(((RName)arg0).name);
+ return f;
+ }
+
+ public int hashCode() {
+ return hashcode;
+ }
+
+ /**
+ * Compare this RName with another Rules Engine Object. RNames
+ * are only equal to other RNames.
+ */
+ public boolean equals(IRObject o) {
+ if(o.type()!=IRObject.iName)return false;
+ return equals((Object)o);
+ }
+ static int cnt= 0;
+ /**
+ * The execution of an RName looks up that RName in the Entity
+ * Stack. If the object found there is an Array, it is pushed
+ * to the Entity Stack. If the object found there is not an
+ * array, and it is not executable, then it is pushed. Otherwise
+ * (not an array, and executable) the object is executed.
+ */
+ public void execute(DTState state) throws RulesException {
+ cnt++;
+ IRObject o = state.find(this); // Does a lookup of the name on the Entity Stack
+ if(o==null){
+ throw new RulesException("Undefined","RName","The Name '"+name+"' was not defined by any Entity on the Entity Stack");
+ }
+ if(o.isExecutable()){
+ o.execute(state);
+ }else{
+ state.datapush(o);
+ }
+ }
+
+ public IRObject getExecutable() {
+ return executable ? this : partner ;
+ }
+
+ public IRObject getNonExecutable() {
+ return executable ? partner : this ;
+ }
+
+ public boolean isExecutable() {
+ return executable;
+ }
+
+
+ /**
+ * Returns the postfix version of the name.
+ */
+ public String postFix() {
+ return executable ? stringValue() : "/"+stringValue();
+ }
+
+ /**
+ * Returns the value of the name unadorned by the leading slash, even
+ * if the name is a literal.
+ */
+ public String stringValue() {
+ if(entity!=null){
+ return entity.stringValue()+"."+name;
+ }
+ return name;
+ }
+
+ /**
+ * Returns the nicest format for debugging, i.e. the Postfix version which
+ * has the slash if the name is a literal name.
+ */
+ public String toString(){
+ return postFix();
+ }
+
+ public int type() {
+ return iName;
+ }
+
+ @Override
+ public int compare(IRObject obj) throws RulesException {
+ String v = obj.stringValue();
+ return name.compareToIgnoreCase(v);
+ }
+ /**
+ * Returns myself
+ */
+ public RName rNameValue() throws RulesException {
+ return this;
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rStringValue()
+ */
+ @Override
+ public RString rStringValue() {
+ return RString.newRString(name);
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class RNull extends ARObject {
+
+ /**
+ * returns 0 if both are equal. -1 Otherwise. A Null is considered
+ * less than anything else. We do this just so sorting arrays were
+ * some values are null doesn't blow up.
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ if(irObject.equals(this))return 0; // A Null is equal to other nulls.
+ return -1; // A Null is less than anything else.
+ }
+
+
+
+ static RNull theNullObject = new RNull();
+ /**
+ * Nobody needs the constructor.
+ *
+ */
+ private RNull(){}
+
+ /**
+ * Returns the RNull object. There is no need for more than
+ * one of these objects.
+ * @return
+ */
+ public static RNull getRNull(){ return theNullObject; }
+
+ /**
+ * A Null is only equal to the null object
+ */
+ public boolean equals(IRObject o) {
+ return o.type()==iNull;
+ }
+
+ public String stringValue() {
+ return "null";
+ }
+
+ /**
+ * A Null is only equal to the null object, i.e. any
+ * Null object. They are all equal.
+ */
+ public boolean equals(Object arg0) {
+ return arg0.getClass().equals(this.getClass());
+ }
+
+ /**
+ * We override toString() to simply return "null".
+ * Because we do this, we override hashcode() as well.
+ */
+ public String toString() {
+ return "null";
+ }
+
+ public int hashCode() {
+ return 0;
+ }
+
+ public int type() {
+ return iNull;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.operators.ROperator;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RuleSet;
+
+/**
+ * @author Paul Snow
+ *
+ */
+public class RString extends ARObject {
+
+ RString pair;
+ String value;
+ boolean executable = false;
+
+ public double doubleValue() throws RulesException {
+ double d;
+ try {
+ d = Double.parseDouble(value);
+ } catch (NumberFormatException e) {
+ return super.doubleValue();
+ }
+ return d;
+ }
+
+ @Override
+ public int intValue() throws RulesException {
+ int i;
+ try {
+ i = Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return super.intValue();
+ }
+ return i;
+ }
+
+ @Override
+ public long longValue() throws RulesException {
+ long l;
+ try {
+ l = Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ return super.longValue();
+ }
+ return l;
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(longValue());
+ }
+
+ @Override
+ public RName rNameValue() throws RulesException {
+ return RName.getRName(value);
+ }
+
+ @Override
+ public RString rStringValue() {
+ return this;
+ }
+
+ private RString(String v,boolean executable,RString pair){
+ value = v;
+ this.pair = pair;
+ this.executable = executable;
+ }
+ /**
+ * Return a non Executable string
+ * @param v
+ * @return
+ */
+ static public RString newRString(String v){
+ return newRString(v,false);
+ }
+ /**
+ * Return an RString of the given executable nature.
+ * @param v
+ * @param executable
+ * @return
+ */
+ static public RString newRString(String v, boolean executable){
+ RString s = new RString(v,executable,null);
+ s.pair = new RString(v,!executable,s);
+ return s;
+ }
+
+ @Override
+ public IRObject getExecutable() {
+ if(isExecutable()){
+ return this;
+ }else{
+ return pair;
+ }
+ }
+
+ @Override
+ public IRObject getNonExecutable() {
+ if(isExecutable()){
+ return pair;
+ }else{
+ return this;
+ }
+ }
+
+ /**
+ * Returns a boolean value if the String can be reasonably
+ * interpreted as a boolean.
+ *
+ * @Override
+ */
+ public boolean booleanValue() throws RulesException {
+ return RBoolean.booleanValue(value);
+ }
+
+ /**
+ *
+ */
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ /**
+ * Returns String type.
+ * @see com.dtrules.interpreter.IRObject#type()
+ */
+ public int type() {
+ return iString;
+ }
+
+ /**
+ * Here we look to see if we can do a compile time lookup of
+ * an object. If we can't, we just return the object unchanged.
+ * But if we can, then we return the value we looked up. That
+ * saves many, many runtime lookups.
+ */
+ static IRObject lookup(RuleSet ruleset, RName name){
+ IRObject v = ROperator.getPrimitives().get(name); // First check if it is an operator
+ if(v==null){ // No? Then
+ try { // look for a decision table.
+ v = ruleset.getEntityFactory(null).getDecisionTable(name);
+ } catch (RulesException e) { } // Any error just means the name isn't
+ } // a decision table. Not a problem.
+ if(v==null || v.type()== iArray) return name;
+ return v;
+ }
+
+ /**
+ * Compiles the String and returns the executable Array Object
+ * that results. Unless the compilation fails, at which time
+ * we throw an exception.
+ *
+ * @return
+ * @throws RulesException
+ */
+ static public IRObject compile(RuleSet rs, String v, boolean executable) throws RulesException{
+
+ if(v==null)v=""; // Allow the compiling of null strings (we just don't do anything).
+
+ SimpleTokenizer tokenizer = new SimpleTokenizer(v);
+
+ IRObject result = compile(rs, tokenizer, v, executable, 0);
+ return result;
+ }
+
+ /**
+ * The compiles of Strings are recursive. When we see a [ or {,
+ * we recurse. Then on a close bracket ] or } we return the
+ * non-executable or executable array. The RString checks to make
+ * sure it is the right type, and throws an error if it isn't.
+ * The recursive depth is checked by compile();
+ * @param tokenizer
+ * @return
+ * @throws RulesException
+ */
+ static private IRObject compile(RuleSet ruleset, SimpleTokenizer tokenizer, String v, boolean executable, int depth) throws RulesException {
+ try{
+ RArray result = new RArray(0,true,executable);
+ Token token;
+ while((token=tokenizer.nextToken())!=null){
+ if(token.getType()== Token.Type.STRING) {
+ IRObject rs = RString.newRString(token.strValue);
+ result.add(rs);
+ }else if(token.getType()== Token.Type.LSQUARE) {
+ IRObject o = compile(ruleset,tokenizer, v, false, depth+1);
+ result.add(o);
+ }else if(token.getType()== Token.Type.RSQUARE) {
+ if(depth==0 || executable){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing <<"+v+">> \nThe token ']' was unexpected.");
+
+ }
+ return result;
+ }else if(token.getType()== Token.Type.LCURLY) {
+ IRObject o = compile(ruleset,tokenizer,v,true, depth+1);
+ result.add(o);
+ }else if(token.getType()== Token.Type.RCURLY) {
+ if(depth==0 || !executable){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing <<"+v+">> \nThe token '}' was unexpected.");
+
+ }
+ return result;
+ }else if(token.getType()== Token.Type.NAME) {
+ if(token.nameValue.isExecutable()){ // All executable names are checked for compile time lookup.
+ IRObject prim = lookup(ruleset,token.nameValue);
+ if(prim == null){ // If this name is not a primitive, then
+ result.add(token.nameValue); // then add the name as it is to the array.
+ }else{
+ result.add(prim); // Otherwise, compile the reference to the operator.
+ }
+ }else{
+ result.add(token.nameValue);
+ }
+
+ }else if (token.getType() == Token.Type.DATE){
+ result.add(token.datevalue);
+
+ }else if (token.getType()== Token.Type.INT) {
+ RInteger i = RInteger.getRIntegerValue(token.longValue);
+ result.add(i);
+ }else if (token.getType()== Token.Type.REAL) {
+ RDouble d = RDouble.getRDoubleValue(token.doubleValue);
+ result.add(d);
+ }
+ }
+ if(depth!=0){
+ throw new RulesException("Parsing Error",
+ "String Compile",
+ "\nError parsing << " + v + " >>\n missing a " + (executable ? "}" : "]"));
+
+ }
+ return (IRObject) result;
+ } catch (RuntimeException e) {
+ throw new RulesException("Undefined","String Compile","Error compiling string: '"+v+"'\n"+e);
+ }
+
+ }
+ /**
+ * Compiles this String and returns the object.
+ * @param executable
+ * @return
+ * @throws RulesException
+ */
+ public IRObject compile(RuleSet ruleset, boolean executable) throws RulesException{
+ return compile(ruleset, value,executable);
+ }
+
+ @Override
+ public boolean isExecutable() {
+ return executable;
+ }
+
+ public void execute(DTState state) throws RulesException {
+ if(isExecutable()){
+ IRObject o = compile(state.getSession().getRuleSet(),value,true);
+ o.execute(state);
+ }else{
+ state.datapush(this);
+ }
+ }
+
+ public String stringValue() {
+ return value;
+ }
+ public String toString(){
+ return "\""+value+"\"";
+ }
+
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ public int compare(IRObject irObject) throws RulesException {
+ int f = this.value.compareTo(irObject.stringValue());
+ if(f<0)return -1;
+ if(f>0)return 1;
+ return f;
+ }
+
+ public boolean equals(IRObject o) throws RulesException {
+ return value.equals(o.stringValue());
+ }
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.session.RuleSet;
+
+public class RTable extends ARObject {
+ private final int resultType;
+ private final int id;
+ private RName tablename;
+ private RString description;
+
+ private final HashMap<RName, IRObject> table = new HashMap<RName,IRObject>();
+
+ /**
+ * Get the description of this table
+ * @return the description
+ */
+ public RString getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the description of this table
+ */
+ public void setDescription(RString description){
+ this.description = description;
+ }
+
+ /**
+ * Return the Unique ID for this table.
+ * @return the id
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Return the type of result found in this table.
+ * @return the resultType
+ */
+ public int getResultType() {
+ return resultType;
+ }
+
+ /**
+ * Return the HashMap for primary dimension of this table
+ * @return the table
+ */
+ public HashMap<RName, IRObject> getTable() {
+ return table;
+ }
+
+ /**
+ * @return the tablename
+ */
+ public RName getTablename() {
+ return tablename;
+ }
+
+ public boolean containsKey (RName key){
+ return table.containsKey(key);
+ }
+
+ public boolean containsValue (IRObject value){
+ return table.containsValue(value);
+ }
+
+ private RTable(EntityFactory ef,
+ RName tablename,
+ String description,
+ int resultType) throws RulesException {
+ this.tablename = tablename;
+ this.resultType = resultType;
+ this.id = ef.getUniqueID();
+ this.description = RString.newRString(description);
+ }
+ /**
+ * Factory method for creating an RTable
+ * @param state
+ * @param tablename
+ * @param description
+ * @param resultType
+ * @return
+ */
+ static public RTable newRTable(EntityFactory ef, RName tablename, String description, int resultType) throws RulesException{
+ return new RTable(ef,tablename,description,resultType);
+ }
+ /**
+ * This routine assumes that the string defines an Array of the
+ * form:
+ * {
+ * { key1 value1 }
+ * { key2 value2 }
+ * ...
+ * { keyn valuen }
+ * }
+ * This routine compiles the given string, then calls the
+ * set routine that takes an array of key value pairs and sets
+ * them into the RTable
+ *
+ * @param values
+ */
+ public void setValues(RuleSet rs, String values)throws RulesException{
+ RArray array = RString.compile(rs, values, false).rArrayValue();
+ setValues(array);
+ }
+ /**
+ * This routine assumes that an Array of the
+ * form:
+ * {
+ * { key1 value1 }
+ * { key2 value2 }
+ * ...
+ * { keyn valuen }
+ * }
+ * This routine takes an array of key value pairs and sets
+ * them into the RTable
+ *
+ * @param values
+ */
+ public void setValues(RArray values) throws RulesException{
+ for(IRObject irpair : values){
+ RArray pair = irpair.rArrayValue();
+ if(pair.size()!=2){
+ throw new RulesException(
+ "Invalid_Table_Value",
+ "RTable.setValues",
+ "setValues expected an array of arrays giving pairs of values to assert into the Table");
+ }
+ RName key = pair.get(0).rNameValue();
+ IRObject value = pair.get(1);
+ setValue(key, value);
+ }
+ }
+
+ /**
+ * Set a value with the given set of keys into the given table.
+ * @param keys
+ * @param value
+ * @throws RulesException
+ */
+ @SuppressWarnings("unchecked")
+ public void setValue(DTState state, RName[]keys, IRObject value) throws RulesException{
+ IRObject v = this;
+ for(int i=0;i<keys.length-1; i++){
+ if(v.type()!=iTable){
+ throw new RulesException("OutOfBounds","RTable","Invalid Number of Keys used with Table "+this.stringValue());
+ }
+ RTable table = v.rTableValue();
+ IRObject next = table.getValue(keys[i]);
+ if(next == null){
+ next = newRTable(state.getSession().getEntityFactory(),this.tablename,this.description.stringValue(),this.resultType);
+ table.setValue(keys[i], next);
+ }
+ v = (IRObject) next;
+ }
+ v.rTableValue().setValue(keys[keys.length-1], value);
+ }
+
+ public void setValue(RName key, IRObject value) throws RulesException{
+ table.put(key, value);
+ }
+
+ public IRObject getValue(RName key) throws RulesException {
+ IRObject v = this.table.get(key);
+ if(v==null)return RNull.getRNull();
+ return v;
+ }
+
+ public IRObject getValue(RName[]keys) throws RulesException {
+ IRObject v = this;
+ for(int i=0;i<keys.length; i++){
+ if(v.type()!=iTable){
+ throw new RulesException("OutOfBounds","RTable","Invalid Number of Keys used with Table "+this.stringValue());
+ }
+ RTable table = v.rTableValue();
+ IRObject next = table.getValue(keys[i]);
+ if(next == null){
+ return RNull.getRNull();
+ }
+ v = (IRObject) next;
+ }
+ return v;
+ }
+
+ public RArray getKeys (DTState state){
+ ArrayList <RName> keys = new ArrayList<RName>(table.keySet());
+ int id = state.getSession().getUniqueID();
+ return new RArray(id, true, keys,false);
+ }
+
+ public String stringValue() {
+ return tablename.stringValue();
+ }
+
+ public int type() {
+ return iTable;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rTableValue()
+ */
+ @Override
+ public RTable rTableValue() throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#tableValue()
+ */
+ @SuppressWarnings({"unchecked"})
+ public HashMap tableValue() throws RulesException {
+ return table;
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+public class RTime extends ARObject {
+ final Date time;
+ public int type() {
+ return iTime;
+ }
+
+ @Override
+ public double doubleValue() throws RulesException {
+ return time.getTime();
+ }
+
+ @Override
+ public long longValue() throws RulesException {
+ return time.getTime();
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(time.getTime());
+ }
+
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(time.getTime());
+ }
+
+ @Override
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+
+
+ private RTime(Date t){
+ time = t;
+ }
+
+ public static SimpleDateFormat [] formats ={
+ new SimpleDateFormat("MM/dd/yyyy"),
+ new SimpleDateFormat("MM-dd-yyyy"),
+ };
+
+ public static Date getDate(String s){
+ for(int i=0;i<formats.length;i++){
+ try {
+ Date d = formats[i].parse(s);
+ return d;
+ } catch (ParseException e) { } // Didn't work? just try again
+ }
+ return null;
+ }
+
+ /**
+ * Returns a Null if no valid RDate can be parsed from
+ * the string representation
+ * @param s
+ * @return
+ */
+ public static RTime getRDate(String s) throws RulesException {
+ Date d = getDate(s);
+ if(d==null){
+ throw new RulesException("Bad Date Format","getRDate","Could not parse: '"+s+"' as a Date or Time value");
+ }
+ return new RTime(d);
+ }
+
+ public static RTime getRTime(Date t){
+ return new RTime(t);
+ }
+
+ @Override
+ public String toString(){
+ SimpleDateFormat f = new SimpleDateFormat("MM/dd/yyyy hh:mm aa");
+ return f.format(time);
+ }
+
+ public String stringValue() {
+ return time.toString();
+ }
+
+ public int getYear(DTState state) throws RulesException{
+ if(time==null){
+ throw new RulesException("Undefined", "getYear()", "No valid date available");
+ }
+ state.calendar.setTime(time);
+ return state.calendar.get(Calendar.YEAR);
+ }
+ /**
+ * Returns self.
+ */
+ @Override
+ public RTime rTimeValue() throws RulesException {
+ return this;
+ }
+
+ /**
+ * Returns the time's date object.
+ */
+ @Override
+ public Date timeValue() throws RulesException {
+ return time;
+ }
+
+ /**
+ * returns 0 if both are equal. -1 if this object is less than the argument.
+ * 1 if this object is greater than the argument
+ */
+ @Override
+ public int compare(IRObject irObject) throws RulesException {
+ return this.time.compareTo(irObject.timeValue());
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return time.equals(o.timeValue());
+ }
+
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.dtrules.interpreter;
+
+import java.util.ArrayList;
+import java.util.Date;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+
+/**
+ * @author paul snow
+ *
+ * An XmlValue object represents a node in the XML input stream that
+ * supplied data to the Rules Engine. It provides a way to update
+ * and modify that XML based on rules defined in Decision Tables.
+ *
+ */
+public class RXmlValue extends ARObject {
+ XMLTag tag;
+ DTState state;
+ int id;
+
+ public RXmlValue(DTState state, XMLTag tag){
+ this.tag = tag;
+ id = state.getSession().getUniqueID();
+ }
+
+ /**
+ * Sets the value of an Attribute on the tag for this RXmlValue.
+ *
+ * @param attribute
+ * @param value
+ */
+ public void setAttribute(String attribute, String value){
+ tag.getAttribs().put(attribute, value);
+ }
+
+ /**
+ * Gets the value of an Attribute on the tag for this RXmlValue.
+ * Returns a null if the Attribute isn't defined on this tag.
+ * @param attribute
+ * @param value
+ */
+ public String getAttribute(String attribute){
+ if(!tag.getAttribs().containsKey(attribute)){
+ return null;
+ }
+ return tag.getAttribs().get(attribute).toString();
+ }
+
+ /**
+ * The following are all the accessors that are suppored
+ * for working with RXmlValue objects
+ */
+
+ /**
+ * The string value of an XMLTag is its body value
+ */
+ public String stringValue() {
+ return tag.getBody().toString();
+ }
+ public int type() {
+ return iXmlValue;
+ }
+
+ public ArrayList<IRObject> arrayValue() throws RulesException {
+ ArrayList<IRObject> a = new ArrayList<IRObject>();
+ if(tag.getTags().size()>0){
+ for(XMLTag t : tag.getTags()){
+ a.add(new RXmlValue(state,t));
+ }
+ }
+ return a;
+ }
+
+ @Override
+ public boolean booleanValue() throws RulesException {
+ return RBoolean.booleanValue(tag.getBody().toString());
+ }
+
+ @Override
+ public double doubleValue() throws RulesException {
+ return RDouble.getDoubleValue(tag.getBody().toString());
+ }
+
+ @Override
+ public boolean equals(IRObject o) throws RulesException {
+ return rStringValue().equals(o);
+ }
+
+ @Override
+ public int intValue() throws RulesException {
+ return (int)RInteger.getIntegerValue(tag.getBody().toString());
+ }
+
+
+ @Override
+ public long longValue() throws RulesException {
+ return RInteger.getIntegerValue(tag.getBody().toString());
+ }
+
+ @Override
+ public RBoolean rBooleanValue() throws RulesException {
+ return RBoolean.getRBoolean(booleanValue());
+ }
+
+ @Override
+ public RDouble rDoubleValue() throws RulesException {
+ return RDouble.getRDoubleValue(doubleValue());
+ }
+
+ @Override
+ public RInteger rIntegerValue() throws RulesException {
+ return RInteger.getRIntegerValue(longValue());
+ }
+
+ @Override
+ public RName rNameValue() throws RulesException {
+ return RName.getRName(stringValue(),false);
+ }
+
+ public RString rStringValue() {
+ return RString.newRString(stringValue());
+ }
+
+ public RTime rTimeValue() throws RulesException {
+ return RTime.getRTime(timeValue());
+ }
+
+ public Date timeValue() throws RulesException {
+ return RTime.getDate(tag.getBody().toString());
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#rXmlValue()
+ */
+ @Override
+ public RXmlValue rXmlValue() throws RulesException {
+ return this;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.interpreter.ARObject#xmlTagValue()
+ */
+ @Override
+ public XMLTag xmlTagValue() throws RulesException {
+ return tag;
+ }
+
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+import java.util.Date;
+
+import com.dtrules.infrastructure.RulesException;
+
+public class SimpleTokenizer {
+ private StringBuffer buff;
+ private int index;
+
+ static RTime t;
+ static {
+ try{
+ t = RTime.getRDate("12/31/2000");
+ }catch(RulesException e){}
+ }
+
+ public SimpleTokenizer (String input){
+ buff = new StringBuffer(input);
+ index = 0;
+ }
+ /**
+ * Tosses whitespace (anything less than 32). Returns true if any
+ * whitespace was found, and false otherwise. The end of string counts
+ * as whitespace.
+ * @return
+ */
+ private boolean tossWhite(){
+ if(index>=buff.length())return true;
+ char c = buff.charAt(index);
+ if(c>' ')return false;
+ while(hasChar() && buff.charAt(index)<=32)index++;
+ return true;
+ }
+ /**
+ * Returns true if any characters remain in the buffer.
+ * @return
+ */
+ private boolean hasChar(){
+ return index < buff.length();
+ }
+ /**
+ * Returns the next character in the buffer. Returns a space on end
+ * of string.
+ * @return
+ */
+ char getChar(){
+ if(index>=buff.length())return ' ';
+ char c = buff.charAt(index++);
+ return c;
+ }
+
+ /**
+ * Parses out a token at a time, and returns null on the end of input.
+ * @return
+ */
+ public Token nextToken() throws RulesException {
+ tossWhite();
+ if(!hasChar())return null;
+ int start = index;
+ char c = getChar();
+ switch(c){
+ case '"': case '\'': return parseString(c);
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '(':
+ case ')': return new Token(c);
+ }
+ while(getChar()>32);
+ return buildToken(buff.substring(start, index));
+ }
+ /**
+ * We assume the first quote has been
+ * parsed already. We parse till we find the delim char.
+ * We then build
+ * @param delim
+ * @return
+ */
+ Token parseString(char delim){
+ char c = ' ';
+ int start = index;
+ while(hasChar()){
+ if(getChar()==delim){
+ if(start>index-1){
+ return new Token("",Token.Type.STRING);
+ }
+ return new Token(buff.substring(start,index-1),Token.Type.STRING);
+ }
+ }
+ throw new RuntimeException("String is missing the closing quote: ("+c+")");
+ }
+ /**
+ * We attempt to convert v to a long.
+ * Then we attempt to convert v to a float.
+ * Then we try parsing it as a date.
+ * Then we build a name.
+ * @param v
+ * @return
+ */
+ Token buildToken(String v){
+ try {
+ Long longValue = Long.parseLong(v.replaceAll(",", ""));
+ return new Token(longValue);
+ } catch (NumberFormatException e) {}
+ try {
+ Double doubleValue = Double.parseDouble(v.replaceAll(",",""));
+ return new Token(doubleValue);
+ } catch (NumberFormatException e) {}
+ Date t = RTime.getDate(v);
+ if(t!=null){
+ return new Token(RTime.getRTime(t));
+ }
+
+ return new Token(RName.getRName(v));
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.interpreter;
+
+class Token {
+
+ public enum Type {
+ INT,
+ REAL,
+ DATE,
+ LPAREN,
+ RPAREN,
+ LCURLY,
+ RCURLY,
+ LSQUARE,
+ RSQUARE,
+ NAME,
+ STRING,
+ };
+
+ Type type;
+ String strValue;
+ Long longValue;
+ Double doubleValue;
+ RTime datevalue;
+ RName nameValue;
+
+ public Type getType(){
+ return type;
+ }
+
+ Token(char c) {
+ strValue = String.valueOf(c);
+ switch(c){
+ case '[': type = Type.LSQUARE; break;
+ case ']': type = Type.RSQUARE; break;
+ case '{': type = Type.LCURLY; break;
+ case '}': type = Type.RCURLY; break;
+ case '(': type = Type.LPAREN; break;
+ case ')': type = Type.RPAREN; break;
+ default :
+ nameValue = RName.getRName(String.valueOf(c));
+ type = Type.NAME;
+ }
+ }
+
+ Object getValue(){
+ if(type == Type.INT)return longValue;
+ if(type == Type.REAL)return doubleValue;
+ if(type == Type.STRING)return strValue;
+ if(type == Type.LSQUARE)return "[";
+ if(type == Type.RSQUARE)return "]";
+ if(type == Type.LCURLY)return "{";
+ if(type == Type.RCURLY)return "}";
+ if(type == Type.LPAREN)return "(";
+ if(type == Type.RPAREN)return ")";
+ if(type == Type.NAME)return "/"+nameValue.stringValue();
+ return "?";
+ }
+
+ Token(RTime t){
+ datevalue = t;
+ type = Type.DATE;
+ }
+
+ Token(String s,Type t){
+ strValue = s;
+ type = t;
+ }
+ Token(long v){
+ longValue = v;
+ type = Type.INT;
+ }
+
+ Token(Double v){
+ doubleValue = v;
+ type = Type.REAL;
+ }
+
+ Token(RName n){
+ nameValue = n;
+ type = Type.NAME;
+ }
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/interpreter/operators
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RMiscOps.java
+file
+
+
+
+
+2008-08-25T04:59:36.531250Z
+e8be3cc2d14b73fc851276a7bbf94d57
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RDateTimeOps.java
+file
+
+
+
+
+2008-08-24T00:34:17.250000Z
+36d7d65366f0aa289729d61b3bb7c1dc
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RXmlValueOps.java
+file
+
+
+
+
+2008-08-25T04:59:19.609375Z
+9073e12f81b06314f76b1b3415783c5c
+2008-08-25T15:24:13.257771Z
+11349
+psnow
+\f
+RArrayOps.java
+file
+
+
+
+
+2008-08-24T00:32:34.203125Z
+d6c4627122f84069d7c2de7010ae72df
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RControl.java
+file
+
+
+
+
+2008-09-08T20:21:23.531250Z
+5f6e3bbbff4dfd1a08d096efd347f621
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15980
+\f
+RBooleanOps.java
+file
+
+
+
+
+2008-08-25T13:03:24.281250Z
+ae286e6bbf8dfc376fb25381d02c3ead
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RMath.java
+file
+
+
+
+
+2008-08-24T00:34:36.625000Z
+dbef85555561c237abf2027786cd81ab
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+RTableOps.java
+file
+
+
+
+
+2008-09-08T18:27:19.750000Z
+fc7fec356bb8a5e27aa4e7109ce1569c
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6264
+\f
+ROperator.java
+file
+
+
+
+
+2008-08-25T03:56:01.312500Z
+166a3db99071c5729aa4df29526ee58e
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.ArrayList;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RMark;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings("unchecked")
+public class RArrayOps {
+ static {
+ new Addto();
+ new Addat();
+ new Remove();
+ new Removeat();
+ new Getat();
+ new Newarray();
+ new Length();
+ new Memberof();
+ new Mark();
+ new Arraytomark();
+ new Copyelements();
+ new Sortarray();
+ new Sortentities();
+ new Add_no_dups();
+ new Clear();
+ new Merge();
+ new Randomize();
+ new AddArray();
+ new Tokenize();
+ }
+ /**
+ * tokenize ( String1 String2 --> array )
+ * String1 is a string to tokenize
+ * String2 is a regular expression defining these tokens
+ * array is an array of strings that results when String1 is tokenized.
+ * @author ps24876
+ *
+ */
+ static class Tokenize extends ROperator {
+ Tokenize(){super("tokenize");}
+
+ public void execute(DTState state) throws RulesException {
+
+ String pattern = state.datapop().stringValue();
+ IRObject obj1 = state.datapop();
+ String v = "";
+ if(obj1.type() != IRObject.iNull){
+ v = obj1.stringValue().trim();
+ }
+ String [] results = v.split(pattern);
+
+ RArray r = new RArray(state.getSession().getUniqueID(),false,false);
+ for(String t : results){
+ r.add(RString.newRString(t));
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayID='"+r.getID()+"'","'"+t+"'");
+ }
+ }
+ state.datapush(r);
+ }
+ }
+
+
+ /**
+ * addto( Array Value --> )
+ * Addto Operator, adds an element to an array
+ * @author Paul Snow
+ *
+ */
+ static class Addto extends ROperator {
+ Addto(){super("addto");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RArray rarray = state.datapop().rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayID='"+rarray.getID()+"'",value.postFix());
+ }
+ rarray.add(value);
+ }
+ }
+
+ /**
+ * addat( Array int Value --> )
+ * Addat Operator, adds an element to an array at the given location
+ */
+ static class Addat extends ROperator {
+ Addat() {super("addat");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ int position = state.datapop().intValue();
+ RArray rarray = state.datapop().rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addat", "arrayID='"+rarray.getID()+"' index="+position+"'",value.postFix());
+ }
+ rarray.add(position, value);
+
+ }
+ }
+
+ /**
+ * remove( Array Value --> boolean )
+ * Remove Operator, removes all elements from an array that match the value. Returns a
+ * true if at least one element was removed, and a false otherwise.
+ */
+ static class Remove extends ROperator {
+ Remove() {super("remove");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RArray rarray = (RArray)state.datapop();
+ ArrayList array = rarray.arrayValue();
+ boolean removed = false;
+ if(value!=null){
+ for(int i=0; i<array.size();){
+ if(value.equals((IRObject)array.get(i))){
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("removed", "arrayID='"+rarray.getID()+"'",value.postFix());
+ }
+ array.remove(i);
+ removed = true;
+ } else {
+ i++;
+ }
+ }
+ }
+ state.datapush(RBoolean.getRBoolean(removed)); // Return indicater that something was removed.
+ }
+ }
+
+ /**
+ * removeat( Array int --> boolean )
+ * Removeat Operator, removes an element from an
+ * array at the given location. Returns true upon
+ * success
+ */
+ static class Removeat extends ROperator {
+ Removeat() {super("removeat");}
+
+ public void execute(DTState state) throws RulesException {
+ int position = state.datapop().intValue();
+ RArray rarray = (RArray)state.datapop();
+ if(position >= rarray.size()){
+ state.datapush(RBoolean.getRBoolean(false));
+ }
+
+ ArrayList array = rarray.arrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("removed", "arrayID='"+rarray.getID()+"' position='"+position+"'");
+ }
+
+ array.remove(position);
+ state.datapush(RBoolean.getRBoolean(true));
+ }
+ }
+
+ /**
+ * getat( Array int --> value)
+ * Getat Operator, gets an element from an array at the given location
+ */
+ static class Getat extends ROperator {
+ Getat() {super("getat");}
+
+ public void execute(DTState state) throws RulesException {
+ int position = state.datapop().intValue();
+ ArrayList array = state.datapop().arrayValue();
+ state.datapush((IRObject)array.get(position));
+ }
+ }
+
+ /**
+ * newarray( --> Array)
+ * Newarray Operator, returns a new empty array
+ */
+ static class Newarray extends ROperator {
+ Newarray() {super("newarray");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject irobject = new RArray(state.getSession().getUniqueID(),true, false);
+ state.datapush(irobject);
+ }
+ }
+
+ /**
+ * length( Array --> int)
+ * Length Operator, returns the size of the array
+ */
+ static class Length extends ROperator {
+ Length() {super("length");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList array = state.datapop().arrayValue();
+ state.datapush(RInteger.getRIntegerValue(array.size()));
+ }
+ }
+
+ /**
+ * memberof( Array Value --> boolean)
+ * Memberof Operator, returns true if the element found in the array
+ */
+ static class Memberof extends ROperator {
+ Memberof() {super("memberof");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ ArrayList array = state.datapop().arrayValue();
+ boolean found = false;
+ if(value!=null){
+ for(int i=0; i<array.size(); i++){
+ if(value.equals((IRObject)array.get(i))){
+ found=true;
+ break;
+ }
+ }
+ }
+ state.datapush(RBoolean.getRBoolean(found));
+ }
+ }
+
+ /**
+ * copyelements( Array --> newarray)
+ * Copyelements Operator, returns the copy of the array
+ */
+ static class Copyelements extends ROperator {
+ Copyelements() {super("copyelements");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray rarray = state.datapop().rArrayValue();
+ RArray newRArray = rarray.clone(state.getSession()).rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("copyelements", "id='"+rarray.getID()+"' newarrayid='"+newRArray.getID()+"'");
+ for(IRObject v : newRArray){
+ state.traceInfo("addto", "arrayID='"+rarray.getID()+"'",v.postFix());
+ }
+ }
+
+ state.datapush(newRArray);
+
+ }
+ }
+
+ /**
+ * sortarray( Array boolean --> )
+ * Sortarray Operator, sorts the array elements (asc is boolean is true)
+ */
+ static class Sortarray extends ROperator {
+ Sortarray() {super("sortarray");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean asc = state.datapop().booleanValue();
+ int direction = asc ? 1 : -1;
+
+ RArray rarray = state.datapop().rArrayValue();
+ ArrayList<IRObject> array = rarray.arrayValue();
+
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("sort", "length='"+array.size()+"' arrayID='"+rarray.getID()+"'",asc ? "true" : "false");
+ }
+
+ IRObject temp = null;
+ int size = array.size();
+ for(int i=0; i<size-1; i++){
+ for(int j=0; j<size-1-i; j++){
+ if(((IRObject)array.get(j+1)).compare((IRObject)array.get(j)) == direction){
+ temp = (IRObject)array.get(j);
+ array.set(j, (IRObject)array.get(j+1));
+ array.set(j+1, temp);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * randomize ( Array --> )
+ * Randomizes the order in the given array.
+ */
+ static class Randomize extends ROperator {
+ Randomize() {
+ super("randomize");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList<IRObject> array = state.datapop().arrayValue();
+ IRObject temp = null;
+ int size = array.size();
+ for(int i=0; i<10; i++){
+ for(int j=0; j<size; j++){
+ int x = state.rand.nextInt(size);
+ temp = (IRObject)array.get(j);
+ array.set(j, (IRObject)array.get(x));
+ array.set(x, temp);
+ }
+ }
+ }
+ }
+
+ /**
+ * sortentities( Array field boolean --> )
+ * Sortentities Operator,
+ */
+ static class Sortentities extends ROperator {
+ Sortentities() {super("sortentities");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean asc = state.datapop().booleanValue();
+ RName rname = state.datapop().rNameValue();
+ RArray rarray = state.datapop().rArrayValue();
+ ArrayList<IRObject> array = rarray.arrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("sortentities",
+ "length='"+array.size()+
+ "' by='"+rname.stringValue()+
+ "' arrayID='"+rarray.getID()+"'",
+ asc ? "true" : "false");
+ }
+ REntity temp = null;
+ int size = array.size();
+ int greaterthan = asc ? 1 : -1;
+ for(int i=0; i<size; i++){
+ boolean done = true;
+ for(int j=0; j<size-1-i; j++){
+ try {
+ if((((REntity)array.get(j)).get(rname)).compare(((REntity)array.get(j+1)).get(rname))==greaterthan){
+ temp = (REntity)array.get(j);
+ array.set(j, (REntity)array.get(j+1));
+ array.set(j+1, temp);
+ done = false;
+ }
+ }catch(RuntimeException e){
+ throw new RulesException("undefined","sort","Field is undefined: "+rName);
+ }
+ }
+ if(done)return;
+ }
+ }
+ }
+
+ /**
+ * add_no_dups( Array item --> )
+ * Add_no_dups Operator, adds an element to an array if it is not present
+ */
+ static class Add_no_dups extends ROperator {
+ Add_no_dups(){super("add_no_dups");}
+
+ public void execute(DTState state) throws RulesException {
+
+ IRObject value = state.datapop();
+ RArray rArray = (RArray) state.datapop();
+ ArrayList array = rArray.arrayValue();
+ for(int i=0; i<array.size(); i++){
+ if(value.equals((IRObject)array.get(i))){
+ return;
+ }
+ }
+ array.add(value);
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayId='"+rArray.getID()+"'",value.postFix());
+ }
+
+ }
+ }
+
+ /**
+ * clear( Array --> )
+ * Clear Operator, removes all elements from the array
+ */
+ static class Clear extends ROperator {
+ Clear(){super("clear");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject rarray = state.datapop();
+ ArrayList array = rarray.arrayValue();
+ array.clear();
+ if (state.testState(DTState.TRACE)){
+ state.traceInfo("clear", "array='"+rarray.stringValue()+"'");
+ }
+ }
+ }
+
+ /**
+ * merge( Array Array--> Array)
+ * Merge Operator, merges two array to one (Array1 elements followed by Array2 elements)
+ */
+ static class Merge extends ROperator {
+ Merge(){super("merge");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList array2 = state.datapop().arrayValue();
+ ArrayList array1 = state.datapop().arrayValue();
+ ArrayList newarray = new ArrayList();
+ newarray.addAll(array1);
+ newarray.addAll(array2);
+ state.datapush(new RArray(state.getSession().getUniqueID(),false,newarray, false));
+ }
+ }
+
+ /**
+ * Mark ( -- mark ) pushes a mark object onto the data stack.
+ *
+ */
+ static class Mark extends ROperator {
+ Mark(){super("mark");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RMark.getMark());
+ }
+ }
+
+ /**
+ * arraytomark ( mark obj obj ... -- array ) creates an array out
+ * of the elements on the data stack down to the first mark.
+ *
+ */
+ static class Arraytomark extends ROperator {
+ Arraytomark(){super("arraytomark");}
+
+ public void execute(DTState state) throws RulesException {
+ int im = state.ddepth()-1; // Index of top of stack
+ while(im>=0 && state.getds(im).type()!=iMark)im--; // Index of mark
+ RArray newarray = new RArray(state.getSession().getUniqueID(),true,false); // Create a new array
+ int newdepth = im++; // skip the mark (remember its index)
+ while(im<state.ddepth()){ // copy elements to the array
+ newarray.add(state.getds(im++));
+ }
+ while(newdepth < state.ddepth())state.datapop(); // toss elements AND mark
+ state.datapush(newarray); // push the new array.
+ }
+ }
+
+
+ /**
+ * ( array1 array2 boolean -- ) Adds all the elements of array1 to array2. If
+ * the boolean is true, then no duplicates are added to array2. If false, all elements
+ * (duplicate or not) are added to array2
+ *
+ */
+ static class AddArray extends ROperator {
+ AddArray(){super("addarray");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean dups = state.datapop().booleanValue();
+ RArray a2 = state.datapop().rArrayValue();
+ RArray a1 = state.datapop().rArrayValue();
+
+ for(IRObject o : a1){
+ if(dups || !a2.contains(o)){
+ a2.add(o);
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+
+/**
+ * Boolean Operators
+ * @author anand b
+ */
+public class RBooleanOps {
+
+ static {
+ ROperator.alias(RBoolean.getRBoolean(true),"true");
+ ROperator.alias(RBoolean.getRBoolean(false),"false");
+ new Not();
+ new And();
+ new Or();
+ new Greaterthan();
+ new Lessthan();
+ new Greaterthanequal();
+ new Lessthanequal();
+ new Equal();
+ new FGreaterthan();
+ new FLessthan();
+ new FGreaterthanequal();
+ new FLessthanequal();
+ new FEqual();
+ new Isnull();
+ new Booleanequal();
+ new Booleannotequal();
+ new SGreaterthan();
+ new SLessthan();
+ new SGreaterthanequal();
+ new SLessthanequal();
+ new SEqual();
+ new SEqualIgnoreCase();
+ new SConcat();
+ new Strremove();
+ new Req();
+ }
+
+ /**
+ * not( Boolean -- ~boolean )
+ * Not Operator, returns the negation of the input value
+ *
+ */
+ static class Not extends ROperator {
+ Not(){super("not");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(!(state.datapop().booleanValue())));
+ }
+ }
+
+ /**
+ * And( Boolean1 Boolean2 -- Boolean3 )
+ * And Operator, returns the && value of two booleans
+ *
+ */
+ static class And extends ROperator {
+ And(){super("&&"); alias("and");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean v2 = state.datapop().booleanValue();
+ boolean v1 = state.datapop().booleanValue();
+
+ state.datapush(RBoolean.getRBoolean(v1 && v2));
+ }
+ }
+
+ /**
+ * Or( Boolean1 Boolean2 -- Boolean3 )
+ * And Operator, returns the || value of two booleans
+ */
+ static class Or extends ROperator {
+ Or(){super("||");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue() || state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * Greaterthan( Number Number -- Boolean )
+ * Greaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Greaterthan extends ROperator {
+ Greaterthan(){super(">");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject o2 = state.datapop();
+ IRObject o1 = state.datapop();
+ long number2 = o2.longValue();
+ long number1 = o1.longValue();
+ state.datapush(RBoolean.getRBoolean(number1 > number2));
+ }
+ }
+
+ /**
+ * Lessthan( Number Number -- Boolean )
+ * Lessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Lessthan extends ROperator {
+ Lessthan(){super("<");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 < number2));
+ }
+ }
+
+ /**
+ * Greaterthanequal( Number Number -- Boolean )
+ * Greaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Greaterthanequal extends ROperator {
+ Greaterthanequal(){super(">=");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 >= number2));
+ }
+ }
+
+ /**
+ * Lessthanequal( Number Number -- Boolean )
+ * Lessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Lessthanequal extends ROperator {
+ Lessthanequal(){super("<=");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 <= number2));
+ }
+ }
+
+ /**
+ * Equal( Number Number -- Boolean )
+ * Lessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Equal extends ROperator {
+ Equal(){super("==");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().longValue() == state.datapop().longValue()));
+ }
+ }
+
+ /**
+ * FGreaterthan( Number Number -- Boolean )
+ * FGreaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FGreaterthan extends ROperator {
+ FGreaterthan(){super("f>");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 > number2));
+ }
+ }
+
+ /**
+ * FLessthan( Number Number -- Boolean )
+ * FLessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FLessthan extends ROperator {
+ FLessthan(){super("f<");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 < number2));
+ }
+ }
+
+ /**
+ * FGreaterthanequal( Number Number -- Boolean )
+ * FGreaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FGreaterthanequal extends ROperator {
+ FGreaterthanequal(){super("f>=");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 >= number2));
+ }
+ }
+
+ /**
+ * FLessthanequal( Number Number -- Boolean )
+ * FLessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FLessthanequal extends ROperator {
+ FLessthanequal(){super("f<=");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 <= number2));
+ }
+ }
+
+ /**
+ * FEqual( Number Number -- Boolean )
+ * FEqual Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FEqual extends ROperator {
+ FEqual(){super("f==");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().doubleValue() == state.datapop().doubleValue()));
+ }
+ }
+
+ /**
+ * Isnull(object -- Boolean )
+ * Isnull Operator, returns true if the object is null
+ */
+ static class Isnull extends ROperator {
+ Isnull(){super("isnull");}
+
+ public void execute(DTState state) throws RulesException
+ {
+ state.datapush(RBoolean.getRBoolean(state.datapop().type()==IRObject.iNull));
+ }
+ }
+
+ /**
+ * Booleanequal(boolean1 boolean2 -- Boolean )
+ * Booleanequal Operator, returns true if both are equal
+ */
+ static class Booleanequal extends ROperator {
+ Booleanequal(){super("b="); alias("beq");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue()==state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * Booleannotequal(boolean1 boolean2 -- Boolean )
+ * Booleannotequal Operator, returns true if both are not equal
+ */
+ static class Booleannotequal extends ROperator {
+ Booleannotequal(){super("b!=");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue()!=state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * SGreaterthan( String String -- Boolean )
+ * SGreaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SGreaterthan extends ROperator {
+ SGreaterthan(){super("s>");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)>0));
+ }
+ }
+
+ /**
+ * SLessthan( String String -- Boolean )
+ * SLessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SLessthan extends ROperator {
+ SLessthan(){super("s<");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)< 0));
+ }
+ }
+
+ /**
+ * SGreaterthanequal( String String -- Boolean )
+ * SGreaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SGreaterthanequal extends ROperator {
+ SGreaterthanequal(){super("s>=");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)>=0));
+ }
+ }
+
+ /**
+ * SLessthanequal( String String -- Boolean )
+ * SLessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SLessthanequal extends ROperator {
+ SLessthanequal(){super("s<=");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)<=0));
+ }
+ }
+
+ /**
+ * SEqual( String String -- Boolean )
+ * SEqual Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SEqual extends ROperator {
+ SEqual(){super("s=="); alias("streq");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.equals(value2)));
+ }
+ }
+
+ /**
+ * SEqualIgnoreCase( String String -- Boolean )
+ * Same as SEqual Operator, only ignores the case.
+ * Returns the boolean value for condition with the given parameters
+ */
+ static class SEqualIgnoreCase extends ROperator {
+ SEqualIgnoreCase(){super("sic=="); alias("streqignorecase");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.equalsIgnoreCase(value2)));
+ }
+ }
+
+
+
+ /**
+ * StrConcat( String String -- String )
+ * StrConcat Operator, add the given two strings and returns a string value
+ */
+ static class SConcat extends ROperator {
+ SConcat(){super("s+"); alias("strconcat");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RString.newRString(value1+value2));
+ }
+ }
+
+ /**
+ * Strremove( String1 String2 -- String3 )
+ * Strremove Operator, removes string2 from string1 and returns string3
+ */
+ static class Strremove extends ROperator {
+ Strremove(){super("strremove");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RString.newRString(value1.replaceAll(value2, "")));
+ }
+ }
+
+ /**
+ * Req( object1 object2 -- Boolean )
+ * Req Operator, compares the two objects using equals and returns the boolean value
+ */
+ static class Req extends ROperator {
+ Req(){super("req");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value2 = state.datapop();
+ IRObject value1 = state.datapop();
+ state.datapush(RBoolean.getRBoolean(value1.equals(value2)));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+/**
+ * Defines math operators.
+ * @author paul snow
+ *
+ */
+@SuppressWarnings("unchecked")
+public class RControl {
+ static {
+ new If(); new Ifelse(); new While();
+ new Forallr(); new Forall(); new For();
+ new Forr(); new Entityforall(); new Forfirst();
+ new Doloop(); new ForFirstElse(); new ExecuteTable();
+ new Execute(); new Deallocate(); new Allocate();
+ new Localfetch(); new Localstore();
+ }
+
+ /**
+ * ( body boolean -- ) executes the body if the boolean is true.
+ * @author paul snow
+ *
+ */
+ static class If extends ROperator {
+ If(){super("if");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean test = state.datapop().booleanValue();
+ IRObject body = state.datapop();
+ if(test)body.execute(state);
+ }
+ }
+ /**
+ * ( truebody falsebody test -- ) Executes truebody if the boolean test is true, otherwise
+ * executes falsebody.
+ * @author paul snow
+ *
+ */
+ static class Ifelse extends ROperator {
+ Ifelse(){super("ifelse");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean test = state.datapop().booleanValue();
+ IRObject falsebody = state.datapop();
+ IRObject truebody = state.datapop();
+ if(test){
+ truebody.execute(state);
+ }else{
+ falsebody.execute(state);
+ }
+ }
+ }
+
+ /**
+ * This is an internal operator which doesn't have any use outside of the
+ * Rules Engine itself. It is used to execute the conditions and actions
+ * for a table within the context as defined in the table.
+ *
+ * ( DecisionTableName -- ) Takes the DecisionTable name and looks it up
+ * in the decisiontable entity. It then executes the table within that
+ * decision table. Because of this extra lookup, this path shouldn't be
+ * used unless there actually is a context to be executed.
+ *
+ * @author paul snow
+ *
+ */
+ static class ExecuteTable extends ROperator {
+ ExecuteTable(){super("executetable");}
+
+ public void execute(DTState state) throws RulesException {
+ RName dtname = state.datapop().rNameValue();
+ state.getSession().getEntityFactory().getDecisionTable(dtname).executeTable(state);
+ }
+ }
+ /**
+ * ( RObject -- ? ) Executes the object on the top of the data stack.
+ * The behavior of this operator is defined by the object executed. Usually
+ * the data stack will be left clean.
+ * @author paul snow
+ *
+ */
+ static class Execute extends ROperator {
+ Execute(){super("execute"); }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapop().getExecutable().execute(state);
+ }
+ }
+
+ /**
+ * ( body test -- ) executes test. If test returns true, executes body.
+ * Repeats until the test returns false.
+ *
+ * @author paul snow
+ *
+ */
+ static class While extends ROperator {
+ While(){super("while");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject test = state.datapop(); // Get the test
+ IRObject body = state.datapop(); // Get the body
+
+ test.execute(state); // evaluate the test
+ while(state.datapop().booleanValue()){ // If true, keep looping
+ body.execute(state); // execute the body.
+ test.execute(state); // check the test again.
+ }
+
+
+ }
+ }
+ /**
+ * ( body array -- ) Execute the body for each entity in the array.
+ * executes backwards through the array, and the entity can be removed
+ * from the array by the body.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forallr extends ROperator {
+ Forallr(){super("forallr");}
+
+ public void execute(DTState state) throws RulesException {
+
+ ArrayList array = state.datapop().arrayValue(); // Get the array
+ int length = array.size(); // get Array length.
+ IRObject body = state.datapop(); // Get the body
+ for(int i=length - 1;i>=0;i--){ // For each element in array,
+ IRObject o = (IRObject) array.get(i);
+ int t = o.type();
+ if(t== iNull)continue;
+ if(t!=iEntity){
+ throw new RulesException("Type Check", "Forallr", "Encountered a non-Entity entry in array: "+o);
+ }
+ state.entitypush((IREntity) o);
+ body.execute(state);
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body array -- ) executes the body for each entity in the array. Uses an
+ * Iterator and executes forward in the array. The entity cannot be removed from
+ * the array by the body.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forall extends ROperator {
+ Forall(){super("forall");}
+
+ public void execute(DTState state) throws RulesException {
+
+ RArray array = state.datapop().rArrayValue();
+ IRObject body = state.datapop(); // Get the body
+
+ for(IRObject o : array){
+ int t = o.type();
+ if(t== iNull)continue;
+ if(t!=iEntity){
+ throw new RulesException("Type Check", "Forallr", "Encountered a non-Entity entry in array: "+o);
+ }
+ state.entitypush((IREntity) o);
+ body.execute(state);
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body array -- ) Pushes each element on to the data stack, then executes the body.
+ * @author paul snow
+ *
+ */
+ static class For extends ROperator {
+ For(){super("for");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray list = state.datapop().rArrayValue();
+ IRObject body = state.datapop(); // Get the body
+ for(IRObject o : list){
+ state.datapush(o);
+ body.execute(state);
+ }
+ }
+ }
+ /**
+ * ( body array -- ) pushes each element on to the data stack, then executes the body.
+ * Because the array is evaluated in reverse order, the element can be removed from the
+ * array if you care to.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forr extends ROperator {
+ Forr(){super("forr");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList<IRObject> array = state.datapop().arrayValue(); // Get the array
+ int length = array.size(); // get Array length.
+ IRObject body = state.datapop(); // Get the body
+ for(int i=length-1;i>=0;i++){ // For each element in array,
+ IRObject o = (IRObject) array.get(i);
+ state.datapush((IRObject) o);
+ body.execute(state);
+ }
+ }
+ }
+ /**
+ * ( body entity -- ) Executes the body for each key value pair in the Entity.
+ *
+ * @author paul snow
+ *
+ */
+ static class Entityforall extends ROperator {
+ Entityforall(){super("entityforall");}
+
+ public void execute(DTState state) throws RulesException {
+ IREntity entity = state.datapop().rEntityValue(); // Get the entity
+ IRObject body = state.datapop(); // Get the body
+ Iterator keys = entity.getAttributeIterator(); // Get the Attribute Iterator
+ while(keys.hasNext()){ // For each attribute
+ RName n = (RName) keys.next();
+ IRObject v = entity.get(n);
+ if(v!=null){
+ state.datapush(n);
+ state.datapush(v);
+ body.execute(state);
+ }
+ }
+ }
+ }
+ /**
+ * ( body test array -- )
+ * Each entity within the array is placed on the entity stack. The test is evaluated, which should
+ * return the boolean. If true, the body is executed, and the loop stops.
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class Forfirst extends ROperator {
+ Forfirst(){super("forfirst");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray array = state.datapop().rArrayValue();
+ IRObject test = state.datapop();
+ IRObject body = state.datapop();
+ Iterator<REntity> ie = array.getIterator();
+ while(ie.hasNext()){
+ state.entitypush(ie.next());
+ test.execute(state);
+ if(state.datapop().booleanValue()){
+ body.execute(state);
+ state.entitypop();
+ return;
+ }
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body1 body2 test array -- )
+ * Each entity within the array is placed on the entity stack. The test is
+ * evaluated, which should return the boolean. If true, the body1 is executed,
+ * and the loop stops. If no match is found, body2 is executed. Kinda a
+ * default operation.
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class ForFirstElse extends ROperator {
+ ForFirstElse(){super("forfirstelse");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray array = state.datapop().rArrayValue();
+ IRObject test = state.datapop();
+ IRObject body2 = state.datapop();
+ IRObject body1 = state.datapop();
+ for(IRObject obj : array) {
+ IREntity e = obj.rEntityValue();
+ state.entitypush(e);
+ test.execute(state);
+ if(state.datapop().booleanValue()){
+ body1.execute(state);
+ state.entitypop();
+ return;
+ }
+ state.entitypop();
+ }
+ body2.execute(state);
+ }
+ }
+
+ /**
+ * ( body start increment limit -- ) Starts the index with the value "start". If the
+ * increment is positive and start is below the limit, the index
+ * is pushed and body is executed, then the index is incremented
+ * by increment. If the increment is negative and stat is above
+ * the limit, then the index is pushed and the body is executed,
+ * then the index is decremented by the increment. This continues
+ * until the limit is reached.
+ *
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class Doloop extends ROperator {
+ Doloop(){super("doloop");}
+
+ public void execute(DTState state) throws RulesException {
+ int limit = state.datapop().intValue();
+ int increment = state.datapop().intValue();
+ int start = state.datapop().intValue();
+ IRObject body = state.datapop();
+ if(increment>0){
+ for(int i = start;i<limit;i+=increment){
+ state.cpush(RInteger.getRIntegerValue(i));
+ body.execute(state);
+ state.cpop();
+ }
+ }else{
+ for(int i = start;i>limit;i+=increment){
+ state.cpush(RInteger.getRIntegerValue(i));
+ body.execute(state);
+ state.cpop();
+ }
+ }
+ }
+ }
+ /**
+ * ( value -- )
+ * Allocates storage for a local variable. The value is the initial
+ * value for that variable. In all reality, this is just a push of
+ * a value to the control stack.
+ * @author paul snow
+ *
+ */
+ static class Allocate extends ROperator {
+ Allocate(){super("allocate"); alias("cpush");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("allocate", "value='"+v.stringValue()+"'");
+ }
+ state.cpush(v);
+ }
+ }
+
+ /**
+ * ( -- value )
+ * Deallocates storage for a local variable. In all reality, this is
+ * just a pop of a value from the control stack.
+ *
+ * @author paul snow
+ *
+ */
+ static class Deallocate extends ROperator {
+ Deallocate(){super("deallocate"); alias("cpop");}
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.cpop());
+ }
+ }
+ /**
+ * ( index -- IRObject ) fetches the value from the local variable
+ * specified by the given index. This is an offset from the currentframe.
+ * @author paul snow
+ *
+ */
+ static class Localfetch extends ROperator {
+ Localfetch(){super("local@");}
+
+ public void execute(DTState state) throws RulesException {
+ int index = state.datapop().intValue();
+ IRObject value = state.getFrameValue(index);
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("local_fetch", "index='"+index+"' value='"+value.stringValue()+"'");
+ }
+ state.datapush(value);
+ }
+ }
+ /**
+ * (value index -- ) stores the value into the local variable specified
+ * by the given index. The index is an offset from the currentframe.
+ * @author paul snow
+ *
+ */
+ static class Localstore extends ROperator {
+ Localstore(){super("local!");}
+
+ public void execute(DTState state) throws RulesException {
+ int index = state.datapop().intValue();
+ IRObject value = state.datapop();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("local_store", "index='"+index+"' value='"+value.stringValue()+"'");
+ }
+ state.setFrameValue(index, value);
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+
+/**
+ * Boolean Operators
+ * @author anand b
+ */
+public class RDateTimeOps {
+
+ static {
+ new Newdate();
+ new SetCalendar();
+ new Yearof();
+ new Getdaysinyear();
+ new Getdaysinmonth();
+ new Getdayofmonth();
+ new Datelt();
+ new Dategt();
+ new Dateeq();
+ new Gettimestamp();
+ new Days();
+ new DatePlus();
+ new DateMinus();
+ new FirstOfMonth();
+ new FirstOfYear();
+ new AddYears();
+ new AddMonths();
+ new AddDays();
+ new EndOfMonth();
+ new YearsBetween();
+ new DaysBetween();
+ new MonthsBetween();
+ }
+
+ /**
+ * Newdate( String -- Date )
+ * Newdate Operator, returns the Date object for the String value
+ *
+ */
+ static class Newdate extends ROperator {
+ Newdate(){super("newdate");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RTime.getRTime(java.sql.Date.valueOf(state.datapop().stringValue())));
+ }
+ }
+
+ /**
+ * Days( number -- Date )
+ * Returns a Date object holding this number of days.
+ *
+ */
+ static class Days extends ROperator {
+ Days(){super("days");}
+
+ public void execute(DTState state) throws RulesException {
+ int days = state.datapop().intValue();
+ long time = days * 24* 60 * 60 * 1000;
+ state.datapush(RTime.getRTime(new Date(time)));
+ }
+ }
+
+ /**
+ * FirstOfMonth ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the month.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class FirstOfMonth extends ROperator {
+ FirstOfMonth(){super("firstofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(Calendar.DAY_OF_MONTH, 1);
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * FirstOfYear ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the year.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class FirstOfYear extends ROperator {
+ FirstOfYear(){super("firstofyear");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(Calendar.DAY_OF_MONTH, 1);
+ state.calendar.set(Calendar.MONTH, 0);
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * EndOfMonth ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the month.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class EndOfMonth extends ROperator {
+ EndOfMonth(){super("endofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(
+ Calendar.DAY_OF_MONTH,
+ state.calendar.getActualMaximum(Calendar.MONTH));
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * AddYears ( date int -- date2)
+ * Adds the given number of years to the given date. Care has to be
+ * taken where leap years are in effect. The month can change.
+ * So given 2/23/07 3 addYears would return 2/23/10
+ */
+ static class AddYears extends ROperator {
+ AddYears(){super("addyears");}
+
+ public void execute(DTState state) throws RulesException {
+ int years = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.YEAR, years);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * AddMonths ( date int -- date2)
+ * Adds the given number of months to the given date. Care has to be
+ * taken where the current day (31) may not be present in the new
+ * month (a month with 30 days).
+ * The behavior in this case is defined by the behavior of the Java
+ * Calendar.
+ * So given 2/23/07 3 addMonths would return 5/23/07
+ */
+ static class AddMonths extends ROperator {
+ AddMonths(){super("addmonths");}
+
+ public void execute(DTState state) throws RulesException {
+ int months = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.MONTH, months);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * AddDays ( date int -- date2)
+ * Adds the given number of days to the given date. You might
+ * move over to the next month!
+ */
+ static class AddDays extends ROperator {
+ AddDays(){super("adddays");}
+
+ public void execute(DTState state) throws RulesException {
+ int days = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.DATE, days);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * SetCalendar( String -- )
+ * SetCalendar Operator,
+ */
+ @SuppressWarnings({"unchecked"})
+ static class SetCalendar extends ROperator {
+ SetCalendar(){super("setCalendar");}
+
+ public void execute(DTState state) throws RulesException {
+ try {
+ Class clazz = Class.forName(state.datapop().stringValue());
+ Object obj = clazz.newInstance();
+ if(obj instanceof Calendar){
+ state.calendar=(Calendar)obj;
+ } else {
+ throw new RulesException("Date Time Exception","Set Calendar","Not a Calendar Object");
+ }
+ } catch(Exception e){
+ throw new RulesException("Date Time Exception","/","Error while creating object: "+e);
+ }
+ }
+ }
+
+ /**
+ * Yearof( date -- int )
+ * Yearof Operator, returns the year value for the given date
+ */
+ static class Yearof extends ROperator {
+ Yearof(){super("yearof");}
+
+ public void execute(DTState state) throws RulesException {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(state.datapop().timeValue());
+ state.datapush(RInteger.getRIntegerValue(calendar.get(Calendar.YEAR)));
+ }
+ }
+
+ /**
+ * Getdaysinyear( date -- long )
+ * Getdaysinyear Operator, returns the number of days in a year from the given date
+ */
+ static class Getdaysinyear extends ROperator {
+ Getdaysinyear(){super("getdaysinyear");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ if(calendar.isLeapYear(calendar.get(Calendar.YEAR))){
+ state.datapush(RInteger.getRIntegerValue(366));
+ } else {
+ state.datapush(RInteger.getRIntegerValue(365));
+ }
+ }
+ }
+ /**
+ * Getdayofmonth( date -- long )
+ * Returns the day of the month in the given date
+ */
+ static class Getdayofmonth extends ROperator {
+ Getdayofmonth(){super("getdayofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+ state.datapush(RInteger.getRIntegerValue(day));
+ }
+ }
+ /**
+ * GetdaysinMonth( date -- long )
+ * Getdaysinyear Operator, returns the number of days in a year from the given date
+ */
+ static class Getdaysinmonth extends ROperator {
+ Getdaysinmonth(){super("getdaysinmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ int daysinmonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ state.datapush(RInteger.getRIntegerValue(daysinmonth));
+ }
+ }
+
+ /**
+ * Datelt( date1 date2 -- boolean )
+ * Datelt Operator, returns true if date1 is less than date2
+ */
+ static class Datelt extends ROperator {
+ Datelt(){super("d<");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ boolean test =date1.before(date2);
+ state.datapush(RBoolean.getRBoolean(test));
+ }
+ }
+
+ /**
+ * Dategt( date1 date2 -- boolean )
+ * Dategt Operator, returns true if date1 is greater than date2
+ */
+ static class Dategt extends ROperator {
+ Dategt(){super("d>");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ boolean test = date1.after(date2);
+ state.datapush(RBoolean.getRBoolean(test));
+ }
+ }
+
+ /**
+ * Dateeq (date1 date2 -- boolean )
+ * Dateeq Operator, returns true if date1 is equals to date2
+ */
+ static class Dateeq extends ROperator {
+ Dateeq(){super("d==");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ state.datapush(RBoolean.getRBoolean(date1.compareTo(date2)==0));
+ }
+ }
+
+ /**
+ * Gettimestamp( date -- String )
+ * Gettimestamp Operator, creates a string timestamp from s date
+ */
+ static class Gettimestamp extends ROperator {
+ Gettimestamp(){super("gettimestamp");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.datapush(RString.newRString((new Timestamp(date.getTime())).toString()));
+ }
+ }
+
+ /**
+ * d+ ( date1 date2 -- )
+ * Add two dates together. This doesn't make all that much sense unless
+ * one or both of the dates is just a count of days.
+ */
+ static class DatePlus extends ROperator {
+ DatePlus() {super("d+"); }
+ public void execute(DTState state) throws RulesException {
+ long date2 = state.datapop().timeValue().getTime();
+ long date1 = state.datapop().timeValue().getTime();
+ state.datapush(RTime.getRTime(new Date(date1+date2)));
+ }
+
+ }
+
+ /**
+ * d- ( date1 date2 -- )
+ * Subtract date2 from date1 This doesn't make all that much sense unless
+ * one or both of the dates is just a count of days.
+ */
+ static class DateMinus extends ROperator {
+ DateMinus() {super("d-"); }
+ public void execute(DTState state) throws RulesException {
+ long date2 = state.datapop().timeValue().getTime();
+ long date1 = state.datapop().timeValue().getTime();
+ state.datapush(RTime.getRTime(new Date(date1-date2)));
+ }
+
+ }
+ /**
+ * ( date1 date2 -- int )
+ * Returns the number of years between date1 and date2. It is always
+ * the difference, i.e. positive, even if date1 is after date2
+ */
+ static class YearsBetween extends ROperator {
+ YearsBetween() {super("yearsbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ int y1 = state.calendar.get(Calendar.YEAR);
+ int m1 = state.calendar.get(Calendar.MONTH);
+ int d1 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ state.calendar.setTime(date2);
+ int y2 = state.calendar.get(Calendar.YEAR);
+ int m2 = state.calendar.get(Calendar.MONTH);
+ int d2 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ int diff = y2-y1;
+ if(m2<m1)diff--;
+ if(m2==m1 && d2<d1)diff--;
+ state.datapush(RInteger.getRIntegerValue(diff));
+ }
+
+ }
+ /**
+ * ( date1 date2 -- int )
+ * Returns the number of months between date1 and date2. It is always
+ * the difference, i.e. positive, even if date1 is after date2. The
+ * number of months doesn't care about the day... the 30th of the month
+ * is treated identically to the first of the month.
+ */
+ static class MonthsBetween extends ROperator {
+ MonthsBetween() {super("monthsbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ int y1 = state.calendar.get(Calendar.YEAR);
+ int m1 = state.calendar.get(Calendar.MONTH);
+ int d1 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ state.calendar.setTime(date2);
+ int y2 = state.calendar.get(Calendar.YEAR);
+ int m2 = state.calendar.get(Calendar.MONTH);
+ int d2 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ int yeardiff = y2-y1;
+ if(m2<m1)yeardiff--;
+ int monthdiff = m2-m1;
+ if(d2<d1-1)monthdiff--;
+ if(monthdiff < 0)monthdiff +=12;
+ monthdiff += 12*yeardiff;
+ state.datapush(RInteger.getRIntegerValue(monthdiff));
+ }
+ }
+ static class DaysBetween extends ROperator {
+ DaysBetween() {super("daysbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ long from = state.calendar.getTimeInMillis();
+ state.calendar.setTime(date2);
+ long to = state.calendar.getTimeInMillis();
+ long days = Math.round((to-from)/(1000*60*60*24));
+ state.datapush(RInteger.getRIntegerValue(days));
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.session.DTState;
+/**
+ * Defines math operators.
+ * @author paul snow
+ *
+ */
+public class RMath {
+ static {
+ new Add(); new Mul(); new Sub(); new Div();
+ new FAdd(); new FMul(); new FSub(); new FDiv();
+ new Abs(); new Negate();
+ new FAbs(); new FNegate();
+ new Roundto();
+ }
+
+ /**
+ * ( number #places boundary -- number2 )
+ * The number of decimal places would be zero to round to the nearest
+ * integer, 1 to the nearest 10th, -1 to the nearest 10. The boundary
+ * is the value added to the lower fractional amount to trigger the
+ * round. In other words, <br><br>
+ *
+ * 1.3 0 .7 roundto<br><br>
+ *
+ * would result in 1, while<br><br>
+ *
+ * 1.7 0 .7 roundto<br>
+ *
+ * would reslut in 2.<br><br><br>
+ *
+ * Note: if the boundary is zero, than any fractional amount will round up.
+ * If the boundary is 1, the number is simply truncated.
+ *
+ * Limitation: We always towards zero. Lots of other rounding ideas are
+ * possible. We need to come back here and rework and add to our options
+ * if the need for more complexity comes our way.
+ *
+ * @author paul snow
+ *
+ */
+ static class Roundto extends ROperator {
+ Roundto(){super("roundto"); }
+
+ double round(double number,double boundary){
+ double v = (int)number; // Get the integer porition of number
+ if (boundary>=1) return v; // If boundary is 1 or greater we are done
+ double r = Math.abs(number - v); // Get the fractional portion of number
+ if (boundary<=0) return r>0 ? v++ : v; // If boundary is 0 or less, inc on any fraction
+ if(r>=boundary)return v++; // Otherwise test the boundary. Inc if fraction
+ return v; // is greater or equal to the boundary.
+ }
+ public void execute(DTState state)throws RulesException {
+ double boundary = state.datapop().doubleValue();
+ int places = state.datapop().intValue();
+ double number = state.datapop().doubleValue();
+ if(places >0){ // We put the boundary across zero. shift left if
+ number *= 10*places; // places is positive (okay, its a decimal shift)
+ number = round(number,boundary); // Do the round thing.
+ number /= 10*places; // Fix it back when done.
+ }else{
+ number /= -10*places; // We decimal shift right if places is negative
+ number = round(number,boundary); // Do the round thing
+ number *= -10*places; // Fix it back.
+ }
+
+ }
+ }
+
+
+ /**
+ * Negate a double
+ * @author paul snow
+ *
+ */
+ static class FNegate extends ROperator {
+ FNegate(){super("fnegate"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RDouble.getRDoubleValue(
+ -state.datapop().doubleValue()
+ )
+ );
+ }
+ }
+
+
+ /**
+ * Absolute value of a double.
+ * @author paul snow
+ *
+ */
+ static class FAbs extends ROperator {
+ FAbs(){super("fabs"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RDouble.getRDoubleValue(
+ Math.abs(state.datapop().doubleValue())
+ )
+ );
+ }
+ }
+ /**
+ * Absolute value of an integer
+ * @author paul snow
+ *
+ */
+ static class Abs extends ROperator {
+ Abs(){super("abs"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RInteger.getRIntegerValue(
+ Math.abs(state.datapop().intValue())
+ )
+ );
+ }
+ }
+
+ /**
+ * Negate an integer
+ * @author paul snow
+ *
+ */
+ static class Negate extends ROperator {
+ Negate(){super("negate"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RInteger.getRIntegerValue(
+ -state.datapop().intValue()
+ )
+ );
+ }
+ }
+
+ /**
+ * Add Operator, adds two integers
+ * @author Paul Snow
+ *
+ */
+ static class Add extends ROperator {
+ Add(){
+ super("+"); alias("ladd");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RInteger.getRIntegerValue(state.datapop().longValue()+state.datapop().longValue()));
+ }
+ }
+
+
+
+
+ /**
+ * Sub Operator, subracts two integers
+ * @author Paul Snow
+ *
+ */
+ static class Sub extends ROperator {
+ Sub(){super("-"); alias("lsub");}
+
+ public void execute(DTState state) throws RulesException {
+ long b = state.datapop().longValue();
+ long a = state.datapop().longValue();
+ long result = a-b;
+ state.datapush(RInteger.getRIntegerValue(result));
+ }
+ }
+
+ /**
+ * Mul Operator, multiply two integers
+ * @author Paul Snow
+ *
+ */
+ static class Mul extends ROperator {
+ Mul(){super("*"); alias("lmul");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RInteger.getRIntegerValue(state.datapop().longValue()*state.datapop().longValue()));
+ }
+ }
+
+ /**
+ * Divide Operator, divides one integer by another
+ * @author Paul Snow
+ *
+ */
+ static class Div extends ROperator {
+ Div(){super("/"); alias("div"); alias("ldiv");}
+
+ public void execute(DTState state) throws RulesException {
+ long result;
+ long a=0; long b=0;
+ try {
+ b = state.datapop().longValue();
+ a = state.datapop().longValue();
+ result = a/b;
+ } catch (ArithmeticException e) {
+ throw new RulesException("Math Exception","/","Error in Divide: "+a+"/"+b+"\n"+e);
+ }
+ state.datapush(RInteger.getRIntegerValue(result));
+ }
+ }
+
+ /**
+ * FAdd (f+) Operator, adds two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FAdd extends ROperator {
+ FAdd(){
+ super("f+");alias("fadd");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ IRObject b = state.datapop();
+ IRObject a = state.datapop();
+ state.datapush(RDouble.getRDoubleValue(a.doubleValue()+b.doubleValue()));
+ }
+ }
+
+
+
+
+ /**
+ * FSub (f-) Operator, subracts two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FSub extends ROperator {
+ FSub(){super("f-");alias("fsub");}
+
+ public void execute(DTState state) throws RulesException {
+ double b = state.datapop().doubleValue();
+ double a = state.datapop().doubleValue();
+ double result = a-b;
+ state.datapush(RDouble.getRDoubleValue(result));
+ }
+ }
+
+ /**
+ * FMul Operator, multiply two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FMul extends ROperator {
+ FMul(){super("f*");alias("fmul");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RDouble.getRDoubleValue(state.datapop().doubleValue()*state.datapop().doubleValue()));
+ }
+ }
+
+ /**
+ * FDiv Operator, divides one double by another double.
+ * @author Paul Snow
+ *
+ */
+ static class FDiv extends ROperator {
+ FDiv(){super("fdiv"); alias("f/");}
+
+ public void execute(DTState state) throws RulesException {
+ double result;
+ double a=0; double b=0;
+ try {
+ b = state.datapop().doubleValue();
+ a = state.datapop().doubleValue();
+ result = a/b;
+ } catch (ArithmeticException e) {
+ throw new RulesException("Math Exception","f/","Error in Divide: "+a+"/"+b+"\n"+e);
+ }
+ state.datapush(RDouble.getRDoubleValue(result));
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RSession;
+
+public class RMiscOps {
+ static {
+ new RError();
+ new Debug();
+ new Traceon();
+ new Traceoff();
+ new Ignore();
+ new Stringlength();
+ new Touppercase();
+ new Tolowercase();
+ new Trim();
+ new substring();
+ new Swap();
+ new Dup();
+ new Pop();
+ new Over();
+ new EntityName();
+ new Entitypush();
+ new Entitypop();
+ new Entityfetch();
+ new I(); new J(); new K();
+ new ToR();
+ new FromR();
+ new Def();
+ new Find();
+ new Print();
+ new Clone();
+ new Xdef();
+ new PStack();
+ new Null();
+ new Createentity();
+ new Cvi();
+ new Cvr();
+ new Cvb();
+ new Cve();
+ new Cvs();
+ new Cvn();
+ new Cvd();
+ new ActionString();
+ new GetDescription();
+ new RegexMatch();
+ }
+
+ /**
+ * ( -- RNull ) Return the Null object
+ */
+ static class Null extends ROperator {
+ Null() {
+ super("null");
+ }
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RNull.getRNull());
+ }
+ }
+
+
+ /**
+ * ( entity -- RName ) Get the name of the given entity.
+ */
+ static class EntityName extends ROperator {
+ EntityName() {
+ super("entityname");
+ }
+ public void execute(DTState state) throws RulesException {
+ IREntity entity = state.datapop().rEntityValue();
+ state.datapush(entity.getName());
+ }
+ }
+ /**
+ * ( Exception message -- ) Throws a RulesException with the given message.
+ * @author paul snow
+ *
+ *
+ */
+ static class RError extends ROperator {
+ RError(){super("error");}
+
+ public void execute(DTState state) throws RulesException {
+ String message = state.datapop().stringValue();
+ String exception = state.datapop().stringValue();
+ try {
+ throw new RulesException(
+ "exception",
+ "User Exception",
+ message);
+ } catch (Exception e) {
+ throw new RulesException("Type Check",
+ "User Exception",
+ exception+":"+message);
+ }
+ }
+ }
+
+ /**
+ * ( string -- ) Prints a debug message only if debug output is enabled.
+ * @author paul snow
+ *
+ */
+ static class Debug extends ROperator {
+ Debug(){super("debug");}
+
+ public void execute(DTState state) throws RulesException {
+ String msg = state.datapop().stringValue();
+ if(state.testState(DTState.DEBUG)){
+ state.debug(msg);
+ }
+ }
+ }
+
+ /**
+ * ( -- ) Turn on the trace flag.
+ * @author paul snow
+ *
+ */
+ static class Traceon extends ROperator {
+ Traceon(){super("traceon");}
+
+ public void execute(DTState state) throws RulesException {
+ state.setState(DTState.TRACE);
+ }
+ }
+
+ /**
+ * ( -- ) Turn off the trace flag
+ * @author paul snow
+ *
+ */
+ static class Traceoff extends ROperator {
+ Traceoff(){super("traceoff");}
+
+ public void execute(DTState state) throws RulesException {
+ state.clearState(DTState.TRACE);
+ }
+ }
+
+ /**
+ * ( flag -- ) Set the debug state
+ *
+ * @author paul snow
+ *
+ */
+ static class SetDebug extends ROperator {
+ SetDebug(){super("setdebug");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean flg = state.datapop().booleanValue();
+ if(flg){
+ state.setState(DTState.DEBUG);
+ }else{
+ state.clearState(DTState.DEBUG);
+ }
+ }
+ }
+
+ /**
+ * A Noop -- Does nothing.
+ * @author paul snow
+ *
+ */
+ static class Ignore extends ROperator {
+ Ignore(){super("ignore"); alias("nop");}
+
+ public void execute(DTState state) throws RulesException {
+ }
+ }
+
+ /**
+ * ( string -- length ) returns the length of the given string
+ * @author paul snow
+ *
+ */
+ static class Stringlength extends ROperator {
+ Stringlength(){super("strlength");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ RInteger len = RInteger.getRIntegerValue(str.length());
+ state.datapush(len);
+ }
+ }
+
+ /**
+ * ( String -- String ) converts the string to uppercase.
+ * @author paul snow
+ *
+ */
+ static class Touppercase extends ROperator {
+ Touppercase(){super("touppercase");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.toUpperCase();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( String -- String ) converts the string to lowercase
+ * @author paul snow
+ *
+ */
+ static class Tolowercase extends ROperator {
+ Tolowercase(){super("tolowercase");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.toLowerCase();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( string -- string ) Trims the string, per trim in Java
+ * @author paul snow
+ *
+ */
+ static class Trim extends ROperator {
+ Trim(){super("trim");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.trim();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * (endindex beginindex string -- substring ) Returns the substring
+ * @author paul snow
+ *
+ */
+ static class substring extends ROperator {
+ substring(){super("substring");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ int b = state.datapop().intValue();
+ int e = state.datapop().intValue();
+ String str2 = str.substring(b,e);
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( obj1 obj2 -- obj2 obj1 ) swaps the top two elements on the data stack
+ * @author paul snow
+ *
+ */
+ static class Swap extends ROperator {
+ Swap(){super("swap"); alias("exch");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.datapop();
+ IRObject obj2 = state.datapop();
+ state.datapush(obj1);
+ state.datapush(obj2);
+ }
+ }
+
+ /**
+ * ( obj1 -- obj1 obj2 )
+ * @author paul snow
+ *
+ */
+ static class Dup extends ROperator {
+ Dup(){super("dup");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.datapop();
+ state.datapush(obj1);
+ state.datapush(obj1);
+ }
+ }
+
+ static class Pop extends ROperator {
+ Pop(){
+ super("pop");
+ alias("drop");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapop();
+ }
+ }
+
+ /**
+ * (obj1 obj2 -- obj1 obj2 obj1 ) copies the element below the top.
+ * @author paul snow
+ *
+ */
+ static class Over extends ROperator {
+ Over(){super("over");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.getds(state.ddepth()-2);
+ state.datapush(obj1);
+ }
+ }
+
+ /**
+ * ( entity -- ) push the given entity onto the entity stack
+ * @author paul snow
+ *
+ */
+ static class Entitypush extends ROperator {
+ Entitypush(){super("entitypush");}
+
+ public void execute(DTState state) throws RulesException {
+ IREntity e = state.datapop().rEntityValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("entitypush", "value='"+e.stringValue()+"' id='"+e.getID()+"'");
+ }
+ state.entitypush(e);
+ }
+ }
+
+ /**
+ * ( -- ) pops the top element from the entity stack and tosses
+ * it into the bit bucket
+ * @author paul snow
+ *
+ */
+ static class Entitypop extends ROperator {
+ Entitypop(){super("entitypop");}
+
+ public void execute(DTState state) throws RulesException {
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("entitypop","");
+ }
+ state.entitypop();
+ }
+ }
+
+ /**
+ * Pushes a copy of the top entity on the entity stack on to the
+ * data stack.
+ * ( index -- element )
+ * @author paul snow
+ *
+ */
+ static class Entityfetch extends ROperator {
+ Entityfetch(){super("entityfetch");}
+ public void execute(DTState state) throws RulesException {
+ int i = state.datapop().intValue();
+ state.datapush(state.entityfetch(i));
+ }
+ }
+
+ /**
+ * Returns the top element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class I extends ROperator {
+ I(){super("i"); alias("r@");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-1));
+ }
+ }
+
+ /**
+ * Returns the second element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class J extends ROperator {
+ J(){super("j");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-2));
+ }
+ }
+
+ /**
+ * Returns the third element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class K extends ROperator {
+ K(){super("k");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-3));
+ }
+ }
+
+ /**
+ * ( obj -- ) Pops the top element from the data stack, and pushes
+ * it to the Control stack.
+ * @author paul snow
+ *
+ */
+ static class ToR extends ROperator {
+ ToR(){super(">r");}
+
+ public void execute(DTState state) throws RulesException {
+ state.cpush(state.datapop());
+ }
+ }
+
+ /**
+ * ( -- obj ) pops the top element from the control stack, and pushes
+ * it to the data stack.
+ * @author paul snow
+ *
+ */
+ static class FromR extends ROperator {
+ FromR(){super("r>");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.cpop());
+ }
+ }
+
+ /**
+ * ( name value -- )
+ * Binds the name with the value in the highest entity on the
+ * entity stack which is both writable, and has an entry with
+ * a writiable name that matches.
+ *
+ * @author paul snow
+ *
+ */
+ static class Def extends ROperator {
+ Def(){super("def");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RName name = state.datapop().rNameValue();
+ boolean f = state.def(name, value, true);
+ if(!f)throw new RulesException("Undefined",
+ "def",
+ name+" is undefined");
+ }
+ }
+ /**
+ * ( name -- obj )
+ * Looks up the name, and returns the value associated with
+ * the name in the top most entity that defines the name.
+ * Returns RNull if the name isn't found.
+ * @author paul snow
+ *
+ */
+ static class Find extends ROperator {
+ Find(){super("find");}
+
+ public void execute(DTState state) throws RulesException {
+ RName name = state.datapop().rNameValue();
+ IRObject v = state.find(name);
+ if(v==null)throw new RulesException("Undefined",
+ "find",
+ name+" is undefined");
+ }
+ }
+ /**
+ * ( obj -- ) Prints the top element of on the data stack to
+ * Standard Out.
+ * @author paul snow
+ *
+ */
+ static class Print extends ROperator {
+ Print(){super("print"); alias("debug"); }
+
+ public void execute(DTState state) throws RulesException {
+ state.debug(state.datapop().toString());
+ }
+ }
+
+ /**
+ * ( obj1 -- obj2 ) Creates a clone of the given object.
+ * @author paul snow
+ *
+ */
+ static class Clone extends ROperator {
+ Clone(){super("clone");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().clone(state.getSession()));
+ }
+ }
+
+ /**
+ * ( value name -- )
+ * Binds the name with the value in the highest entity on the
+ * entity stack which is both writable, and has an entry with
+ * a writiable name that matches.
+ *
+ * @author paul snow
+ *
+ */
+ static class Xdef extends ROperator {
+ Xdef(){super("xdef");}
+
+ public void execute(DTState state) throws RulesException {
+ RName name = state.datapop().rNameValue();
+ IRObject value = state.datapop();
+ boolean f = state.def(name, value, true);
+ if(!f)
+ if(state.find(name)==null){
+ throw new RulesException("Undefined",
+ "xdef",
+ name+" is undefined");
+ }else{
+ throw new RulesException("Write Protection",
+ "xdef",
+ name+" is Input only, and xdef attempted to write to it");
+ }
+ }
+ }
+
+ /**
+ * ( -- ) Prints all the elements on all the stacks non-distructively.
+ * This is purely a debugging aid.
+ * @author paul snow
+ *
+ */
+ static class PStack extends ROperator {
+ PStack(){super("pstack");}
+
+ public void execute(DTState state) throws RulesException {
+ state.pstack();
+ }
+ }
+
+ /**
+ * ( RName -- ) Creates an instance of the entity with the given name.
+ *
+ * @author paul snow
+ *
+ */
+ static class Createentity extends ROperator {
+ Createentity(){super("createentity");}
+
+ public void execute(DTState state) throws RulesException {
+ RName ename = state.datapop().rNameValue();
+ IREntity entity = ((RSession) state.getSession()).createEntity(null, ename);
+ state.datapush(entity);
+ }
+ }
+
+ /**
+ * ( Object -- Integer ) Converts to an Integer.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvi extends ROperator {
+ Cvi(){super("cvi");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ IRObject obj = v.rIntegerValue();
+ if(state.testState(DTState.TRACE)){
+ if(v.type()!= IRObject.iInteger){
+ state.traceInfo("cvi", "value='"+v+"'",obj.stringValue());
+ }
+ }
+ state.datapush(obj);
+ }
+ }
+ /**
+ * ( Object -- Double ) Converts to an Double.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvr extends ROperator {
+ Cvr(){super("cvr"); alias("cvd");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ IRObject obj = v.rDoubleValue();
+ if(state.testState(DTState.TRACE)){
+ if(v.type()!= IRObject.iDouble){
+ state.traceInfo("cvr", "value='"+v+"'",obj.stringValue());
+ }
+ }
+ state.datapush(obj);
+ }
+ }
+ /**
+ * ( Object -- Boolean ) Converts to an Boolean.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvb extends ROperator {
+ Cvb(){super("cvb");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().rBooleanValue());
+ }
+ }
+ /**
+ * ( Object -- Entity ) Converts to an Entity.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cve extends ROperator {
+ Cve(){super("cve");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ if(v.type()==IRObject.iNull){
+ state.datapush(v);
+ }else{
+ state.datapush(v.rEntityValue());
+ }
+ }
+ }
+ /**
+ * ( Object -- String ) Converts to a String.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvs extends ROperator {
+ Cvs(){super("cvs");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().rStringValue());
+ }
+ }
+ /**
+ * ( Object -- String ) Converts to a Name.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvn extends ROperator {
+ Cvn(){super("cvn");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj = state.datapop();
+ state.datapush(obj.rNameValue().getNonExecutable());
+ }
+ }
+ /**
+ * ( Object -- Date ) Converts to an Date.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvd extends ROperator {
+ Cvd(){super("cvd");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject datevalue = state.datapop();
+ state.datapush(datevalue.rTimeValue());
+ }
+ }
+
+ /**
+ * ( -- String ) Returns the Decision Table and Action number
+ *
+ * @author paul snow
+ *
+ */
+ static class ActionString extends ROperator {
+ ActionString(){super("actionstring");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( RString.newRString(
+ state.getCurrentTable().getName().stringValue()+" "+
+ state.getCurrentTableSection()+" "+
+ (state.getNumberInSection()+1)));
+ }
+ }
+ /**
+ * ( -- String ) Returns the Decision Table and Action number
+ *
+ * @author paul snow
+ *
+ */
+ static class GetDescription extends ROperator {
+ GetDescription(){super("getdescription");}
+
+ public void execute(DTState state) throws RulesException {
+ String section = state.getCurrentTableSection();
+ String description = "";
+ if(section.equalsIgnoreCase("action")){
+ RDecisionTable table = state.getCurrentTable();
+ description = table.getActionsComment()[state.getNumberInSection()];
+ }else if(section.equalsIgnoreCase("condition")){
+ RDecisionTable table = state.getCurrentTable();
+ description = table.getConditionsComment()[state.getNumberInSection()];
+ }
+ state.datapush( RString.newRString(description));
+ }
+ }
+ /**
+ * ( regex String -- boolean ) Returns true if the given string is matched
+ * by the given regular expression.
+ *
+ * @author Paul Snow
+ *
+ */
+ static class RegexMatch extends ROperator {
+ RegexMatch(){super("regexmatch");}
+
+ public void execute(DTState state) throws RulesException {
+ String string = state.datapop().stringValue();
+ String regex = state.datapop().stringValue();
+ boolean b = string.matches(regex);
+ state.datapush( RBoolean.getRBoolean(b));
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+
+/**
+ * This Class creates the primities entity in a rather cute way. The actual operators
+ * are for the most part extend ROperator and only supply a new execute() method. Each
+ * of these classes are defined as subclasses of the classes listed in the static
+ * section. They in turn have a static section that lists all of classes that implement
+ * the operators in their section.
+ * <br><br>
+ * Each operator calls the super constructor with their name, and the super constructor
+ * (defined here) creates the entry in the primitives entity for the operator.
+ *
+ * @author paul snow
+ *
+ */
+public class ROperator extends ARObject {
+
+ static final REntity primitives = new REntity(1,true,RName.getRName("primities",false));
+
+ static {
+ new RMath();
+ new RArrayOps();
+ new RControl();
+ new RBooleanOps();
+ new RMiscOps();
+ new RDateTimeOps();
+ new RTableOps();
+ new RXmlValueOps();
+ }
+
+ static public IREntity getPrimitives() {
+ return primitives;
+ }
+
+ final RName name;
+ public int type() { return iOperator; }
+
+ /**
+ * Puts another entry into the primitives entity under a different name. This is
+ * useful for operators that we would like to define under two names (such as "pop" and
+ * "drop".)
+ *
+ * This function also allows us to define constants such as "true" and "false" as objects
+ * rather than defining operators that return "true" and "false".
+ *
+ * @param o
+ * @param n
+ */
+ protected static void alias (IRObject o ,String n) {
+ try {
+ RName rn = RName.getRName(n);
+ primitives.addAttribute(rn, "", o, false, true, o.type(),null);
+ primitives.put(rn,o);
+ } catch (RulesException e) {
+ throw new RuntimeException("An Error occured in alias building the primitives Entity: "+n);
+ }
+ }
+
+ /**
+ * A method that makes it a bit easier to call the other alias function when I am
+ * creating an alias for an operator in its own constructor.
+ *
+ * @param n
+ */
+ protected void alias (String n){
+ alias(this,n);
+ }
+
+ /**
+ * All of the operators extend ROperator. They call the super constructor with their
+ * name as a string. Here we convert the name to an RName, set the name as a final
+ * field in the Operator, and create an entry in the primities entity for the
+ * operator.
+ * @param _name
+ */
+ public ROperator(String _name){
+ name = RName.getRName(_name,true);
+ try {
+ primitives.addAttribute(name, "", this,false, true,iOperator,null);
+ primitives.put(name,this);
+ } catch (RulesException e) {
+ throw new RuntimeException("An Error occured building the primitives Entity: "+name);
+ }
+ }
+
+ public boolean isExecutable() { return true; }
+
+ public String stringValue() {
+ return name.stringValue();
+ }
+
+ public String toString(){
+ return name.stringValue();
+ }
+
+ public String postFix(){
+ return name.stringValue();
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTable;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RSession;
+
+public class RTableOps {
+ static {
+ new Lookup(); new Set(); new GetKeys ();
+ new NewTable(); new SetDescription(); new Translate ();
+ }
+ /**
+ * ( table, index1, index2, ... lookup -- result )
+ * Does a lookup (of however many keys) and returns the result. An
+ * Error will be thrown if any index but the last fails to return
+ * an RTable object
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class Lookup extends ROperator {
+ Lookup(){ super("lookup");}
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0;
+ int d = state.ddepth();
+ while(state.getds(--d).type()!=iTable)cnt++;
+ RName []keys = new RName[cnt];
+ for(int i=0;i<cnt;i++){
+ keys[i]= state.datapop().rNameValue();
+ }
+ RTable rtable = state.datapop().rTableValue();
+ state.datapush(rtable.getValue(keys));
+ }
+ }
+
+ /**
+ * ( table, index1, index2, ... , indexN value set -- )
+ * Takes a table, and a set of indexes. The Nth index is used to
+ * set the value.
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class Set extends ROperator {
+ Set(){ super("set");}
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0; // We keep a count of the keys.
+ IRObject v = state.datapop(); // Get the value to store
+ int d = state.ddepth(); // Get current depth of data stack.
+
+ while(state.getds(--d).type()==iName)cnt++; // Count the keys (index1, index2, etc.)
+
+ RName []keys = new RName[cnt]; // Get an array big enough to hold the keys
+
+ for(int i=0;i<cnt;i++){ // Get all the keys off the data stack
+ keys[i]= state.datapop().rNameValue();
+ }
+
+ RTable rtable = state.datapop().rTableValue();
+
+ rtable.setValue(state,keys, v); // Set the value.
+ }
+ }
+ /**
+ * ( table getKeys -- Array ) Returns an array holding all the
+ * keys in a table.
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class GetKeys extends ROperator {
+ GetKeys(){ super("getkeys");}
+
+ public void execute(DTState state) throws RulesException {
+ RTable rtable = state.datapop().rTableValue();
+ state.datapush(rtable.getKeys(state));
+ }
+ }
+
+ /**
+ * ( Name Type -- Table ) newTable
+ * Name is a name for the table
+ */
+ static class NewTable extends ROperator {
+ NewTable(){ super("newtable");}
+
+ public void execute(DTState state) throws RulesException {
+ String type = state.datapop().stringValue();
+ RName name = state.datapop().rNameValue();
+ int itype = RSession.typeStr2Int(type,"","");
+ RTable table = RTable.newRTable(state.getSession().getEntityFactory(),name,"",itype);
+ state.datapush(table);
+ }
+ }
+
+ /**
+ * ( Table description -- ) setDescription
+ */
+ static class SetDescription extends ROperator {
+ SetDescription() { super("setdescription"); }
+ public void execute(DTState state) throws RulesException {
+ RString description = state.datapop().rStringValue();
+ RTable table = state.datapop().rTableValue();
+ table.setDescription(description);
+ }
+ }
+ /**
+ * ( Table keyArray boolean -- valueArray ) translate
+ * All the keys provided by the keyArray are looked up in the
+ * given Table. If a key is not found in the table, it is
+ * ignored. If a key is found, then that value is added to
+ * the valueArray.
+ *
+ * If the boolean is true, then duplicates are allowed in
+ * the valueArray. If boolean is false, then only unique
+ * values are returned.
+ *
+ * @author paul snow
+ *
+ */
+ static class Translate extends ROperator {
+ Translate(){super("translate"); }
+ public void execute(DTState state) throws RulesException {
+ boolean duplicates = state.datapop().booleanValue();
+ RArray keys = state.datapop().rArrayValue();
+ RTable table = state.datapop().rTableValue();
+ RArray valueArray = new RArray(state.getSession().getUniqueID(),duplicates,false);
+ for(IRObject irkey : keys){
+ RName key = irkey.rNameValue();
+ if(table.containsKey(key)){
+ valueArray.add(table.getValue(key));
+ }
+ }
+ state.datapush(valueArray);
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings("unchecked")
+public class RXmlValueOps {
+ static {
+ new SetXmlAttribute();
+ new GetXmlAttribute();
+ }
+
+ /**
+ * SetXmlAttribute ( XmlValue Attribute Value --> )
+ * Addto Operator, adds an element to an array
+ * @author Paul Snow
+ *
+ */
+ static class SetXmlAttribute extends ROperator {
+ SetXmlAttribute(){super("setxmlattribute");}
+
+ @Override
+ public void execute(DTState state) throws RulesException {
+ String value = state.datapop().stringValue();
+ String attribute = state.datapop().stringValue();
+ XMLTag xmlTag = state.datapop().xmlTagValue();
+
+ state.traceInfo("SetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' value='"+value+"'");
+
+ xmlTag.getAttribs().put(attribute, value);
+ }
+ }
+ /**
+ * GetXmlAttribute ( XmlValue Attribute --> Value )
+ * Get the value of the given attribute from this XmlValue.
+ * If the attribute is not defined, a null is returned.
+ * @author Paul Snow
+ *
+ */
+ static class GetXmlAttribute extends ROperator {
+ GetXmlAttribute(){super("getxmlattribute");}
+
+ @Override
+ public void execute(DTState state) throws RulesException {
+ String attribute = state.datapop().stringValue();
+ XMLTag xmlTag = state.datapop().xmlTagValue();
+
+ String value = (String) xmlTag.getAttribs().get(attribute);
+ if(value != null ){
+ state.datapush(RString.newRString(value));
+ state.traceInfo("GetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' value='"+value+"'");
+ }else{
+ state.datapush(RNull.getRNull());
+ state.traceInfo("GetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' null='true'");
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.ArrayList;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RMark;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings("unchecked")
+public class RArrayOps {
+ static {
+ new Addto();
+ new Addat();
+ new Remove();
+ new Removeat();
+ new Getat();
+ new Newarray();
+ new Length();
+ new Memberof();
+ new Mark();
+ new Arraytomark();
+ new Copyelements();
+ new Sortarray();
+ new Sortentities();
+ new Add_no_dups();
+ new Clear();
+ new Merge();
+ new Randomize();
+ new AddArray();
+ new Tokenize();
+ }
+ /**
+ * tokenize ( String1 String2 --> array )
+ * String1 is a string to tokenize
+ * String2 is a regular expression defining these tokens
+ * array is an array of strings that results when String1 is tokenized.
+ * @author ps24876
+ *
+ */
+ static class Tokenize extends ROperator {
+ Tokenize(){super("tokenize");}
+
+ public void execute(DTState state) throws RulesException {
+
+ String pattern = state.datapop().stringValue();
+ IRObject obj1 = state.datapop();
+ String v = "";
+ if(obj1.type() != IRObject.iNull){
+ v = obj1.stringValue().trim();
+ }
+ String [] results = v.split(pattern);
+
+ RArray r = new RArray(state.getSession().getUniqueID(),false,false);
+ for(String t : results){
+ r.add(RString.newRString(t));
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayID='"+r.getID()+"'","'"+t+"'");
+ }
+ }
+ state.datapush(r);
+ }
+ }
+
+
+ /**
+ * addto( Array Value --> )
+ * Addto Operator, adds an element to an array
+ * @author Paul Snow
+ *
+ */
+ static class Addto extends ROperator {
+ Addto(){super("addto");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RArray rarray = state.datapop().rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayID='"+rarray.getID()+"'",value.postFix());
+ }
+ rarray.add(value);
+ }
+ }
+
+ /**
+ * addat( Array int Value --> )
+ * Addat Operator, adds an element to an array at the given location
+ */
+ static class Addat extends ROperator {
+ Addat() {super("addat");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ int position = state.datapop().intValue();
+ RArray rarray = state.datapop().rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addat", "arrayID='"+rarray.getID()+"' index="+position+"'",value.postFix());
+ }
+ rarray.add(position, value);
+
+ }
+ }
+
+ /**
+ * remove( Array Value --> boolean )
+ * Remove Operator, removes all elements from an array that match the value. Returns a
+ * true if at least one element was removed, and a false otherwise.
+ */
+ static class Remove extends ROperator {
+ Remove() {super("remove");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RArray rarray = (RArray)state.datapop();
+ ArrayList array = rarray.arrayValue();
+ boolean removed = false;
+ if(value!=null){
+ for(int i=0; i<array.size();){
+ if(value.equals((IRObject)array.get(i))){
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("removed", "arrayID='"+rarray.getID()+"'",value.postFix());
+ }
+ array.remove(i);
+ removed = true;
+ } else {
+ i++;
+ }
+ }
+ }
+ state.datapush(RBoolean.getRBoolean(removed)); // Return indicater that something was removed.
+ }
+ }
+
+ /**
+ * removeat( Array int --> boolean )
+ * Removeat Operator, removes an element from an
+ * array at the given location. Returns true upon
+ * success
+ */
+ static class Removeat extends ROperator {
+ Removeat() {super("removeat");}
+
+ public void execute(DTState state) throws RulesException {
+ int position = state.datapop().intValue();
+ RArray rarray = (RArray)state.datapop();
+ if(position >= rarray.size()){
+ state.datapush(RBoolean.getRBoolean(false));
+ }
+
+ ArrayList array = rarray.arrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("removed", "arrayID='"+rarray.getID()+"' position='"+position+"'");
+ }
+
+ array.remove(position);
+ state.datapush(RBoolean.getRBoolean(true));
+ }
+ }
+
+ /**
+ * getat( Array int --> value)
+ * Getat Operator, gets an element from an array at the given location
+ */
+ static class Getat extends ROperator {
+ Getat() {super("getat");}
+
+ public void execute(DTState state) throws RulesException {
+ int position = state.datapop().intValue();
+ ArrayList array = state.datapop().arrayValue();
+ state.datapush((IRObject)array.get(position));
+ }
+ }
+
+ /**
+ * newarray( --> Array)
+ * Newarray Operator, returns a new empty array
+ */
+ static class Newarray extends ROperator {
+ Newarray() {super("newarray");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject irobject = new RArray(state.getSession().getUniqueID(),true, false);
+ state.datapush(irobject);
+ }
+ }
+
+ /**
+ * length( Array --> int)
+ * Length Operator, returns the size of the array
+ */
+ static class Length extends ROperator {
+ Length() {super("length");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList array = state.datapop().arrayValue();
+ state.datapush(RInteger.getRIntegerValue(array.size()));
+ }
+ }
+
+ /**
+ * memberof( Array Value --> boolean)
+ * Memberof Operator, returns true if the element found in the array
+ */
+ static class Memberof extends ROperator {
+ Memberof() {super("memberof");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ ArrayList array = state.datapop().arrayValue();
+ boolean found = false;
+ if(value!=null){
+ for(int i=0; i<array.size(); i++){
+ if(value.equals((IRObject)array.get(i))){
+ found=true;
+ break;
+ }
+ }
+ }
+ state.datapush(RBoolean.getRBoolean(found));
+ }
+ }
+
+ /**
+ * copyelements( Array --> newarray)
+ * Copyelements Operator, returns the copy of the array
+ */
+ static class Copyelements extends ROperator {
+ Copyelements() {super("copyelements");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray rarray = state.datapop().rArrayValue();
+ RArray newRArray = rarray.clone(state.getSession()).rArrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("copyelements", "id='"+rarray.getID()+"' newarrayid='"+newRArray.getID()+"'");
+ for(IRObject v : newRArray){
+ state.traceInfo("addto", "arrayID='"+rarray.getID()+"'",v.postFix());
+ }
+ }
+
+ state.datapush(newRArray);
+
+ }
+ }
+
+ /**
+ * sortarray( Array boolean --> )
+ * Sortarray Operator, sorts the array elements (asc is boolean is true)
+ */
+ static class Sortarray extends ROperator {
+ Sortarray() {super("sortarray");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean asc = state.datapop().booleanValue();
+ int direction = asc ? 1 : -1;
+
+ RArray rarray = state.datapop().rArrayValue();
+ ArrayList<IRObject> array = rarray.arrayValue();
+
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("sort", "length='"+array.size()+"' arrayID='"+rarray.getID()+"'",asc ? "true" : "false");
+ }
+
+ IRObject temp = null;
+ int size = array.size();
+ for(int i=0; i<size-1; i++){
+ for(int j=0; j<size-1-i; j++){
+ if(((IRObject)array.get(j+1)).compare((IRObject)array.get(j)) == direction){
+ temp = (IRObject)array.get(j);
+ array.set(j, (IRObject)array.get(j+1));
+ array.set(j+1, temp);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * randomize ( Array --> )
+ * Randomizes the order in the given array.
+ */
+ static class Randomize extends ROperator {
+ Randomize() {
+ super("randomize");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList<IRObject> array = state.datapop().arrayValue();
+ IRObject temp = null;
+ int size = array.size();
+ for(int i=0; i<10; i++){
+ for(int j=0; j<size; j++){
+ int x = state.rand.nextInt(size);
+ temp = (IRObject)array.get(j);
+ array.set(j, (IRObject)array.get(x));
+ array.set(x, temp);
+ }
+ }
+ }
+ }
+
+ /**
+ * sortentities( Array field boolean --> )
+ * Sortentities Operator,
+ */
+ static class Sortentities extends ROperator {
+ Sortentities() {super("sortentities");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean asc = state.datapop().booleanValue();
+ RName rname = state.datapop().rNameValue();
+ RArray rarray = state.datapop().rArrayValue();
+ ArrayList<IRObject> array = rarray.arrayValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("sortentities",
+ "length='"+array.size()+
+ "' by='"+rname.stringValue()+
+ "' arrayID='"+rarray.getID()+"'",
+ asc ? "true" : "false");
+ }
+ REntity temp = null;
+ int size = array.size();
+ int greaterthan = asc ? 1 : -1;
+ for(int i=0; i<size; i++){
+ boolean done = true;
+ for(int j=0; j<size-1-i; j++){
+ try {
+ if((((REntity)array.get(j)).get(rname)).compare(((REntity)array.get(j+1)).get(rname))==greaterthan){
+ temp = (REntity)array.get(j);
+ array.set(j, (REntity)array.get(j+1));
+ array.set(j+1, temp);
+ done = false;
+ }
+ }catch(RuntimeException e){
+ throw new RulesException("undefined","sort","Field is undefined: "+rName);
+ }
+ }
+ if(done)return;
+ }
+ }
+ }
+
+ /**
+ * add_no_dups( Array item --> )
+ * Add_no_dups Operator, adds an element to an array if it is not present
+ */
+ static class Add_no_dups extends ROperator {
+ Add_no_dups(){super("add_no_dups");}
+
+ public void execute(DTState state) throws RulesException {
+
+ IRObject value = state.datapop();
+ RArray rArray = (RArray) state.datapop();
+ ArrayList array = rArray.arrayValue();
+ for(int i=0; i<array.size(); i++){
+ if(value.equals((IRObject)array.get(i))){
+ return;
+ }
+ }
+ array.add(value);
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("addto", "arrayId='"+rArray.getID()+"'",value.postFix());
+ }
+
+ }
+ }
+
+ /**
+ * clear( Array --> )
+ * Clear Operator, removes all elements from the array
+ */
+ static class Clear extends ROperator {
+ Clear(){super("clear");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject rarray = state.datapop();
+ ArrayList array = rarray.arrayValue();
+ array.clear();
+ if (state.testState(DTState.TRACE)){
+ state.traceInfo("clear", "array='"+rarray.stringValue()+"'");
+ }
+ }
+ }
+
+ /**
+ * merge( Array Array--> Array)
+ * Merge Operator, merges two array to one (Array1 elements followed by Array2 elements)
+ */
+ static class Merge extends ROperator {
+ Merge(){super("merge");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList array2 = state.datapop().arrayValue();
+ ArrayList array1 = state.datapop().arrayValue();
+ ArrayList newarray = new ArrayList();
+ newarray.addAll(array1);
+ newarray.addAll(array2);
+ state.datapush(new RArray(state.getSession().getUniqueID(),false,newarray, false));
+ }
+ }
+
+ /**
+ * Mark ( -- mark ) pushes a mark object onto the data stack.
+ *
+ */
+ static class Mark extends ROperator {
+ Mark(){super("mark");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RMark.getMark());
+ }
+ }
+
+ /**
+ * arraytomark ( mark obj obj ... -- array ) creates an array out
+ * of the elements on the data stack down to the first mark.
+ *
+ */
+ static class Arraytomark extends ROperator {
+ Arraytomark(){super("arraytomark");}
+
+ public void execute(DTState state) throws RulesException {
+ int im = state.ddepth()-1; // Index of top of stack
+ while(im>=0 && state.getds(im).type()!=iMark)im--; // Index of mark
+ RArray newarray = new RArray(state.getSession().getUniqueID(),true,false); // Create a new array
+ int newdepth = im++; // skip the mark (remember its index)
+ while(im<state.ddepth()){ // copy elements to the array
+ newarray.add(state.getds(im++));
+ }
+ while(newdepth < state.ddepth())state.datapop(); // toss elements AND mark
+ state.datapush(newarray); // push the new array.
+ }
+ }
+
+
+ /**
+ * ( array1 array2 boolean -- ) Adds all the elements of array1 to array2. If
+ * the boolean is true, then no duplicates are added to array2. If false, all elements
+ * (duplicate or not) are added to array2
+ *
+ */
+ static class AddArray extends ROperator {
+ AddArray(){super("addarray");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean dups = state.datapop().booleanValue();
+ RArray a2 = state.datapop().rArrayValue();
+ RArray a1 = state.datapop().rArrayValue();
+
+ for(IRObject o : a1){
+ if(dups || !a2.contains(o)){
+ a2.add(o);
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+
+/**
+ * Boolean Operators
+ * @author anand b
+ */
+public class RBooleanOps {
+
+ static {
+ ROperator.alias(RBoolean.getRBoolean(true),"true");
+ ROperator.alias(RBoolean.getRBoolean(false),"false");
+ new Not();
+ new And();
+ new Or();
+ new Greaterthan();
+ new Lessthan();
+ new Greaterthanequal();
+ new Lessthanequal();
+ new Equal();
+ new FGreaterthan();
+ new FLessthan();
+ new FGreaterthanequal();
+ new FLessthanequal();
+ new FEqual();
+ new Isnull();
+ new Booleanequal();
+ new Booleannotequal();
+ new SGreaterthan();
+ new SLessthan();
+ new SGreaterthanequal();
+ new SLessthanequal();
+ new SEqual();
+ new SEqualIgnoreCase();
+ new SConcat();
+ new Strremove();
+ new Req();
+ }
+
+ /**
+ * not( Boolean -- ~boolean )
+ * Not Operator, returns the negation of the input value
+ *
+ */
+ static class Not extends ROperator {
+ Not(){super("not");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(!(state.datapop().booleanValue())));
+ }
+ }
+
+ /**
+ * And( Boolean1 Boolean2 -- Boolean3 )
+ * And Operator, returns the && value of two booleans
+ *
+ */
+ static class And extends ROperator {
+ And(){super("&&"); alias("and");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean v2 = state.datapop().booleanValue();
+ boolean v1 = state.datapop().booleanValue();
+
+ state.datapush(RBoolean.getRBoolean(v1 && v2));
+ }
+ }
+
+ /**
+ * Or( Boolean1 Boolean2 -- Boolean3 )
+ * And Operator, returns the || value of two booleans
+ */
+ static class Or extends ROperator {
+ Or(){super("||");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue() || state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * Greaterthan( Number Number -- Boolean )
+ * Greaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Greaterthan extends ROperator {
+ Greaterthan(){super(">");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject o2 = state.datapop();
+ IRObject o1 = state.datapop();
+ long number2 = o2.longValue();
+ long number1 = o1.longValue();
+ state.datapush(RBoolean.getRBoolean(number1 > number2));
+ }
+ }
+
+ /**
+ * Lessthan( Number Number -- Boolean )
+ * Lessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Lessthan extends ROperator {
+ Lessthan(){super("<");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 < number2));
+ }
+ }
+
+ /**
+ * Greaterthanequal( Number Number -- Boolean )
+ * Greaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Greaterthanequal extends ROperator {
+ Greaterthanequal(){super(">=");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 >= number2));
+ }
+ }
+
+ /**
+ * Lessthanequal( Number Number -- Boolean )
+ * Lessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Lessthanequal extends ROperator {
+ Lessthanequal(){super("<=");}
+
+ public void execute(DTState state) throws RulesException {
+ long number2 = state.datapop().longValue();
+ long number1 = state.datapop().longValue();
+ state.datapush(RBoolean.getRBoolean(number1 <= number2));
+ }
+ }
+
+ /**
+ * Equal( Number Number -- Boolean )
+ * Lessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class Equal extends ROperator {
+ Equal(){super("==");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().longValue() == state.datapop().longValue()));
+ }
+ }
+
+ /**
+ * FGreaterthan( Number Number -- Boolean )
+ * FGreaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FGreaterthan extends ROperator {
+ FGreaterthan(){super("f>");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 > number2));
+ }
+ }
+
+ /**
+ * FLessthan( Number Number -- Boolean )
+ * FLessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FLessthan extends ROperator {
+ FLessthan(){super("f<");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 < number2));
+ }
+ }
+
+ /**
+ * FGreaterthanequal( Number Number -- Boolean )
+ * FGreaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FGreaterthanequal extends ROperator {
+ FGreaterthanequal(){super("f>=");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 >= number2));
+ }
+ }
+
+ /**
+ * FLessthanequal( Number Number -- Boolean )
+ * FLessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FLessthanequal extends ROperator {
+ FLessthanequal(){super("f<=");}
+
+ public void execute(DTState state) throws RulesException {
+ double number2 = state.datapop().doubleValue();
+ double number1 = state.datapop().doubleValue();
+ state.datapush(RBoolean.getRBoolean(number1 <= number2));
+ }
+ }
+
+ /**
+ * FEqual( Number Number -- Boolean )
+ * FEqual Operator, returns the boolean value for condition with the given parameters
+ */
+ static class FEqual extends ROperator {
+ FEqual(){super("f==");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().doubleValue() == state.datapop().doubleValue()));
+ }
+ }
+
+ /**
+ * Isnull(object -- Boolean )
+ * Isnull Operator, returns true if the object is null
+ */
+ static class Isnull extends ROperator {
+ Isnull(){super("isnull");}
+
+ public void execute(DTState state) throws RulesException
+ {
+ state.datapush(RBoolean.getRBoolean(state.datapop().type()==IRObject.iNull));
+ }
+ }
+
+ /**
+ * Booleanequal(boolean1 boolean2 -- Boolean )
+ * Booleanequal Operator, returns true if both are equal
+ */
+ static class Booleanequal extends ROperator {
+ Booleanequal(){super("b="); alias("beq");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue()==state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * Booleannotequal(boolean1 boolean2 -- Boolean )
+ * Booleannotequal Operator, returns true if both are not equal
+ */
+ static class Booleannotequal extends ROperator {
+ Booleannotequal(){super("b!=");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RBoolean.getRBoolean(state.datapop().booleanValue()!=state.datapop().booleanValue()));
+ }
+ }
+
+ /**
+ * SGreaterthan( String String -- Boolean )
+ * SGreaterthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SGreaterthan extends ROperator {
+ SGreaterthan(){super("s>");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)>0));
+ }
+ }
+
+ /**
+ * SLessthan( String String -- Boolean )
+ * SLessthan Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SLessthan extends ROperator {
+ SLessthan(){super("s<");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)< 0));
+ }
+ }
+
+ /**
+ * SGreaterthanequal( String String -- Boolean )
+ * SGreaterthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SGreaterthanequal extends ROperator {
+ SGreaterthanequal(){super("s>=");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)>=0));
+ }
+ }
+
+ /**
+ * SLessthanequal( String String -- Boolean )
+ * SLessthanequal Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SLessthanequal extends ROperator {
+ SLessthanequal(){super("s<=");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.compareTo(value2)<=0));
+ }
+ }
+
+ /**
+ * SEqual( String String -- Boolean )
+ * SEqual Operator, returns the boolean value for condition with the given parameters
+ */
+ static class SEqual extends ROperator {
+ SEqual(){super("s=="); alias("streq");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.equals(value2)));
+ }
+ }
+
+ /**
+ * SEqualIgnoreCase( String String -- Boolean )
+ * Same as SEqual Operator, only ignores the case.
+ * Returns the boolean value for condition with the given parameters
+ */
+ static class SEqualIgnoreCase extends ROperator {
+ SEqualIgnoreCase(){super("sic=="); alias("streqignorecase");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RBoolean.getRBoolean(value1.equalsIgnoreCase(value2)));
+ }
+ }
+
+
+
+ /**
+ * StrConcat( String String -- String )
+ * StrConcat Operator, add the given two strings and returns a string value
+ */
+ static class SConcat extends ROperator {
+ SConcat(){super("s+"); alias("strconcat");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RString.newRString(value1+value2));
+ }
+ }
+
+ /**
+ * Strremove( String1 String2 -- String3 )
+ * Strremove Operator, removes string2 from string1 and returns string3
+ */
+ static class Strremove extends ROperator {
+ Strremove(){super("strremove");}
+
+ public void execute(DTState state) throws RulesException {
+ String value2 = state.datapop().stringValue();
+ String value1 = state.datapop().stringValue();
+ state.datapush(RString.newRString(value1.replaceAll(value2, "")));
+ }
+ }
+
+ /**
+ * Req( object1 object2 -- Boolean )
+ * Req Operator, compares the two objects using equals and returns the boolean value
+ */
+ static class Req extends ROperator {
+ Req(){super("req");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value2 = state.datapop();
+ IRObject value1 = state.datapop();
+ state.datapush(RBoolean.getRBoolean(value1.equals(value2)));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+/**
+ * Defines math operators.
+ * @author paul snow
+ *
+ */
+@SuppressWarnings("unchecked")
+public class RControl {
+ static {
+ new If(); new Ifelse(); new While();
+ new Forallr(); new Forall(); new For();
+ new Forr(); new Entityforall(); new Forfirst();
+ new Doloop(); new ForFirstElse(); new ExecuteTable();
+ new Execute(); new Deallocate(); new Allocate();
+ new Localfetch(); new Localstore();
+ }
+
+ /**
+ * ( body boolean -- ) executes the body if the boolean is true.
+ * @author paul snow
+ *
+ */
+ static class If extends ROperator {
+ If(){super("if");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean test = state.datapop().booleanValue();
+ IRObject body = state.datapop();
+ if(test)body.execute(state);
+ }
+ }
+ /**
+ * ( truebody falsebody test -- ) Executes truebody if the boolean test is true, otherwise
+ * executes falsebody.
+ * @author paul snow
+ *
+ */
+ static class Ifelse extends ROperator {
+ Ifelse(){super("ifelse");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean test = state.datapop().booleanValue();
+ IRObject falsebody = state.datapop();
+ IRObject truebody = state.datapop();
+ if(test){
+ truebody.execute(state);
+ }else{
+ falsebody.execute(state);
+ }
+ }
+ }
+
+ /**
+ * This is an internal operator which doesn't have any use outside of the
+ * Rules Engine itself. It is used to execute the conditions and actions
+ * for a table within the context as defined in the table.
+ *
+ * ( DecisionTableName -- ) Takes the DecisionTable name and looks it up
+ * in the decisiontable entity. It then executes the table within that
+ * decision table. Because of this extra lookup, this path shouldn't be
+ * used unless there actually is a context to be executed.
+ *
+ * @author paul snow
+ *
+ */
+ static class ExecuteTable extends ROperator {
+ ExecuteTable(){super("executetable");}
+
+ public void execute(DTState state) throws RulesException {
+ RName dtname = state.datapop().rNameValue();
+ state.getSession().getEntityFactory().getDecisionTable(dtname).executeTable(state);
+ }
+ }
+ /**
+ * ( RObject -- ? ) Executes the object on the top of the data stack.
+ * The behavior of this operator is defined by the object executed. Usually
+ * the data stack will be left clean.
+ * @author paul snow
+ *
+ */
+ static class Execute extends ROperator {
+ Execute(){super("execute"); }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapop().getExecutable().execute(state);
+ }
+ }
+
+ /**
+ * ( body test -- ) executes test. If test returns true, executes body.
+ * Repeats until the test returns false.
+ *
+ * @author paul snow
+ *
+ */
+ static class While extends ROperator {
+ While(){super("while");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject test = state.datapop(); // Get the test
+ IRObject body = state.datapop(); // Get the body
+
+ test.execute(state); // evaluate the test
+ while(state.datapop().booleanValue()){ // If true, keep looping
+ body.execute(state); // execute the body.
+ test.execute(state); // check the test again.
+ }
+
+
+ }
+ }
+ /**
+ * ( body array -- ) Execute the body for each entity in the array.
+ * executes backwards through the array, and the entity can be removed
+ * from the array by the body.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forallr extends ROperator {
+ Forallr(){super("forallr");}
+
+ public void execute(DTState state) throws RulesException {
+
+ ArrayList array = state.datapop().arrayValue(); // Get the array
+ int length = array.size(); // get Array length.
+ IRObject body = state.datapop(); // Get the body
+ for(int i=length - 1;i>=0;i--){ // For each element in array,
+ IRObject o = (IRObject) array.get(i);
+ int t = o.type();
+ if(t== iNull)continue;
+ if(t!=iEntity){
+ throw new RulesException("Type Check", "Forallr", "Encountered a non-Entity entry in array: "+o);
+ }
+ state.entitypush((IREntity) o);
+ body.execute(state);
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body array -- ) executes the body for each entity in the array. Uses an
+ * Iterator and executes forward in the array. The entity cannot be removed from
+ * the array by the body.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forall extends ROperator {
+ Forall(){super("forall");}
+
+ public void execute(DTState state) throws RulesException {
+
+ RArray array = state.datapop().rArrayValue();
+ IRObject body = state.datapop(); // Get the body
+
+ for(IRObject o : array){
+ int t = o.type();
+ if(t== iNull)continue;
+ if(t!=iEntity){
+ throw new RulesException("Type Check", "Forallr", "Encountered a non-Entity entry in array: "+o);
+ }
+ state.entitypush((IREntity) o);
+ body.execute(state);
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body array -- ) Pushes each element on to the data stack, then executes the body.
+ * @author paul snow
+ *
+ */
+ static class For extends ROperator {
+ For(){super("for");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray list = state.datapop().rArrayValue();
+ IRObject body = state.datapop(); // Get the body
+ for(IRObject o : list){
+ state.datapush(o);
+ body.execute(state);
+ }
+ }
+ }
+ /**
+ * ( body array -- ) pushes each element on to the data stack, then executes the body.
+ * Because the array is evaluated in reverse order, the element can be removed from the
+ * array if you care to.
+ *
+ * @author paul snow
+ *
+ */
+ static class Forr extends ROperator {
+ Forr(){super("forr");}
+
+ public void execute(DTState state) throws RulesException {
+ ArrayList<IRObject> array = state.datapop().arrayValue(); // Get the array
+ int length = array.size(); // get Array length.
+ IRObject body = state.datapop(); // Get the body
+ for(int i=length-1;i>=0;i++){ // For each element in array,
+ IRObject o = (IRObject) array.get(i);
+ state.datapush((IRObject) o);
+ body.execute(state);
+ }
+ }
+ }
+ /**
+ * ( body entity -- ) Executes the body for each key value pair in the Entity.
+ *
+ * @author paul snow
+ *
+ */
+ static class Entityforall extends ROperator {
+ Entityforall(){super("entityforall");}
+
+ public void execute(DTState state) throws RulesException {
+ IREntity entity = state.datapop().rEntityValue(); // Get the entity
+ IRObject body = state.datapop(); // Get the body
+ Iterator keys = entity.getAttributeIterator(); // Get the Attribute Iterator
+ while(keys.hasNext()){ // For each attribute
+ RName n = (RName) keys.next();
+ IRObject v = entity.get(n);
+ if(v!=null){
+ state.datapush(n);
+ state.datapush(v);
+ body.execute(state);
+ }
+ }
+ }
+ }
+ /**
+ * ( body test array -- )
+ * Each entity within the array is placed on the entity stack. The test is evaluated, which should
+ * return the boolean. If true, the body is executed, and the loop stops.
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class Forfirst extends ROperator {
+ Forfirst(){super("forfirst");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray array = state.datapop().rArrayValue();
+ IRObject test = state.datapop();
+ IRObject body = state.datapop();
+ Iterator<REntity> ie = array.getIterator();
+ while(ie.hasNext()){
+ state.entitypush(ie.next());
+ test.execute(state);
+ if(state.datapop().booleanValue()){
+ body.execute(state);
+ state.entitypop();
+ return;
+ }
+ state.entitypop();
+ }
+ }
+ }
+
+ /**
+ * ( body1 body2 test array -- )
+ * Each entity within the array is placed on the entity stack. The test is
+ * evaluated, which should return the boolean. If true, the body1 is executed,
+ * and the loop stops. If no match is found, body2 is executed. Kinda a
+ * default operation.
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class ForFirstElse extends ROperator {
+ ForFirstElse(){super("forfirstelse");}
+
+ public void execute(DTState state) throws RulesException {
+ RArray array = state.datapop().rArrayValue();
+ IRObject test = state.datapop();
+ IRObject body2 = state.datapop();
+ IRObject body1 = state.datapop();
+ for(IRObject obj : array) {
+ IREntity e = obj.rEntityValue();
+ state.entitypush(e);
+ test.execute(state);
+ if(state.datapop().booleanValue()){
+ body1.execute(state);
+ state.entitypop();
+ return;
+ }
+ state.entitypop();
+ }
+ body2.execute(state);
+ }
+ }
+
+ /**
+ * ( body start increment limit -- ) Starts the index with the value "start". If the
+ * increment is positive and start is below the limit, the index
+ * is pushed and body is executed, then the index is incremented
+ * by increment. If the increment is negative and stat is above
+ * the limit, then the index is pushed and the body is executed,
+ * then the index is decremented by the increment. This continues
+ * until the limit is reached.
+ *
+ * @author paul snow
+ * Jan 10, 2007
+ *
+ */
+ static class Doloop extends ROperator {
+ Doloop(){super("doloop");}
+
+ public void execute(DTState state) throws RulesException {
+ int limit = state.datapop().intValue();
+ int increment = state.datapop().intValue();
+ int start = state.datapop().intValue();
+ IRObject body = state.datapop();
+ if(increment>0){
+ for(int i = start;i<limit;i+=increment){
+ state.cpush(RInteger.getRIntegerValue(i));
+ body.execute(state);
+ state.cpop();
+ }
+ }else{
+ for(int i = start;i>limit;i+=increment){
+ state.cpush(RInteger.getRIntegerValue(i));
+ body.execute(state);
+ state.cpop();
+ }
+ }
+ }
+ }
+ /**
+ * ( value -- )
+ * Allocates storage for a local variable. The value is the initial
+ * value for that variable. In all reality, this is just a push of
+ * a value to the control stack.
+ * @author paul snow
+ *
+ */
+ static class Allocate extends ROperator {
+ Allocate(){super("allocate"); alias("cpush");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("allocate", "value='"+v.stringValue()+"'");
+ }
+ state.cpush(v);
+ }
+ }
+
+ /**
+ * ( -- value )
+ * Deallocates storage for a local variable. In all reality, this is
+ * just a pop of a value from the control stack.
+ *
+ * @author paul snow
+ *
+ */
+ static class Deallocate extends ROperator {
+ Deallocate(){super("deallocate"); alias("cpop");}
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.cpop());
+ }
+ }
+ /**
+ * ( index -- IRObject ) fetches the value from the local variable
+ * specified by the given index. This is an offset from the currentframe.
+ * @author paul snow
+ *
+ */
+ static class Localfetch extends ROperator {
+ Localfetch(){super("local@");}
+
+ public void execute(DTState state) throws RulesException {
+ int index = state.datapop().intValue();
+ IRObject value = state.getFrameValue(index);
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("local_fetch", "index='"+index+"' value='"+value.stringValue()+"'");
+ }
+ state.datapush(value);
+ }
+ }
+ /**
+ * (value index -- ) stores the value into the local variable specified
+ * by the given index. The index is an offset from the currentframe.
+ * @author paul snow
+ *
+ */
+ static class Localstore extends ROperator {
+ Localstore(){super("local!");}
+
+ public void execute(DTState state) throws RulesException {
+ int index = state.datapop().intValue();
+ IRObject value = state.datapop();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("local_store", "index='"+index+"' value='"+value.stringValue()+"'");
+ }
+ state.setFrameValue(index, value);
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+
+/**
+ * Boolean Operators
+ * @author anand b
+ */
+public class RDateTimeOps {
+
+ static {
+ new Newdate();
+ new SetCalendar();
+ new Yearof();
+ new Getdaysinyear();
+ new Getdaysinmonth();
+ new Getdayofmonth();
+ new Datelt();
+ new Dategt();
+ new Dateeq();
+ new Gettimestamp();
+ new Days();
+ new DatePlus();
+ new DateMinus();
+ new FirstOfMonth();
+ new FirstOfYear();
+ new AddYears();
+ new AddMonths();
+ new AddDays();
+ new EndOfMonth();
+ new YearsBetween();
+ new DaysBetween();
+ new MonthsBetween();
+ }
+
+ /**
+ * Newdate( String -- Date )
+ * Newdate Operator, returns the Date object for the String value
+ *
+ */
+ static class Newdate extends ROperator {
+ Newdate(){super("newdate");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RTime.getRTime(java.sql.Date.valueOf(state.datapop().stringValue())));
+ }
+ }
+
+ /**
+ * Days( number -- Date )
+ * Returns a Date object holding this number of days.
+ *
+ */
+ static class Days extends ROperator {
+ Days(){super("days");}
+
+ public void execute(DTState state) throws RulesException {
+ int days = state.datapop().intValue();
+ long time = days * 24* 60 * 60 * 1000;
+ state.datapush(RTime.getRTime(new Date(time)));
+ }
+ }
+
+ /**
+ * FirstOfMonth ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the month.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class FirstOfMonth extends ROperator {
+ FirstOfMonth(){super("firstofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(Calendar.DAY_OF_MONTH, 1);
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * FirstOfYear ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the year.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class FirstOfYear extends ROperator {
+ FirstOfYear(){super("firstofyear");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(Calendar.DAY_OF_MONTH, 1);
+ state.calendar.set(Calendar.MONTH, 0);
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * EndOfMonth ( date -- date2)
+ * Given a date, returns date2 pointing to the first of the month.
+ * So given 2/23/07 would return 2/1/07
+ */
+ static class EndOfMonth extends ROperator {
+ EndOfMonth(){super("endofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.set(
+ Calendar.DAY_OF_MONTH,
+ state.calendar.getActualMaximum(Calendar.MONTH));
+ state.calendar.set(Calendar.HOUR, 0);
+ state.calendar.set(Calendar.MINUTE, 0);
+ state.calendar.set(Calendar.MILLISECOND, 0);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+ /**
+ * AddYears ( date int -- date2)
+ * Adds the given number of years to the given date. Care has to be
+ * taken where leap years are in effect. The month can change.
+ * So given 2/23/07 3 addYears would return 2/23/10
+ */
+ static class AddYears extends ROperator {
+ AddYears(){super("addyears");}
+
+ public void execute(DTState state) throws RulesException {
+ int years = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.YEAR, years);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * AddMonths ( date int -- date2)
+ * Adds the given number of months to the given date. Care has to be
+ * taken where the current day (31) may not be present in the new
+ * month (a month with 30 days).
+ * The behavior in this case is defined by the behavior of the Java
+ * Calendar.
+ * So given 2/23/07 3 addMonths would return 5/23/07
+ */
+ static class AddMonths extends ROperator {
+ AddMonths(){super("addmonths");}
+
+ public void execute(DTState state) throws RulesException {
+ int months = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.MONTH, months);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * AddDays ( date int -- date2)
+ * Adds the given number of days to the given date. You might
+ * move over to the next month!
+ */
+ static class AddDays extends ROperator {
+ AddDays(){super("adddays");}
+
+ public void execute(DTState state) throws RulesException {
+ int days = state.datapop().intValue();
+ Date date = state.datapop().timeValue();
+ state.calendar.setTime(date);
+ state.calendar.add(Calendar.DATE, days);
+ state.datapush(RTime.getRTime(state.calendar.getTime()));
+ }
+ }
+
+ /**
+ * SetCalendar( String -- )
+ * SetCalendar Operator,
+ */
+ @SuppressWarnings({"unchecked"})
+ static class SetCalendar extends ROperator {
+ SetCalendar(){super("setCalendar");}
+
+ public void execute(DTState state) throws RulesException {
+ try {
+ Class clazz = Class.forName(state.datapop().stringValue());
+ Object obj = clazz.newInstance();
+ if(obj instanceof Calendar){
+ state.calendar=(Calendar)obj;
+ } else {
+ throw new RulesException("Date Time Exception","Set Calendar","Not a Calendar Object");
+ }
+ } catch(Exception e){
+ throw new RulesException("Date Time Exception","/","Error while creating object: "+e);
+ }
+ }
+ }
+
+ /**
+ * Yearof( date -- int )
+ * Yearof Operator, returns the year value for the given date
+ */
+ static class Yearof extends ROperator {
+ Yearof(){super("yearof");}
+
+ public void execute(DTState state) throws RulesException {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(state.datapop().timeValue());
+ state.datapush(RInteger.getRIntegerValue(calendar.get(Calendar.YEAR)));
+ }
+ }
+
+ /**
+ * Getdaysinyear( date -- long )
+ * Getdaysinyear Operator, returns the number of days in a year from the given date
+ */
+ static class Getdaysinyear extends ROperator {
+ Getdaysinyear(){super("getdaysinyear");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ if(calendar.isLeapYear(calendar.get(Calendar.YEAR))){
+ state.datapush(RInteger.getRIntegerValue(366));
+ } else {
+ state.datapush(RInteger.getRIntegerValue(365));
+ }
+ }
+ }
+ /**
+ * Getdayofmonth( date -- long )
+ * Returns the day of the month in the given date
+ */
+ static class Getdayofmonth extends ROperator {
+ Getdayofmonth(){super("getdayofmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ int day = calendar.get(Calendar.DAY_OF_MONTH);
+ state.datapush(RInteger.getRIntegerValue(day));
+ }
+ }
+ /**
+ * GetdaysinMonth( date -- long )
+ * Getdaysinyear Operator, returns the number of days in a year from the given date
+ */
+ static class Getdaysinmonth extends ROperator {
+ Getdaysinmonth(){super("getdaysinmonth");}
+
+ public void execute(DTState state) throws RulesException {
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(state.datapop().timeValue());
+ int daysinmonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
+ state.datapush(RInteger.getRIntegerValue(daysinmonth));
+ }
+ }
+
+ /**
+ * Datelt( date1 date2 -- boolean )
+ * Datelt Operator, returns true if date1 is less than date2
+ */
+ static class Datelt extends ROperator {
+ Datelt(){super("d<");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ boolean test =date1.before(date2);
+ state.datapush(RBoolean.getRBoolean(test));
+ }
+ }
+
+ /**
+ * Dategt( date1 date2 -- boolean )
+ * Dategt Operator, returns true if date1 is greater than date2
+ */
+ static class Dategt extends ROperator {
+ Dategt(){super("d>");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ boolean test = date1.after(date2);
+ state.datapush(RBoolean.getRBoolean(test));
+ }
+ }
+
+ /**
+ * Dateeq (date1 date2 -- boolean )
+ * Dateeq Operator, returns true if date1 is equals to date2
+ */
+ static class Dateeq extends ROperator {
+ Dateeq(){super("d==");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ state.datapush(RBoolean.getRBoolean(date1.compareTo(date2)==0));
+ }
+ }
+
+ /**
+ * Gettimestamp( date -- String )
+ * Gettimestamp Operator, creates a string timestamp from s date
+ */
+ static class Gettimestamp extends ROperator {
+ Gettimestamp(){super("gettimestamp");}
+
+ public void execute(DTState state) throws RulesException {
+ Date date = state.datapop().timeValue();
+ state.datapush(RString.newRString((new Timestamp(date.getTime())).toString()));
+ }
+ }
+
+ /**
+ * d+ ( date1 date2 -- )
+ * Add two dates together. This doesn't make all that much sense unless
+ * one or both of the dates is just a count of days.
+ */
+ static class DatePlus extends ROperator {
+ DatePlus() {super("d+"); }
+ public void execute(DTState state) throws RulesException {
+ long date2 = state.datapop().timeValue().getTime();
+ long date1 = state.datapop().timeValue().getTime();
+ state.datapush(RTime.getRTime(new Date(date1+date2)));
+ }
+
+ }
+
+ /**
+ * d- ( date1 date2 -- )
+ * Subtract date2 from date1 This doesn't make all that much sense unless
+ * one or both of the dates is just a count of days.
+ */
+ static class DateMinus extends ROperator {
+ DateMinus() {super("d-"); }
+ public void execute(DTState state) throws RulesException {
+ long date2 = state.datapop().timeValue().getTime();
+ long date1 = state.datapop().timeValue().getTime();
+ state.datapush(RTime.getRTime(new Date(date1-date2)));
+ }
+
+ }
+ /**
+ * ( date1 date2 -- int )
+ * Returns the number of years between date1 and date2. It is always
+ * the difference, i.e. positive, even if date1 is after date2
+ */
+ static class YearsBetween extends ROperator {
+ YearsBetween() {super("yearsbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ int y1 = state.calendar.get(Calendar.YEAR);
+ int m1 = state.calendar.get(Calendar.MONTH);
+ int d1 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ state.calendar.setTime(date2);
+ int y2 = state.calendar.get(Calendar.YEAR);
+ int m2 = state.calendar.get(Calendar.MONTH);
+ int d2 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ int diff = y2-y1;
+ if(m2<m1)diff--;
+ if(m2==m1 && d2<d1)diff--;
+ state.datapush(RInteger.getRIntegerValue(diff));
+ }
+
+ }
+ /**
+ * ( date1 date2 -- int )
+ * Returns the number of months between date1 and date2. It is always
+ * the difference, i.e. positive, even if date1 is after date2. The
+ * number of months doesn't care about the day... the 30th of the month
+ * is treated identically to the first of the month.
+ */
+ static class MonthsBetween extends ROperator {
+ MonthsBetween() {super("monthsbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ int y1 = state.calendar.get(Calendar.YEAR);
+ int m1 = state.calendar.get(Calendar.MONTH);
+ int d1 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ state.calendar.setTime(date2);
+ int y2 = state.calendar.get(Calendar.YEAR);
+ int m2 = state.calendar.get(Calendar.MONTH);
+ int d2 = state.calendar.get(Calendar.DAY_OF_MONTH);
+ int yeardiff = y2-y1;
+ if(m2<m1)yeardiff--;
+ int monthdiff = m2-m1;
+ if(d2<d1-1)monthdiff--;
+ if(monthdiff < 0)monthdiff +=12;
+ monthdiff += 12*yeardiff;
+ state.datapush(RInteger.getRIntegerValue(monthdiff));
+ }
+ }
+ static class DaysBetween extends ROperator {
+ DaysBetween() {super("daysbetween"); }
+ public void execute(DTState state) throws RulesException {
+ Date date2 = state.datapop().timeValue();
+ Date date1 = state.datapop().timeValue();
+ if(date1.after(date2)){
+ Date hold = date1;
+ date1 = date2;
+ date2 = hold;
+ }
+ state.calendar.setTime(date1);
+ long from = state.calendar.getTimeInMillis();
+ state.calendar.setTime(date2);
+ long to = state.calendar.getTimeInMillis();
+ long days = Math.round((to-from)/(1000*60*60*24));
+ state.datapush(RInteger.getRIntegerValue(days));
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.session.DTState;
+/**
+ * Defines math operators.
+ * @author paul snow
+ *
+ */
+public class RMath {
+ static {
+ new Add(); new Mul(); new Sub(); new Div();
+ new FAdd(); new FMul(); new FSub(); new FDiv();
+ new Abs(); new Negate();
+ new FAbs(); new FNegate();
+ new Roundto();
+ }
+
+ /**
+ * ( number #places boundary -- number2 )
+ * The number of decimal places would be zero to round to the nearest
+ * integer, 1 to the nearest 10th, -1 to the nearest 10. The boundary
+ * is the value added to the lower fractional amount to trigger the
+ * round. In other words, <br><br>
+ *
+ * 1.3 0 .7 roundto<br><br>
+ *
+ * would result in 1, while<br><br>
+ *
+ * 1.7 0 .7 roundto<br>
+ *
+ * would reslut in 2.<br><br><br>
+ *
+ * Note: if the boundary is zero, than any fractional amount will round up.
+ * If the boundary is 1, the number is simply truncated.
+ *
+ * Limitation: We always towards zero. Lots of other rounding ideas are
+ * possible. We need to come back here and rework and add to our options
+ * if the need for more complexity comes our way.
+ *
+ * @author paul snow
+ *
+ */
+ static class Roundto extends ROperator {
+ Roundto(){super("roundto"); }
+
+ double round(double number,double boundary){
+ double v = (int)number; // Get the integer porition of number
+ if (boundary>=1) return v; // If boundary is 1 or greater we are done
+ double r = Math.abs(number - v); // Get the fractional portion of number
+ if (boundary<=0) return r>0 ? v++ : v; // If boundary is 0 or less, inc on any fraction
+ if(r>=boundary)return v++; // Otherwise test the boundary. Inc if fraction
+ return v; // is greater or equal to the boundary.
+ }
+ public void execute(DTState state)throws RulesException {
+ double boundary = state.datapop().doubleValue();
+ int places = state.datapop().intValue();
+ double number = state.datapop().doubleValue();
+ if(places >0){ // We put the boundary across zero. shift left if
+ number *= 10*places; // places is positive (okay, its a decimal shift)
+ number = round(number,boundary); // Do the round thing.
+ number /= 10*places; // Fix it back when done.
+ }else{
+ number /= -10*places; // We decimal shift right if places is negative
+ number = round(number,boundary); // Do the round thing
+ number *= -10*places; // Fix it back.
+ }
+
+ }
+ }
+
+
+ /**
+ * Negate a double
+ * @author paul snow
+ *
+ */
+ static class FNegate extends ROperator {
+ FNegate(){super("fnegate"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RDouble.getRDoubleValue(
+ -state.datapop().doubleValue()
+ )
+ );
+ }
+ }
+
+
+ /**
+ * Absolute value of a double.
+ * @author paul snow
+ *
+ */
+ static class FAbs extends ROperator {
+ FAbs(){super("fabs"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RDouble.getRDoubleValue(
+ Math.abs(state.datapop().doubleValue())
+ )
+ );
+ }
+ }
+ /**
+ * Absolute value of an integer
+ * @author paul snow
+ *
+ */
+ static class Abs extends ROperator {
+ Abs(){super("abs"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RInteger.getRIntegerValue(
+ Math.abs(state.datapop().intValue())
+ )
+ );
+ }
+ }
+
+ /**
+ * Negate an integer
+ * @author paul snow
+ *
+ */
+ static class Negate extends ROperator {
+ Negate(){super("negate"); }
+
+ public void execute(DTState state)throws RulesException {
+ state.datapush(
+ RInteger.getRIntegerValue(
+ -state.datapop().intValue()
+ )
+ );
+ }
+ }
+
+ /**
+ * Add Operator, adds two integers
+ * @author Paul Snow
+ *
+ */
+ static class Add extends ROperator {
+ Add(){
+ super("+"); alias("ladd");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RInteger.getRIntegerValue(state.datapop().longValue()+state.datapop().longValue()));
+ }
+ }
+
+
+
+
+ /**
+ * Sub Operator, subracts two integers
+ * @author Paul Snow
+ *
+ */
+ static class Sub extends ROperator {
+ Sub(){super("-"); alias("lsub");}
+
+ public void execute(DTState state) throws RulesException {
+ long b = state.datapop().longValue();
+ long a = state.datapop().longValue();
+ long result = a-b;
+ state.datapush(RInteger.getRIntegerValue(result));
+ }
+ }
+
+ /**
+ * Mul Operator, multiply two integers
+ * @author Paul Snow
+ *
+ */
+ static class Mul extends ROperator {
+ Mul(){super("*"); alias("lmul");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RInteger.getRIntegerValue(state.datapop().longValue()*state.datapop().longValue()));
+ }
+ }
+
+ /**
+ * Divide Operator, divides one integer by another
+ * @author Paul Snow
+ *
+ */
+ static class Div extends ROperator {
+ Div(){super("/"); alias("div"); alias("ldiv");}
+
+ public void execute(DTState state) throws RulesException {
+ long result;
+ long a=0; long b=0;
+ try {
+ b = state.datapop().longValue();
+ a = state.datapop().longValue();
+ result = a/b;
+ } catch (ArithmeticException e) {
+ throw new RulesException("Math Exception","/","Error in Divide: "+a+"/"+b+"\n"+e);
+ }
+ state.datapush(RInteger.getRIntegerValue(result));
+ }
+ }
+
+ /**
+ * FAdd (f+) Operator, adds two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FAdd extends ROperator {
+ FAdd(){
+ super("f+");alias("fadd");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ IRObject b = state.datapop();
+ IRObject a = state.datapop();
+ state.datapush(RDouble.getRDoubleValue(a.doubleValue()+b.doubleValue()));
+ }
+ }
+
+
+
+
+ /**
+ * FSub (f-) Operator, subracts two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FSub extends ROperator {
+ FSub(){super("f-");alias("fsub");}
+
+ public void execute(DTState state) throws RulesException {
+ double b = state.datapop().doubleValue();
+ double a = state.datapop().doubleValue();
+ double result = a-b;
+ state.datapush(RDouble.getRDoubleValue(result));
+ }
+ }
+
+ /**
+ * FMul Operator, multiply two doubles
+ * @author Paul Snow
+ *
+ */
+ static class FMul extends ROperator {
+ FMul(){super("f*");alias("fmul");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RDouble.getRDoubleValue(state.datapop().doubleValue()*state.datapop().doubleValue()));
+ }
+ }
+
+ /**
+ * FDiv Operator, divides one double by another double.
+ * @author Paul Snow
+ *
+ */
+ static class FDiv extends ROperator {
+ FDiv(){super("fdiv"); alias("f/");}
+
+ public void execute(DTState state) throws RulesException {
+ double result;
+ double a=0; double b=0;
+ try {
+ b = state.datapop().doubleValue();
+ a = state.datapop().doubleValue();
+ result = a/b;
+ } catch (ArithmeticException e) {
+ throw new RulesException("Math Exception","f/","Error in Divide: "+a+"/"+b+"\n"+e);
+ }
+ state.datapush(RDouble.getRDoubleValue(result));
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RSession;
+
+public class RMiscOps {
+ static {
+ new RError();
+ new Debug();
+ new Traceon();
+ new Traceoff();
+ new Ignore();
+ new Stringlength();
+ new Touppercase();
+ new Tolowercase();
+ new Trim();
+ new substring();
+ new Swap();
+ new Dup();
+ new Pop();
+ new Over();
+ new EntityName();
+ new Entitypush();
+ new Entitypop();
+ new Entityfetch();
+ new I(); new J(); new K();
+ new ToR();
+ new FromR();
+ new Def();
+ new Find();
+ new Print();
+ new Clone();
+ new Xdef();
+ new PStack();
+ new Null();
+ new Createentity();
+ new Cvi();
+ new Cvr();
+ new Cvb();
+ new Cve();
+ new Cvs();
+ new Cvn();
+ new Cvd();
+ new ActionString();
+ new GetDescription();
+ new RegexMatch();
+ }
+
+ /**
+ * ( -- RNull ) Return the Null object
+ */
+ static class Null extends ROperator {
+ Null() {
+ super("null");
+ }
+ public void execute(DTState state) throws RulesException {
+ state.datapush(RNull.getRNull());
+ }
+ }
+
+
+ /**
+ * ( entity -- RName ) Get the name of the given entity.
+ */
+ static class EntityName extends ROperator {
+ EntityName() {
+ super("entityname");
+ }
+ public void execute(DTState state) throws RulesException {
+ IREntity entity = state.datapop().rEntityValue();
+ state.datapush(entity.getName());
+ }
+ }
+ /**
+ * ( Exception message -- ) Throws a RulesException with the given message.
+ * @author paul snow
+ *
+ *
+ */
+ static class RError extends ROperator {
+ RError(){super("error");}
+
+ public void execute(DTState state) throws RulesException {
+ String message = state.datapop().stringValue();
+ String exception = state.datapop().stringValue();
+ try {
+ throw new RulesException(
+ "exception",
+ "User Exception",
+ message);
+ } catch (Exception e) {
+ throw new RulesException("Type Check",
+ "User Exception",
+ exception+":"+message);
+ }
+ }
+ }
+
+ /**
+ * ( string -- ) Prints a debug message only if debug output is enabled.
+ * @author paul snow
+ *
+ */
+ static class Debug extends ROperator {
+ Debug(){super("debug");}
+
+ public void execute(DTState state) throws RulesException {
+ String msg = state.datapop().stringValue();
+ if(state.testState(DTState.DEBUG)){
+ state.debug(msg);
+ }
+ }
+ }
+
+ /**
+ * ( -- ) Turn on the trace flag.
+ * @author paul snow
+ *
+ */
+ static class Traceon extends ROperator {
+ Traceon(){super("traceon");}
+
+ public void execute(DTState state) throws RulesException {
+ state.setState(DTState.TRACE);
+ }
+ }
+
+ /**
+ * ( -- ) Turn off the trace flag
+ * @author paul snow
+ *
+ */
+ static class Traceoff extends ROperator {
+ Traceoff(){super("traceoff");}
+
+ public void execute(DTState state) throws RulesException {
+ state.clearState(DTState.TRACE);
+ }
+ }
+
+ /**
+ * ( flag -- ) Set the debug state
+ *
+ * @author paul snow
+ *
+ */
+ static class SetDebug extends ROperator {
+ SetDebug(){super("setdebug");}
+
+ public void execute(DTState state) throws RulesException {
+ boolean flg = state.datapop().booleanValue();
+ if(flg){
+ state.setState(DTState.DEBUG);
+ }else{
+ state.clearState(DTState.DEBUG);
+ }
+ }
+ }
+
+ /**
+ * A Noop -- Does nothing.
+ * @author paul snow
+ *
+ */
+ static class Ignore extends ROperator {
+ Ignore(){super("ignore"); alias("nop");}
+
+ public void execute(DTState state) throws RulesException {
+ }
+ }
+
+ /**
+ * ( string -- length ) returns the length of the given string
+ * @author paul snow
+ *
+ */
+ static class Stringlength extends ROperator {
+ Stringlength(){super("strlength");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ RInteger len = RInteger.getRIntegerValue(str.length());
+ state.datapush(len);
+ }
+ }
+
+ /**
+ * ( String -- String ) converts the string to uppercase.
+ * @author paul snow
+ *
+ */
+ static class Touppercase extends ROperator {
+ Touppercase(){super("touppercase");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.toUpperCase();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( String -- String ) converts the string to lowercase
+ * @author paul snow
+ *
+ */
+ static class Tolowercase extends ROperator {
+ Tolowercase(){super("tolowercase");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.toLowerCase();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( string -- string ) Trims the string, per trim in Java
+ * @author paul snow
+ *
+ */
+ static class Trim extends ROperator {
+ Trim(){super("trim");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ String str2 = str.trim();
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * (endindex beginindex string -- substring ) Returns the substring
+ * @author paul snow
+ *
+ */
+ static class substring extends ROperator {
+ substring(){super("substring");}
+
+ public void execute(DTState state) throws RulesException {
+ String str = state.datapop().stringValue();
+ int b = state.datapop().intValue();
+ int e = state.datapop().intValue();
+ String str2 = str.substring(b,e);
+ state.datapush(RString.newRString(str2));
+ }
+ }
+
+ /**
+ * ( obj1 obj2 -- obj2 obj1 ) swaps the top two elements on the data stack
+ * @author paul snow
+ *
+ */
+ static class Swap extends ROperator {
+ Swap(){super("swap"); alias("exch");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.datapop();
+ IRObject obj2 = state.datapop();
+ state.datapush(obj1);
+ state.datapush(obj2);
+ }
+ }
+
+ /**
+ * ( obj1 -- obj1 obj2 )
+ * @author paul snow
+ *
+ */
+ static class Dup extends ROperator {
+ Dup(){super("dup");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.datapop();
+ state.datapush(obj1);
+ state.datapush(obj1);
+ }
+ }
+
+ static class Pop extends ROperator {
+ Pop(){
+ super("pop");
+ alias("drop");
+ }
+
+ public void execute(DTState state) throws RulesException {
+ state.datapop();
+ }
+ }
+
+ /**
+ * (obj1 obj2 -- obj1 obj2 obj1 ) copies the element below the top.
+ * @author paul snow
+ *
+ */
+ static class Over extends ROperator {
+ Over(){super("over");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj1 = state.getds(state.ddepth()-2);
+ state.datapush(obj1);
+ }
+ }
+
+ /**
+ * ( entity -- ) push the given entity onto the entity stack
+ * @author paul snow
+ *
+ */
+ static class Entitypush extends ROperator {
+ Entitypush(){super("entitypush");}
+
+ public void execute(DTState state) throws RulesException {
+ IREntity e = state.datapop().rEntityValue();
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("entitypush", "value='"+e.stringValue()+"' id='"+e.getID()+"'");
+ }
+ state.entitypush(e);
+ }
+ }
+
+ /**
+ * ( -- ) pops the top element from the entity stack and tosses
+ * it into the bit bucket
+ * @author paul snow
+ *
+ */
+ static class Entitypop extends ROperator {
+ Entitypop(){super("entitypop");}
+
+ public void execute(DTState state) throws RulesException {
+ if(state.testState(DTState.TRACE)){
+ state.traceInfo("entitypop","");
+ }
+ state.entitypop();
+ }
+ }
+
+ /**
+ * Pushes a copy of the top entity on the entity stack on to the
+ * data stack.
+ * ( index -- element )
+ * @author paul snow
+ *
+ */
+ static class Entityfetch extends ROperator {
+ Entityfetch(){super("entityfetch");}
+ public void execute(DTState state) throws RulesException {
+ int i = state.datapop().intValue();
+ state.datapush(state.entityfetch(i));
+ }
+ }
+
+ /**
+ * Returns the top element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class I extends ROperator {
+ I(){super("i"); alias("r@");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-1));
+ }
+ }
+
+ /**
+ * Returns the second element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class J extends ROperator {
+ J(){super("j");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-2));
+ }
+ }
+
+ /**
+ * Returns the third element from the control stack.
+ * @author paul snow
+ *
+ */
+ static class K extends ROperator {
+ K(){super("k");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( state.getcs(state.cdepth()-3));
+ }
+ }
+
+ /**
+ * ( obj -- ) Pops the top element from the data stack, and pushes
+ * it to the Control stack.
+ * @author paul snow
+ *
+ */
+ static class ToR extends ROperator {
+ ToR(){super(">r");}
+
+ public void execute(DTState state) throws RulesException {
+ state.cpush(state.datapop());
+ }
+ }
+
+ /**
+ * ( -- obj ) pops the top element from the control stack, and pushes
+ * it to the data stack.
+ * @author paul snow
+ *
+ */
+ static class FromR extends ROperator {
+ FromR(){super("r>");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.cpop());
+ }
+ }
+
+ /**
+ * ( name value -- )
+ * Binds the name with the value in the highest entity on the
+ * entity stack which is both writable, and has an entry with
+ * a writiable name that matches.
+ *
+ * @author paul snow
+ *
+ */
+ static class Def extends ROperator {
+ Def(){super("def");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject value = state.datapop();
+ RName name = state.datapop().rNameValue();
+ boolean f = state.def(name, value, true);
+ if(!f)throw new RulesException("Undefined",
+ "def",
+ name+" is undefined");
+ }
+ }
+ /**
+ * ( name -- obj )
+ * Looks up the name, and returns the value associated with
+ * the name in the top most entity that defines the name.
+ * Returns RNull if the name isn't found.
+ * @author paul snow
+ *
+ */
+ static class Find extends ROperator {
+ Find(){super("find");}
+
+ public void execute(DTState state) throws RulesException {
+ RName name = state.datapop().rNameValue();
+ IRObject v = state.find(name);
+ if(v==null)throw new RulesException("Undefined",
+ "find",
+ name+" is undefined");
+ }
+ }
+ /**
+ * ( obj -- ) Prints the top element of on the data stack to
+ * Standard Out.
+ * @author paul snow
+ *
+ */
+ static class Print extends ROperator {
+ Print(){super("print"); alias("debug"); }
+
+ public void execute(DTState state) throws RulesException {
+ state.debug(state.datapop().toString());
+ }
+ }
+
+ /**
+ * ( obj1 -- obj2 ) Creates a clone of the given object.
+ * @author paul snow
+ *
+ */
+ static class Clone extends ROperator {
+ Clone(){super("clone");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().clone(state.getSession()));
+ }
+ }
+
+ /**
+ * ( value name -- )
+ * Binds the name with the value in the highest entity on the
+ * entity stack which is both writable, and has an entry with
+ * a writiable name that matches.
+ *
+ * @author paul snow
+ *
+ */
+ static class Xdef extends ROperator {
+ Xdef(){super("xdef");}
+
+ public void execute(DTState state) throws RulesException {
+ RName name = state.datapop().rNameValue();
+ IRObject value = state.datapop();
+ boolean f = state.def(name, value, true);
+ if(!f)
+ if(state.find(name)==null){
+ throw new RulesException("Undefined",
+ "xdef",
+ name+" is undefined");
+ }else{
+ throw new RulesException("Write Protection",
+ "xdef",
+ name+" is Input only, and xdef attempted to write to it");
+ }
+ }
+ }
+
+ /**
+ * ( -- ) Prints all the elements on all the stacks non-distructively.
+ * This is purely a debugging aid.
+ * @author paul snow
+ *
+ */
+ static class PStack extends ROperator {
+ PStack(){super("pstack");}
+
+ public void execute(DTState state) throws RulesException {
+ state.pstack();
+ }
+ }
+
+ /**
+ * ( RName -- ) Creates an instance of the entity with the given name.
+ *
+ * @author paul snow
+ *
+ */
+ static class Createentity extends ROperator {
+ Createentity(){super("createentity");}
+
+ public void execute(DTState state) throws RulesException {
+ RName ename = state.datapop().rNameValue();
+ IREntity entity = ((RSession) state.getSession()).createEntity(null, ename);
+ state.datapush(entity);
+ }
+ }
+
+ /**
+ * ( Object -- Integer ) Converts to an Integer.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvi extends ROperator {
+ Cvi(){super("cvi");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ IRObject obj = v.rIntegerValue();
+ if(state.testState(DTState.TRACE)){
+ if(v.type()!= IRObject.iInteger){
+ state.traceInfo("cvi", "value='"+v+"'",obj.stringValue());
+ }
+ }
+ state.datapush(obj);
+ }
+ }
+ /**
+ * ( Object -- Double ) Converts to an Double.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvr extends ROperator {
+ Cvr(){super("cvr"); alias("cvd");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ IRObject obj = v.rDoubleValue();
+ if(state.testState(DTState.TRACE)){
+ if(v.type()!= IRObject.iDouble){
+ state.traceInfo("cvr", "value='"+v+"'",obj.stringValue());
+ }
+ }
+ state.datapush(obj);
+ }
+ }
+ /**
+ * ( Object -- Boolean ) Converts to an Boolean.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvb extends ROperator {
+ Cvb(){super("cvb");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().rBooleanValue());
+ }
+ }
+ /**
+ * ( Object -- Entity ) Converts to an Entity.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cve extends ROperator {
+ Cve(){super("cve");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject v = state.datapop();
+ if(v.type()==IRObject.iNull){
+ state.datapush(v);
+ }else{
+ state.datapush(v.rEntityValue());
+ }
+ }
+ }
+ /**
+ * ( Object -- String ) Converts to a String.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvs extends ROperator {
+ Cvs(){super("cvs");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush(state.datapop().rStringValue());
+ }
+ }
+ /**
+ * ( Object -- String ) Converts to a Name.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvn extends ROperator {
+ Cvn(){super("cvn");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject obj = state.datapop();
+ state.datapush(obj.rNameValue().getNonExecutable());
+ }
+ }
+ /**
+ * ( Object -- Date ) Converts to an Date.
+ *
+ * @author paul snow
+ *
+ */
+ static class Cvd extends ROperator {
+ Cvd(){super("cvd");}
+
+ public void execute(DTState state) throws RulesException {
+ IRObject datevalue = state.datapop();
+ state.datapush(datevalue.rTimeValue());
+ }
+ }
+
+ /**
+ * ( -- String ) Returns the Decision Table and Action number
+ *
+ * @author paul snow
+ *
+ */
+ static class ActionString extends ROperator {
+ ActionString(){super("actionstring");}
+
+ public void execute(DTState state) throws RulesException {
+ state.datapush( RString.newRString(
+ state.getCurrentTable().getName().stringValue()+" "+
+ state.getCurrentTableSection()+" "+
+ (state.getNumberInSection()+1)));
+ }
+ }
+ /**
+ * ( -- String ) Returns the Decision Table and Action number
+ *
+ * @author paul snow
+ *
+ */
+ static class GetDescription extends ROperator {
+ GetDescription(){super("getdescription");}
+
+ public void execute(DTState state) throws RulesException {
+ String section = state.getCurrentTableSection();
+ String description = "";
+ if(section.equalsIgnoreCase("action")){
+ RDecisionTable table = state.getCurrentTable();
+ description = table.getActionsComment()[state.getNumberInSection()];
+ }else if(section.equalsIgnoreCase("condition")){
+ RDecisionTable table = state.getCurrentTable();
+ description = table.getConditionsComment()[state.getNumberInSection()];
+ }
+ state.datapush( RString.newRString(description));
+ }
+ }
+ /**
+ * ( regex String -- boolean ) Returns true if the given string is matched
+ * by the given regular expression.
+ *
+ * @author Paul Snow
+ *
+ */
+ static class RegexMatch extends ROperator {
+ RegexMatch(){super("regexmatch");}
+
+ public void execute(DTState state) throws RulesException {
+ String string = state.datapop().stringValue();
+ String regex = state.datapop().stringValue();
+ boolean b = string.matches(regex);
+ state.datapush( RBoolean.getRBoolean(b));
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.ARObject;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+
+/**
+ * This Class creates the primities entity in a rather cute way. The actual operators
+ * are for the most part extend ROperator and only supply a new execute() method. Each
+ * of these classes are defined as subclasses of the classes listed in the static
+ * section. They in turn have a static section that lists all of classes that implement
+ * the operators in their section.
+ * <br><br>
+ * Each operator calls the super constructor with their name, and the super constructor
+ * (defined here) creates the entry in the primitives entity for the operator.
+ *
+ * @author paul snow
+ *
+ */
+public class ROperator extends ARObject {
+
+ static final REntity primitives = new REntity(1,true,RName.getRName("primities",false));
+
+ static {
+ new RMath();
+ new RArrayOps();
+ new RControl();
+ new RBooleanOps();
+ new RMiscOps();
+ new RDateTimeOps();
+ new RTableOps();
+ new RXmlValueOps();
+ }
+
+ static public IREntity getPrimitives() {
+ return primitives;
+ }
+
+ final RName name;
+ public int type() { return iOperator; }
+
+ /**
+ * Puts another entry into the primitives entity under a different name. This is
+ * useful for operators that we would like to define under two names (such as "pop" and
+ * "drop".)
+ *
+ * This function also allows us to define constants such as "true" and "false" as objects
+ * rather than defining operators that return "true" and "false".
+ *
+ * @param o
+ * @param n
+ */
+ protected static void alias (IRObject o ,String n) {
+ try {
+ RName rn = RName.getRName(n);
+ primitives.addAttribute(rn, "", o, false, true, o.type(),null);
+ primitives.put(rn,o);
+ } catch (RulesException e) {
+ throw new RuntimeException("An Error occured in alias building the primitives Entity: "+n);
+ }
+ }
+
+ /**
+ * A method that makes it a bit easier to call the other alias function when I am
+ * creating an alias for an operator in its own constructor.
+ *
+ * @param n
+ */
+ protected void alias (String n){
+ alias(this,n);
+ }
+
+ /**
+ * All of the operators extend ROperator. They call the super constructor with their
+ * name as a string. Here we convert the name to an RName, set the name as a final
+ * field in the Operator, and create an entry in the primities entity for the
+ * operator.
+ * @param _name
+ */
+ public ROperator(String _name){
+ name = RName.getRName(_name,true);
+ try {
+ primitives.addAttribute(name, "", this,false, true,iOperator,null);
+ primitives.put(name,this);
+ } catch (RulesException e) {
+ throw new RuntimeException("An Error occured building the primitives Entity: "+name);
+ }
+ }
+
+ public boolean isExecutable() { return true; }
+
+ public String stringValue() {
+ return name.stringValue();
+ }
+
+ public String toString(){
+ return name.stringValue();
+ }
+
+ public String postFix(){
+ return name.stringValue();
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTable;
+import com.dtrules.session.DTState;
+import com.dtrules.session.RSession;
+
+public class RTableOps {
+ static {
+ new Lookup(); new Set(); new GetKeys ();
+ new NewTable(); new SetDescription(); new Translate ();
+ }
+ /**
+ * ( table, index1, index2, ... lookup -- result )
+ * Does a lookup (of however many keys) and returns the result. An
+ * Error will be thrown if any index but the last fails to return
+ * an RTable object
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class Lookup extends ROperator {
+ Lookup(){ super("lookup");}
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0;
+ int d = state.ddepth();
+ while(state.getds(--d).type()!=iTable)cnt++;
+ RName []keys = new RName[cnt];
+ for(int i=0;i<cnt;i++){
+ keys[i]= state.datapop().rNameValue();
+ }
+ RTable rtable = state.datapop().rTableValue();
+ state.datapush(rtable.getValue(keys));
+ }
+ }
+
+ /**
+ * ( table, index1, index2, ... , indexN value set -- )
+ * Takes a table, and a set of indexes. The Nth index is used to
+ * set the value.
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class Set extends ROperator {
+ Set(){ super("set");}
+
+ public void execute(DTState state) throws RulesException {
+ int cnt = 0; // We keep a count of the keys.
+ IRObject v = state.datapop(); // Get the value to store
+ int d = state.ddepth(); // Get current depth of data stack.
+
+ while(state.getds(--d).type()==iName)cnt++; // Count the keys (index1, index2, etc.)
+
+ RName []keys = new RName[cnt]; // Get an array big enough to hold the keys
+
+ for(int i=0;i<cnt;i++){ // Get all the keys off the data stack
+ keys[i]= state.datapop().rNameValue();
+ }
+
+ RTable rtable = state.datapop().rTableValue();
+
+ rtable.setValue(state,keys, v); // Set the value.
+ }
+ }
+ /**
+ * ( table getKeys -- Array ) Returns an array holding all the
+ * keys in a table.
+ *
+ * @author paul snow
+ * Aug 14, 2007
+ *
+ */
+ static class GetKeys extends ROperator {
+ GetKeys(){ super("getkeys");}
+
+ public void execute(DTState state) throws RulesException {
+ RTable rtable = state.datapop().rTableValue();
+ state.datapush(rtable.getKeys(state));
+ }
+ }
+
+ /**
+ * ( Name Type -- Table ) newTable
+ * Name is a name for the table
+ */
+ static class NewTable extends ROperator {
+ NewTable(){ super("newtable");}
+
+ public void execute(DTState state) throws RulesException {
+ String type = state.datapop().stringValue();
+ RName name = state.datapop().rNameValue();
+ int itype = RSession.typeStr2Int(type,"","");
+ RTable table = RTable.newRTable(state.getSession().getEntityFactory(),name,"",itype);
+ state.datapush(table);
+ }
+ }
+
+ /**
+ * ( Table description -- ) setDescription
+ */
+ static class SetDescription extends ROperator {
+ SetDescription() { super("setdescription"); }
+ public void execute(DTState state) throws RulesException {
+ RString description = state.datapop().rStringValue();
+ RTable table = state.datapop().rTableValue();
+ table.setDescription(description);
+ }
+ }
+ /**
+ * ( Table keyArray boolean -- valueArray ) translate
+ * All the keys provided by the keyArray are looked up in the
+ * given Table. If a key is not found in the table, it is
+ * ignored. If a key is found, then that value is added to
+ * the valueArray.
+ *
+ * If the boolean is true, then duplicates are allowed in
+ * the valueArray. If boolean is false, then only unique
+ * values are returned.
+ *
+ * @author paul snow
+ *
+ */
+ static class Translate extends ROperator {
+ Translate(){super("translate"); }
+ public void execute(DTState state) throws RulesException {
+ boolean duplicates = state.datapop().booleanValue();
+ RArray keys = state.datapop().rArrayValue();
+ RTable table = state.datapop().rTableValue();
+ RArray valueArray = new RArray(state.getSession().getUniqueID(),duplicates,false);
+ for(IRObject irkey : keys){
+ RName key = irkey.rNameValue();
+ if(table.containsKey(key)){
+ valueArray.add(table.getValue(key));
+ }
+ }
+ state.datapush(valueArray);
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.mapping.XMLTag;
+import com.dtrules.session.DTState;
+
+@SuppressWarnings("unchecked")
+public class RXmlValueOps {
+ static {
+ new SetXmlAttribute();
+ new GetXmlAttribute();
+ }
+
+ /**
+ * SetXmlAttribute ( XmlValue Attribute Value --> )
+ * Addto Operator, adds an element to an array
+ * @author Paul Snow
+ *
+ */
+ static class SetXmlAttribute extends ROperator {
+ SetXmlAttribute(){super("setxmlattribute");}
+
+ @Override
+ public void execute(DTState state) throws RulesException {
+ String value = state.datapop().stringValue();
+ String attribute = state.datapop().stringValue();
+ XMLTag xmlTag = state.datapop().xmlTagValue();
+
+ state.traceInfo("SetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' value='"+value+"'");
+
+ xmlTag.getAttribs().put(attribute, value);
+ }
+ }
+ /**
+ * GetXmlAttribute ( XmlValue Attribute --> Value )
+ * Get the value of the given attribute from this XmlValue.
+ * If the attribute is not defined, a null is returned.
+ * @author Paul Snow
+ *
+ */
+ static class GetXmlAttribute extends ROperator {
+ GetXmlAttribute(){super("getxmlattribute");}
+
+ @Override
+ public void execute(DTState state) throws RulesException {
+ String attribute = state.datapop().stringValue();
+ XMLTag xmlTag = state.datapop().xmlTagValue();
+
+ String value = (String) xmlTag.getAttribs().get(attribute);
+ if(value != null ){
+ state.datapush(RString.newRString(value));
+ state.traceInfo("GetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' value='"+value+"'");
+ }else{
+ state.datapush(RNull.getRNull());
+ state.traceInfo("GetXmlAttribute","tag='"+xmlTag.getTag()+"' attribute='"+attribute+"' null='true'");
+ }
+ }
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/mapping
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:38:00.951175Z
+11671
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+AttributeInfo.java
+file
+
+
+
+
+2008-08-25T00:26:52.875000Z
+3f3659b55d4fad67960ecd268cd4eae7
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+LoadDatamapData.java
+file
+
+
+
+
+2008-09-03T13:43:31.656250Z
+435ae6dd8707f14a0028b7d3f7d79b88
+2008-09-09T03:13:02.964598Z
+11668
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9582
+\f
+MapGenerator.java
+file
+
+
+
+
+2008-08-21T15:12:12.875000Z
+4f56d0ed1c7d4b604ad5c36180c641a1
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+DataMap.java
+file
+
+
+
+
+2008-09-08T15:18:02.921875Z
+6e3ab645e83fea498349e681f923aadc
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+20797
+\f
+EntityInfo.java
+file
+
+
+
+
+2008-05-31T00:36:36.109375Z
+6b938596a76cf4d53465bdcdbfb93cc6
+2008-06-02T03:45:47.934610Z
+9190
+psnow
+\f
+LoadXMLData.java
+file
+
+
+
+
+2008-09-03T21:15:10.781250Z
+ac5ff24260ab4c69c7cd42a90a8f7a86
+2008-09-09T03:13:02.964598Z
+11668
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+14575
+\f
+LoadMapping.java
+file
+
+
+
+
+2008-09-04T20:48:40.531250Z
+98abf07826a720e48efe76296a0cd572
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+Mapping.java
+file
+
+
+
+
+2008-09-09T03:36:43.343750Z
+e47e1f25ad00330be04614d49148301b
+2008-09-09T03:38:00.951175Z
+11671
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9992
+\f
+XMLTag.java
+file
+
+
+
+
+2008-08-23T23:56:16.859375Z
+10037b463a14cac05317a3218e54788c
+2008-08-25T15:24:13.257771Z
+11349
+psnow
+\f
+LoadMap.java
+file
+
+
+
+
+2008-09-08T15:55:23.531250Z
+5a1a3d99ed7781bc8f6a41c2c4d568c6
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+11007
+\f
+DataObjectMap.java
+file
+
+
+
+
+2008-08-21T13:48:27.046875Z
+461458d069ed2228c641fc90c212d68f
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+/**
+ * A structure for holding information about Attributes. Instances of AttributeInfo are stored in the setAttributes HashMap.
+ * Note that Attributes are a bit more complex than Entities. We allow not only the tag to be specfied, but the enclosing tag
+ * for the identification of an Attribute. To further complicate things, we can specify different target attributes...
+ * @author ps24876
+ *
+ */
+@SuppressWarnings({"unchecked"})
+class AttributeInfo {
+
+ public static final String DATE_STRING_TYPE = "DateString"; //Strings
+ public static final String STRING_TYPE = "String";
+ public static final String INTEGER_TYPE = "Integer";
+ public static final String NONE_TYPE = "None";
+ public static final String FLOAT_TYPE = "Float";
+ public static final String BOOLEAN_TYPE = "Boolean";
+ public static final String ARRAY_TYPE = "list";
+ public static final String ENTITY_TYPE = "entity";
+ public static final String XMLVALUE_TYPE = "XmlValue";
+
+ public static final int DATE_STRING_CODE = 0; //Codes
+ public static final int STRING_CODE = 1;
+ public static final int NONE_CODE = 2;
+ public static final int INTEGER_CODE = 3;
+ public static final int FLOAT_CODE = 4;
+ public static final int BOOLEAN_CODE = 5;
+ public static final int ARRAY_CODE = 6;
+ public static final int ENTITY_CODE = 7;
+ public static final int XMLVALUE_CODE = 8;
+
+ public static final String int2str[] = {DATE_STRING_TYPE,
+ STRING_TYPE,
+ NONE_TYPE,
+ INTEGER_TYPE,
+ FLOAT_TYPE,
+ BOOLEAN_TYPE,
+ ARRAY_TYPE,
+ ENTITY_TYPE,
+ XMLVALUE_TYPE,
+ };
+
+ /**
+ * This is the information we collect for an attribute
+ */
+ public class Attrib {
+ String enclosure; // This is the XML Tag that must enclose this attribute.
+ String rAttribute; // This is the Rules Engine attribute to assign the value to
+ String rEntity; // If an Entity type, this is the Entity to create.
+ int type; // This is the type for this attribute.
+ }
+ /**
+ * A list of Attrib values for a given attribute mapping.
+ */
+ ArrayList<Attrib> tag_instances = new ArrayList<Attrib>();
+
+ public ArrayList<Attrib> getTag_instances() {
+ return tag_instances;
+ }
+
+ /**
+ * We add an enclosure attribute pair to these arraylists. An
+ * exception is thrown if we get two of the same enclosures.
+ * @param _enclosure
+ * @param _attribute
+ * @param _type
+ */
+ public void add(DTState state,
+ final String tag,
+ final String _enclosure,
+ final String _attribute,
+ String _type)throws RulesException {
+
+ final Iterator iattribs = tag_instances.iterator();
+ int attribType = -1;
+ if(_type.equalsIgnoreCase("date"))_type = "datestring";
+ if(_type.equalsIgnoreCase("time"))_type = "datestring";
+ for(int i=0;i<int2str.length;i++){
+ if(_type.equalsIgnoreCase(int2str[i])){
+ attribType = i;
+ break;
+ }
+ }
+
+ if(attribType == -1){
+ throw new RuntimeException("Invalid mapping type encountered in mapping file: "+_type); //NOPMD
+ }
+
+ while(iattribs.hasNext()){
+ final Attrib attrib = (Attrib)iattribs.next();
+ /* Duplicate attributes may be encountered in mapping xml.
+ So we won't throw this error. */
+ if(attrib.enclosure.equals(_enclosure)) {
+ if (" ".equals(attrib.rAttribute)) {
+ attrib.rAttribute = _attribute;
+ }
+
+ if (attrib.type == NONE_CODE) {
+ attrib.type = attribType;
+ }
+
+ boolean thisisanerror = true;
+
+ if(attrib.rAttribute.equalsIgnoreCase(_attribute)&&
+ int2str[attrib.type].equalsIgnoreCase(_type)){
+ thisisanerror = false;
+ }
+ if (thisisanerror){
+ state.traceInfo("error", null,"Duplicate:" + _enclosure + "." + tag);
+ }
+ state.traceInfo("error", null,
+ (thisisanerror?"ERROR: ":"WARNING: ") + "\n"+
+ "The tag <"+tag+"> and enclosure <"+_enclosure+"> "+
+ "have been encountered more than once in this mapping file\n"+
+ "For "+ (_enclosure==""?"":"<"+_enclosure+"> ") +tag+"> \n"+
+ " Existing: RAttribute '"+attrib.rAttribute+"'\n"+
+ " type '"+int2str[attrib.type]+"'\n"+
+ " New: RAttribute '"+_attribute+"'\n"+
+ " type '"+_type+"'\n");
+ if(thisisanerror) throw new RuntimeException("Duplicate Enclosures encountered");
+ }
+ }
+ final Attrib attrib = new Attrib();
+ attrib.enclosure = _enclosure==null?"":_enclosure;
+ attrib.rAttribute = _attribute;
+ attrib.type = attribType;
+ tag_instances.add(attrib);
+ }
+
+ /**
+ * Looks up the given enclosure, and returns the attribute
+ * associated with that enclosure, or a null if not found.
+ * @param _enclosure
+ * @return
+ */
+ public Attrib lookup(String _enclosure){
+ if(_enclosure==null) _enclosure="";
+ Iterator iattribs = tag_instances.iterator();
+ while(iattribs.hasNext()){
+ Attrib attrib = (Attrib) iattribs.next();
+ if(attrib.enclosure.equals(_enclosure)){
+ return attrib;
+ }
+ }
+ return null;
+ }
+
+ public boolean elementExists(String tag, String _enclosure)
+ {
+ if(_enclosure==null) _enclosure="";
+ Iterator iattribs = tag_instances.iterator();
+ while(iattribs.hasNext()){
+ Attrib attrib = (Attrib)iattribs.next();
+ if(attrib.enclosure.equals(_enclosure))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The Data Map class holds data for later mapping into the Rules Engine
+ * using the same mapping definition that can be used to upload XML to
+ * an EDD. This interface can also be used to write out XML to a file.
+ *
+ * This isn't a complex implementation. The idea is to collect all the
+ * data we would have written to an XML file, then map it in the same
+ * way with the same tag structure into the EDD. And as a bonus, we
+ * allow for the writing of the data out as XML for debugging or playback
+ * purposes.
+ */
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+import com.dtrules.xmlparser.IXMLPrinter;
+import com.dtrules.xmlparser.XMLPrinter;
+
+
+public class DataMap implements IXMLPrinter{
+ Mapping map;
+ OutputStream out = null;
+ ArrayList<XMLTag> tagStack = new ArrayList<XMLTag>();
+ XMLTag rootTag;
+
+ /**
+ * Write out this DataMap as an XML file. I do not write out
+ * tags with no body (body == null) and no internal structure
+ * (no tag.tags....). This is because the load treats attributes
+ * with null values as having not responded at all. Such
+ * attributes default to the default value specified in the EDD.
+ * When we load the text version however, we can't have a tag
+ * or we will not behave in the same way. A null for a string
+ * will become a zero length string (for example).
+ * @param out
+ */
+ static public void print(XMLPrinter xout, XMLTag tag){
+ if(tag.body == null && tag.tags.size()>0){
+ xout.opentag(tag.tag,tag.attribs);
+ for(XMLTag t : tag.tags){
+ print(xout,t);
+ }
+ xout.closetag();
+ }else{
+ xout.opentag(tag.tag,tag.attribs);
+ xout.printdata(tag.body);
+ xout.closetag();
+ }
+ }
+
+ /**
+ * If created without an output stream, no XML is written.
+ * @param tag
+ */
+ public DataMap(String tag){
+ opentag(tag);
+ rootTag = top();
+ }
+ /**
+ * Constructor you have to use if you wish to use Data Objects to
+ * provide attributes.
+ * @param map - Provides info on the DO's
+ * @param tag
+ * @param xmlOutputStream - Writes an XML file out if specified (not null).
+ */
+ public DataMap(Mapping map, String tag, OutputStream xmlOutputStream){
+ this(tag);
+ this.map = map;
+ this.out = xmlOutputStream;
+ }
+ /**
+ * If created with an output stream, XML is generated and written
+ * to the output stream.
+ * @param tag
+ * @param xmlOutputStream
+ */
+ public DataMap(String tag, OutputStream xmlOutputStream){
+ this(tag);
+ this.out = xmlOutputStream;
+ }
+
+ /**
+ * Write out this DataMap as an XML file
+ * @param out
+ */
+ public void print(OutputStream out){
+ XMLPrinter xout= new XMLPrinter(out);
+ DataMap.print(xout,rootTag);
+ }
+
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth() {
+ return tagStack.size();
+ }
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i){
+ if(i<0 || i>=tagStack.size())return null;
+ return tagStack.get(i).tag;
+ }
+
+ public boolean isInContext(String tag, String key_attribute, Object value){
+ XMLTag t = top();
+ while(t!=null && t!=rootTag){
+ if( t.tag.equals(tag) &&
+ (key_attribute == null ||
+ t.attribs.containsKey(key_attribute) &&
+ (value==null || t.attribs.get(key_attribute).equals(value)))){
+ return true;
+ }
+ t = t.parent;
+ }
+ return false;
+ }
+
+ /**
+ * If we close, then we close all our tags. If an output file has been specified,
+ * we write that out.
+ */
+ public void close() {
+ if(out!=null){
+ print(out);
+ }
+ }
+
+ /**
+ * close the last tag.
+ */
+ public void closetag() {
+ tagStack.remove(tagStack.size()-1);
+ }
+
+ private void newtag(String tag ){
+ XMLTag t = top();
+ if(t!=null && top().body!=null){
+ throw new RuntimeException("You can't have tags and body text within the same XML tag!");
+ }
+ XMLTag newtag = new XMLTag(tag,t);
+ if(t!=null){
+ t.tags.add(newtag);
+ }
+ tagStack.add(newtag);
+ }
+
+ private XMLTag top(){
+ if(tagStack.size()==0)return null;
+ return tagStack.get(tagStack.size()-1);
+ }
+
+ private void addValue(String key, Object value){
+ top().attribs.put(key, value);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ addValue(name9, value9);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9,
+ String name10,Object value10) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ addValue(name9, value9);
+ addValue(name10,value10);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5, String name6, Object value6) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1) {
+ newtag(tag);
+ addValue(name1, value1);
+ }
+
+
+ /*
+ * Open a tag with the given hashmap of values
+ */
+ @SuppressWarnings("unchecked")
+ public void opentag(String tag, HashMap attribs){
+ newtag(tag);
+ for(Object key : attribs.keySet()){
+ addValue((String)key,attribs.get(key));
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String)
+ */
+ public void opentag(String tag) {
+ newtag(tag);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#print_error(java.lang.String)
+ */
+ public void print_error(String errorMsg) {
+ opentag("error","msg",errorMsg);
+ closetag();
+
+ }
+
+ /*
+ * We write the data to the body of the top tag. If multiple printdata() calls
+ * are made, then everything is converted to a String and added together.
+ */
+ public void printdata(Object bodyvalue) {
+ XMLTag t = top();
+ if(t.body==null){
+ t.body = bodyvalue;
+ return;
+ }
+ t.body = t.body.toString() + bodyvalue.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.Object)
+ */
+ public void printdata(String tag, Object bodyvalue) {
+ opentag(tag);
+ printdata(bodyvalue);
+ closetag();
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1, Object body) {
+ opentag(tag,name1,value1);
+ printdata(body);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ String name4, Object value4, Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3, name4, value4);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ String name4, Object value4, String name5, Object value5,
+ Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3, name4, value4, name5, value5);
+ printdata(bodyvalue);
+ closetag();
+
+ }
+
+ /**
+ * Return the Root XMLTag of the data structures
+ * @return
+ */
+ public XMLTag getRootTag(){ return rootTag; }
+ /**
+ * Read the attributes of a Data Object and populate an EDD with
+ * those values. This assumes that the class for the Data Object has
+ * been mapped to an Entity in the Map file for a Rule Set
+ * @param obj
+ * @param tag
+ */
+ public void readDO(Object obj, String tag){
+ String do_name = obj.getClass().getName();
+ ArrayList<DataObjectMap> doMaps = map.dataObjects.get(do_name);
+ DataObjectMap doMap = null;
+ for(DataObjectMap DO : doMaps){
+ if(DO.tag.equals(tag)){
+ doMap = DO;
+ break;
+ }
+ }
+ if(doMap==null){
+ throw new RuntimeException("Unknown Data Object: "+do_name);
+ }
+ try {
+ doMap.mapDO(this, obj);
+ } catch (RulesException e) {
+ throw new RuntimeException("Unknown Data Object: "+do_name);
+ }
+ }
+ /**
+ * Looks up the Key from the Data Object and generates the approprate
+ * open tag structure.
+ * @param obj
+ * @param tag
+ */
+ public void opentag(Object obj, String tag){
+ String do_name = obj.getClass().getName();
+ ArrayList<DataObjectMap> doMaps = map.dataObjects.get(do_name);
+ DataObjectMap doMap = null;
+ if(doMaps != null)for(DataObjectMap DO : doMaps){
+ if(DO.tag.equals(tag)){
+ doMap = DO;
+ break;
+ }
+ }
+ if(doMap==null){
+ throw new RuntimeException("Attempt to map data into the EDD using an Unknown Data Object: "+do_name);
+ }
+ doMap.OpenEntityTag(this, obj);
+ }
+
+ private class XmlLoader implements IGenericXMLParser {
+ DataMap datamap;
+
+ XmlLoader(DataMap datamap){
+ this.datamap = datamap;
+ }
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap<String, String> attribs) throws IOException, Exception {
+ datamap.opentag(tag,attribs);
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag,
+ String body, HashMap<String, String> attribs) throws Exception,
+ IOException {
+ if(body!=null && body.length()>0){
+ datamap.printdata(body);
+ }
+ datamap.closetag();
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ }
+
+ /**
+ * Loads an XML File into a DataMap
+ * @param xml
+ */
+ public void loadXML(InputStream xml) throws RulesException {
+ XmlLoader xmlLoader = new XmlLoader(this);
+ try{
+ GenericXMLParser.load(xml, xmlLoader);
+ }catch(Exception e){
+ throw new RulesException("Bad XML","loadXML",e.toString());
+ }
+ }
+
+}
--- /dev/null
+package com.dtrules.mapping;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.AttributeInfo.Attrib;
+
+/**
+ * Defines the DO accesser to Entity Object Attribute Mapping. Each
+ * instance of a DataObjectMap maps a DO to an Entity. If you need
+ * to be able to map the DO to several Entities, then you will need
+ * several DataObjectMaps, one for each Entity.
+ * @author Paul Snow
+ * May 8, 2008
+ *
+ */
+@SuppressWarnings({"unchecked"})
+class DataObjectMap {
+ String tag; // Entity Tag to look for
+ boolean loaded = false; // Have I initialized this object yet?
+ String dataObjName; // Name for this DO
+ Class dataObj; // This is the Data Object Mapped by this Map
+ // Getter to Attribute Map for this DO
+ String entityName = null; // Names of Entities which receive attributes
+ // from this Data Object
+ String key = null; // The Key identifying this DO
+ String keyAccessor = null; // The name of the Accessor to get the Key
+ String key_attribute = null; // The Attribute identifying the Entity in the XML
+
+ // We figure out what accessors in the DO provide values we can
+ // use populate attributes on the Entity, and we store the accessor to tag
+ // mapping here.
+ HashMap<String,String> tagMap= new HashMap<String,String>();
+
+
+ DataObjectMap(String dataObjName,String entity, String tag, String key,String key_attribute) throws Exception {
+ this.dataObjName = dataObjName;
+ this.entityName = entity;
+ this.tag = tag;
+ this.dataObj = Class.forName(dataObjName);
+ this.key = key;
+ this.key_attribute = key_attribute==null?key:key_attribute;
+ if(key!=null){
+ keyAccessor = "get"+key.substring(0,1).toUpperCase();
+ if(key.length()>1){
+ keyAccessor = keyAccessor+key.substring(1);
+ }
+ }
+ }
+
+ /**
+ * Returns true if an Entity tag has been openned.
+ * @param datamap
+ * @param idataObj
+ * @return
+ * @throws Exception
+ */
+ public boolean OpenEntityTag(DataMap datamap, Object idataObj){
+ try{
+ Class params[] = {};
+ Object paramsObj[] = {};
+ Object keyValue = null;
+ if(keyAccessor!=null){
+ keyValue = dataObj.getMethod(keyAccessor,params).invoke(idataObj,paramsObj);
+ }
+ if(!datamap.isInContext(tag, key_attribute, keyValue)){
+ if(key_attribute!=null){
+ datamap.opentag(tag,key_attribute,keyValue);
+ }else{
+ datamap.opentag(tag);
+ }
+ return true;
+ }
+ return false;
+ }catch(Exception e){
+ return false;
+ }
+ }
+
+ public void mapDO(DataMap datamap, Object idataObj)throws RulesException {
+ if(loaded==false){
+ String err = init(datamap);
+ if(err!=null)throw new RulesException("Undefined","DataObjectMap",err);
+ }
+ Class params[] = {};
+ Object paramsObj[] = {};
+
+ try {
+ boolean needToClose = OpenEntityTag(datamap, idataObj);
+ for(String getter : tagMap.keySet()){
+ String tag = tagMap.get(getter);
+ Method getV = dataObj.getMethod(getter, params);
+ Object v = getV.invoke(idataObj, paramsObj);
+ datamap.printdata(tag, v);
+ }
+ if(needToClose){
+ datamap.closetag();
+ }
+ } catch (SecurityException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (IllegalArgumentException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (NoSuchMethodException e) {
+ throw new RulesException("undefined","DataObjectMap",e.toString());
+ } catch (IllegalAccessException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (InvocationTargetException e) {
+ throw new RulesException("unknown","DataObjectMap",e.toString());
+ }
+ }
+ /**
+ * Returns null if the prefix isn't found.
+ * @param prefix
+ * @param n
+ * @return
+ */
+ private String removePrefix(String prefix, Method method){
+ if(method.getParameterTypes().length!=0) return null;
+ String mName = method.getName();
+ int l = prefix.length();
+ if(mName.length() < l) return null;
+ if(!mName.startsWith(prefix))return null;
+ String first = mName.substring(l,l+1);
+ if(mName.length()>l+1){
+ mName = first.toLowerCase()+mName.substring(l+1);
+ }
+ return mName;
+ }
+ /**
+ * Returns an array of error messages if the initialization fails. This
+ * routine looks through all the getters in the DO and looks for matches
+ * with the tags defined in the mapping file.
+ * @return
+ */
+ public String init(DataMap datamap){
+ loaded = true;
+ try {
+ Class c = Class.forName(dataObjName);
+ Method [] methods = c.getMethods();
+ for(Method method : methods){
+ String tag = removePrefix("is", method);
+ if(tag==null) tag = removePrefix("get",method);
+ if(tag!=null){
+ AttributeInfo info = datamap.map.setattributes.get(tag);
+ if(info!= null) for(Attrib attrib : info.getTag_instances() ){
+ if( entityName.equalsIgnoreCase(attrib.enclosure)){
+ tagMap.put(method.getName(), tag);
+ }
+
+ }
+ }
+ }
+ } catch (ClassNotFoundException e) {
+ return "Could not find the DO: "+dataObjName;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+/**
+ * Holds information about each entity expected in the XML input data.
+ * @author paul snow
+ *
+ */
+class EntityInfo {
+ String id;
+ String name;
+ IREntity entity;
+ String number;
+ String list;
+ /**
+ * Get a new instance of an Entity upon a reference in the data file.
+ * If only one instance of an Entity is to be created, then return
+ * that one. If the Entity is a constant Entity, return the constant
+ * Entity. Otherwise create a new clone and return that.
+ * @return
+ */
+ IREntity getInstance(IRSession s)throws RulesException{
+ if(number.equals("1"))return entity;
+ DTState state = s.getState();
+ IRObject rarray = state.find(RName.getRName(name+"s"));
+
+ IREntity newentity = (IREntity) entity.clone(s);
+ if(rarray!=null && rarray.type() ==IRObject.iArray){
+ ((RArray)rarray).add(newentity);
+ }
+ return newentity;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.interpreter.RXmlValue;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+
+@SuppressWarnings({"unchecked"})
+public class LoadDatamapData extends LoadXMLData {
+
+ public LoadDatamapData(Mapping _map){
+ super(_map);
+ }
+
+ public LoadDatamapData(Mapping _map, IRSession session, String _ruleSetName){
+ super(_map, session, _ruleSetName);
+ }
+
+ XMLTag xmltag = null;
+
+ public void endTag(String[] tagstk, int tagstkptr, XMLTag tag, Object body,
+ HashMap attribs) throws Exception, IOException {
+ this.xmltag = tag;
+ endTag(tagstk,tagstkptr,tag.tag,body,attribs);
+ }
+
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, Object body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ attribs.remove("create entity");
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if creating an Entity, but it can't be null either.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ attribs.remove("set attribute date");
+ if(body instanceof String){
+ String sbody = body.toString();
+ if (sbody.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && sbody.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(sbody);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(sbody);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+ }else {
+ attr = (String) attribs.get("set attribute");
+ }
+ if (attr != null){
+ attribs.remove("set attribute");
+ // Look and see if we have an attribute name defined.
+ if(body!=null){
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity==null){
+ throw new Exception ("No Entity is in the context that defines "+ a.stringValue());
+ }
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(getLong(body));
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(getDouble(body));
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.toString());
+ } else if (type == IRObject.iTime){
+ value = RTime.getRTime((Date)body);
+ } else if (type == IRObject.iEntity) {
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadDatamapData","Entity Tags have to create some Entity Reference");
+ }
+ } else if (type == IRObject.iString) {
+ value = RString.newRString(body.toString());
+ } else if (type == IRObject.iXmlValue){
+ if(xmltag != null){
+ value = new RXmlValue(state,xmltag);
+ }else{
+ throw new RulesException("MappingError","LoadDatamapData","Somehow we are missing the XML Tag for the attribute: "+a);
+ }
+ } else {
+ throw new RulesException("MappingError","LoadDatamapData","Unsupported type encountered: "+RSession.typeInt2Str(type));
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ state.traceInfo("message",null," /"+a+" \""+body+"\" def");
+ }
+ }
+
+ return;
+ }
+
+ long getLong(Object num){
+ if(num.getClass()==BigDecimal.class)return ((BigDecimal)num).longValue();
+ if(num.getClass()==Long.class)return ((Long)num).longValue();
+ if(num.getClass()==Double.class)return ((Double)num).longValue();
+ if(num.getClass()==Integer.class)return((Integer)num).longValue();
+ if(num.getClass()==String.class)return Long.parseLong(num.toString());
+ throw new RuntimeException("Can't figure out the value "+num.toString()+" "+num.getClass().getName());
+ }
+
+ double getDouble(Object num){
+ if(num.getClass()==BigDecimal.class)return ((BigDecimal)num).doubleValue();
+ if(num.getClass()==Long.class)return ((Long)num).doubleValue();
+ if(num.getClass()==Double.class)return ((Double)num).doubleValue();
+ if(num.getClass()==Integer.class)return((Integer)num).doubleValue();
+ if(num.getClass()==String.class)return Double.parseDouble(num.toString());
+ throw new RuntimeException("Can't figure out the value "+num.toString()+" "+num.getClass().getName());
+ }
+
+
+ @Override
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e)throws RulesException {
+ RName listname = RName.getRName(e.getName().stringValue()+"s");
+
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IRObject elist = state.getes(i).get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update any reference to this entity that might be on the Entity Stack.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ for(int i=0;i< state.edepth(); i++){
+ if((state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ (state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+
+/**
+ * LoadMap class is used by the GenerixXMLParser to load the Map defining
+ * the XML to EDD transformation.
+ *
+ * @author Paul Snow
+ *
+ */
+class LoadMap implements IGenericXMLParser {
+ /**
+ * We track if we encountered any errors, but we print as many messages as we can.
+ * Then we report if we failed to load, assuming anyone cares.
+ */
+ private boolean loadSuccessful = true;
+ private HashMap<String, String > undefinedEntities;
+ private HashMap<String, String > definedAttributes;
+
+ private final DTState state;
+ private final EntityFactory ef;
+ private final Mapping map;
+
+ private HashMap<String,String> _attribs;
+
+ /**
+ * @param map
+ */
+ LoadMap(DTState state, Mapping map) {
+ this.map = map;
+ this.state = state;
+ this.ef = state.getSession().getEntityFactory();
+ }
+
+ /**
+ * This boolean is set at the end of loading a file.
+ * @return the loadSuccessful
+ */
+ public boolean isLoadSuccessful() {
+ return loadSuccessful;
+ }
+ /**
+ *
+ */
+
+ public void begin_dataobjects(){}
+
+ public void begin_do2entitymap(){
+
+ String doClass = _attribs.get("class");
+ String key = _attribs.get("key");
+ String key_attribute = _attribs.get("key_attribute");
+ String entity = _attribs.get("entity");
+ String entity_tag = _attribs.get("entity_tag");
+ ArrayList<DataObjectMap> dataobjmaps = map.dataObjects.get(doClass);
+
+ if(dataobjmaps==null){
+ dataobjmaps = new ArrayList<DataObjectMap>();
+ map.dataObjects.put(doClass, dataobjmaps);
+ }
+
+ for(DataObjectMap dataobjmap : dataobjmaps){
+ if(dataobjmap.entityName.equals(entity) &&
+ dataobjmap.tag.equals(entity_tag)){
+ throw new RuntimeException("Duplicate DO to Entity mappings for: "+entity);
+ }
+ }
+
+ try {
+ DataObjectMap dataobjmap = new DataObjectMap(doClass,entity,entity_tag,key,key_attribute);
+ dataobjmaps.add(dataobjmap);
+ } catch (Exception e) {
+ // System.out.println("Undefined Data Object: '"+doClass+"'\n");
+ }
+ }
+
+ /**
+ * Mapping tag. <mapping>
+ * used simply to organize the mapping xml under a single tag.
+ * This does any initialization of the mapping state
+ *
+ */
+ public void begin_mapping () {
+ undefinedEntities = new HashMap<String,String>();
+ definedAttributes = new HashMap<String,String>();
+ loadSuccessful = true;
+ }
+
+ /**
+ * Contains the tags that define the XML to EDD mapping. Right
+ * now that is all we implement. In the future we will add an
+ * EDD to XML mapping set of tags, maybe.
+ *
+ */
+ public void begin_XMLtoEDD () {}
+
+ /**
+ * Tag groups all the entity tags.
+ */
+ public void begin_entities () {}
+
+
+ /**
+ * Process an Entity tag. Example:
+ * <entity name="individual" number="+"/>
+ * Valid number specifications are:
+ * "*" (0 or more)
+ * "+" (1 or more)
+ * "1" (1)
+ */
+ public void begin_entity () {
+ String entity = ((String) _attribs.get("name")).toLowerCase();
+ String number = (String) _attribs.get("number");
+
+ IREntity rEntity = map.getSession().getEntityFactory().findRefEntity(RName.getRName(entity));
+ if(rEntity==null){
+ System.out.println("The Entity specified, '"+entity+"' is not defined");
+ loadSuccessful = false;
+ }
+ if(number.equals("1") || number.equals("+") || number.equals("*")){
+ this.map.entityinfo.put(entity,number);
+ }else{
+
+ try {
+ state.traceInfo("error", null,
+ "Number value must be '1', '*', or '+'. Encounterd: "+number);
+ } catch (RulesException e) {} // Ignore because we are going to throw an exception anyway.
+ throw new RuntimeException("Number value must be '1', '*', or '+'. Encounterd: "+number);
+ }
+ }
+
+ /**
+ * Every entity that defines the given attribute gets its instances logged
+ * in to the given list.
+ */
+ public void addalltolist () {
+ String withAttribute = (String) _attribs.get("withAttribute");
+ String toList = (String) _attribs.get("toList");
+ String pair[] = {withAttribute.toLowerCase(),toList.toLowerCase()};
+ map.attribute2listPairs.add(pair);
+
+ }
+
+ /**
+ * Groups initalentity tags.
+ *
+ */
+ public void begin_initialization(){}
+
+ /**
+ * Defines an entity to be placed on the Entity Stack at initialization.
+ *
+ */
+ public void begin_initialentity(){
+ String entity = (String) _attribs.get("entity");
+ this.map.entitystack.add(entity.toLowerCase());
+ }
+
+ /**
+ * Groups all of the mapping tags.
+ *
+ */
+ public void begin_map(){}
+
+
+ /**
+ * Saves away the information required to create an entity.
+ *
+ */
+ public void begin_createentity(){
+ final String entity = (String) _attribs.get("entity");
+ final String tag = (String) _attribs.get("tag");
+ final String attribute = (String) _attribs.get("attribute");
+ final String value = (String) _attribs.get("value");
+ final String id = (String) _attribs.get("id");
+ String list = (String) _attribs.get("list");
+ list = list==null?"":list;
+
+ try {
+ IREntity theentity = ef.findRefEntity(RName.getRName(entity));
+ if(theentity==null)throw new Exception();
+ } catch (Exception e) {
+ System.out.println("\nThe Entity "+entity+" isn't defined by the EDD");
+ loadSuccessful = false;
+ }
+
+ EntityInfo info = new EntityInfo();
+ info.id = id;
+ info.name = entity.toLowerCase();
+ info.list = list.toLowerCase().trim();
+ if(attribute== null || value==null ){
+ this.map.requests.put(tag,info);
+ }else{
+ this.map.multiple.put(tag,attribute);
+ this.map.requests.put(value,info);
+ }
+ }
+
+
+
+ /**
+ * The Rules Engine expects everything to be lowercase!!
+ * Be careful how you use attributes!
+ */
+ public void begin_setattribute(){
+ String tag = (String) _attribs.get("tag");
+ String type = (String) _attribs.get("type");
+ String enclosure = (String) _attribs.get("enclosure"); // This is an optional tag enclosure....
+ String rattribute = (String) _attribs.get("RAttribute"); // This is the Entity Attribute name
+
+ if(rattribute == null)rattribute = tag; // If no rattribute name is specified, default to the tag.
+
+ AttributeInfo info = (AttributeInfo) this.map.setattributes.get(tag);
+ if(info==null){
+ info = new AttributeInfo();
+ }
+ try {
+ IREntity e = ef.findRefEntity(RName.getRName(enclosure));
+ if(e==null){
+ if(!undefinedEntities.containsKey(enclosure)){
+ System.out.println("The entity "+enclosure+" isn't defined in the EDD");
+ loadSuccessful = false;
+ undefinedEntities.put(enclosure, enclosure);
+ }
+ }else{
+ if(definedAttributes.containsKey(enclosure+"*"+rattribute)){
+ System.out.println("The Entity "+enclosure+" and Attribute "+rattribute +" have multiple definitions");
+ loadSuccessful = false;
+ }
+ if(e.getEntry(RName.getRName(rattribute))==null){
+ System.out.println("The Attribute "+rattribute+" isn't defined by "+enclosure);
+ loadSuccessful = false;
+ }
+ info.add(state,tag, enclosure,rattribute.toLowerCase(),type);
+ }
+ } catch (RulesException e) {}
+
+ this.map.setattributes.put(tag,info);
+ }
+
+
+ /**
+ * Because all of the tags possible within a Mapping XML are defined, and because we only have to load the Mapping
+ * File once at initialization, all we do here is take our parameters and store them away within our class, then
+ * by intraspection load the proper method for this tag, and execute it.
+ */
+ @SuppressWarnings({"unchecked"})
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+
+ _attribs = (HashMap<String,String>)attribs;
+
+ if(state.testState(DTState.VERBOSE)){
+ String data = "<"+tag+" ";
+ for(Object v : attribs.keySet()){
+ data += v+" = '"+attribs.get(v)+"'";
+ }
+ state.traceInfo("Load",null,data+">\n");
+ }
+
+ try {
+ this.getClass().getMethod("begin_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println( e.getCause().getMessage());
+ loadSuccessful = false;
+ } catch (NoSuchMethodException e) {
+ System.out.println("No implmentation for "+tag+"()");
+ throw new RuntimeException("Undefined tag found in mapping file: "+tag);
+ }
+ }
+
+ /**
+ * We are not doing anything on an end tag right now.
+ */
+ @SuppressWarnings({"unchecked"})
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+
+
+ }
+ /**
+ * All errors throw an Exception. If we run into problems, there is no
+ * recovery, no fix.
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+/**
+ * Loads the mapping file (the description of how data should be moved
+ * from XML to the EDD)
+ *
+ */
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class LoadMapping implements IGenericXMLParser {
+ Mapping map;
+ int codeCnt = 0;
+ IRSession session;
+ IRObject def;
+ DTState state;
+ String ruleSetName;
+ static DateFormat df_in = new SimpleDateFormat ("yyyy-MM-dd");
+
+ static DateFormat df_out = new SimpleDateFormat ("MM/dd/yyyy");
+
+
+ public LoadMapping(Mapping _map){
+ map = _map;
+ }
+
+ public LoadMapping(Mapping _map, IRSession session, String _ruleSetName){
+ map = _map;
+ this.session = session;
+ this.state = session.getState();
+ this.ruleSetName = _ruleSetName;
+
+ try{ // Cache the def operator.
+ def = session.getState().find(RName.getRName("def"));
+ }catch(Exception e){
+ try {
+ state.traceInfo("error", null,"General Rules Engine Failure");
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+
+ Iterator<RName> es = this.map.entities.keySet().iterator();
+ while(es.hasNext()){
+ RName ename = (RName) es.next();
+ try {
+ IREntity e = findEntity(ename.stringValue().toLowerCase(),null,null);
+ state.entitypush(e);
+ } catch (RulesException e) {
+ try {
+ state.traceInfo("error", null,"Failed to initialize the Entity Stack (Failed on "+ename+")\n"+e);
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Looks to make sure that we have not yet created an Entity
+ * of this name with the given code. If we have, we return the
+ * earlier created Entity. Otherwise, we create a new instance.
+ * @param entity -- We assume this is a valid Entity name (no dot syntax)
+ * @param code
+ * @return
+ * @throws RulesException
+ */
+ IREntity findEntity( String entity, String code, EntityInfo info) throws RulesException{
+ String number = (String) this.map.entityinfo.get(entity);
+ IREntity e;
+ if(number==null){
+ number = "*";
+ }
+ if(number.equals("1")){
+ e = (IREntity)entities.get(entity);
+ if(e==null){
+ e = session.getState().findEntity(RName.getRName(entity+"."+entity));
+ if(e==null){
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ entities.put(entity,e);
+ }
+ }else { // We assume number.equals("*") || number.equals("+")
+ e = null;
+ String key = "";
+ if(code!=null && code.length()!=0) {
+ key = entity+"$"+code;
+ e = (IREntity)entities.get(key);
+ }
+ if(e==null) {
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ if(code!=null) entities.put(key,e);
+ }
+ if(e==null)throw new RulesException("undefined","LoadMapping.findEntity()","Failed to create the entity "+entity);
+ UpdateReferences(e,info);
+ return e;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ String name = tag; // We assume the tag might create an entity
+ @SuppressWarnings("unused")
+ boolean traceopen = false;
+ EntityInfo info = (EntityInfo) this.map.requests.get(name);
+ AttributeInfo aInfo = (AttributeInfo) this.map.setattributes.get(tag);
+
+
+ // If I get info, then create an entity.
+ // Get the code from this tag.
+ // If a fixed entity name is specified,
+ // or the tag name, use it. Otherwise use the multiple name
+ if(info!=null){
+ Object objCode = attribs.get(info.id);
+ String code = objCode==null?"":objCode.toString();
+ String eName = info.name;
+ if (eName == null || eName.length() <= 0)
+ {
+ eName = (String) attribs.get("name");
+ }
+ IREntity e = findEntity(eName, code, info); // Look up the entity I should create.
+ if(e!=null){ // I hope to goodness I can find it!
+ attribs.put("create entity","true");
+ if(code.length()!=0) {
+ e.put(IREntity.mappingKey,RString.newRString(code));
+ }else{
+ e.put(IREntity.mappingKey,RString.newRString("v"+ (++codeCnt)));
+ }
+
+ state.entitypush(e);
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("createEntity", "name='"+info.name+"' id='"+code+"'");
+ traceopen = true;
+ }
+ }else{
+
+ state.traceInfo("error", null, "The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ throw new Exception("The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ }
+ }
+
+ if(aInfo!=null){ // If we are supposed to set an attribute, then we set ourselves up
+ // to define the entity attribute on the end tag. We may be setting this
+ // Attribute to the value of the Entity we just created/looked up.
+ /**
+ * First check enclosures, then check the blank case. This allows
+ * the user to specify a default mapping, yet still direct some attributes to
+ * specific destinations based on the enclosure.
+ */
+ AttributeInfo.Attrib attrib;
+ { // Not only do you have to match the attribute name,
+ int i=tagstkptr-2; // But you must match the immediately enclosing tag
+ attrib = aInfo.lookup(tagstk[i]);
+ if(attrib!=null){
+ queueSetAttribute(attrib, attribs);
+ }
+ }
+ attrib = aInfo.lookup(""); // If I don't find the enclosure defined, look to see
+ queueSetAttribute(attrib,attribs); // if a general default is defined.
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if we created an Entity.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ if (body.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && body.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(body);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(body);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+
+ if ((attr = (String) attribs.get("set attribute"))!=null){
+ // Look and see if we have an attribute name defined.
+ {
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity!=null){
+
+
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.length()==0? "false" : body);
+ } else if (type == IRObject.iTime){
+ if(body.trim().length()>0){
+ value = RTime.getRDate(body);
+ if(value == null){
+ throw new RulesException("MappingError","LoadMapping","Bad Date... Could not parse '"+body+"'");
+ }
+ }else{
+ value = RNull.getRNull();
+ }
+ } else if (type == IRObject.iEntity){
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadMapping","Entity Tags have to create some Entity Reference");
+ }
+ }else {
+ value = RString.newRString(body);
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ /**
+ * Does nothing if the info is null... Just means we are not mapping this attribute.
+ * Otherwise it updates the attribs hashmap.
+ *
+ * @param info
+ */
+ private void queueSetAttribute( AttributeInfo.Attrib attrib, HashMap attribs){
+ if(attrib==null)return;
+ switch (attrib.type ){
+ case AttributeInfo.DATE_STRING_CODE :
+ attribs.put("set attribute date",attrib.rAttribute);
+ break;
+ case AttributeInfo.STRING_CODE :
+ case AttributeInfo.NONE_CODE :
+ case AttributeInfo.INTEGER_CODE :
+ case AttributeInfo.BOOLEAN_CODE :
+ case AttributeInfo.FLOAT_CODE :
+ case AttributeInfo.ENTITY_CODE :
+ case AttributeInfo.XMLVALUE_CODE :
+ attribs.put("set attribute",attrib.rAttribute);
+ break;
+ default:
+ throw new RuntimeException("Bad Type Code "+attrib.type+" in com.dtrules.mapping.AttributeInfo: "+attrib.rAttribute);
+ }
+ }
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e, EntityInfo info)throws RulesException {
+ RName listname;
+ if(info!=null && info.list.length()==0){
+ listname = RName.getRName(e.getName().stringValue()+"s");
+ }else{
+ listname = RName.getRName(info.list);
+ }
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IREntity entity = state.getes(i);
+ IRObject elist = entity.get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update the reference to this entity that might be on the Entity Stack.
+ // DON'T go wild. Only look at the top entity (or you may overwrite a reference
+ // you'd rather leave alone.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ int i=state.edepth()-1;
+ if(((IREntity)state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ ((IREntity)state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+/**
+ * Loads the mapping file (the description of how data should be moved
+ * from XML to the EDD)
+ *
+ */
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class LoadXMLData implements IGenericXMLParser {
+ Mapping map;
+ int codeCnt = 0;
+ IRSession session;
+ IRObject def;
+ DTState state;
+ String ruleSetName;
+ static DateFormat df_in = new SimpleDateFormat ("yyyy-MM-dd");
+
+ static DateFormat df_out = new SimpleDateFormat ("MM/dd/yyyy");
+
+
+ public LoadXMLData(Mapping _map){
+ map = _map;
+ }
+
+ public LoadXMLData(Mapping _map, IRSession session, String _ruleSetName){
+ map = _map;
+ this.session = session;
+ this.state = session.getState();
+ this.ruleSetName = _ruleSetName;
+
+ try{ // Cache the def operator.
+ def = session.getState().find(RName.getRName("def"));
+ }catch(Exception e){
+ try {
+ state.traceInfo("error", null,"General Rules Engine Failure");
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+
+ for(RName ename : this.map.entities.keySet()){
+ try {
+ IREntity e = findEntity(ename.stringValue().toLowerCase(),null,null);
+ state.entitypush(e);
+ } catch (RulesException e) {
+ try {
+ state.traceInfo("error", null,"Failed to initialize the Entity Stack (Failed on "+ename+")\n"+e);
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Looks to make sure that we have not yet created an Entity
+ * of this name with the given code. If we have, we return the
+ * earlier created Entity. Otherwise, we create a new instance.
+ * @param entity -- We assume this is a valid Entity name (no dot syntax)
+ * @param code
+ * @return
+ * @throws RulesException
+ */
+ IREntity findEntity( String entity, String code, EntityInfo info) throws RulesException{
+ String number = (String) this.map.entityinfo.get(entity);
+ IREntity e;
+ if(number==null){
+ number = "*";
+ }
+ if(number.equals("1")){
+ e = (IREntity)entities.get(entity);
+ if(e==null){
+ e = session.getState().findEntity(RName.getRName(entity+"."+entity));
+ if(e==null){
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ entities.put(entity,e);
+ }
+ }else { // We assume number.equals("*") || number.equals("+")
+ e = null;
+ String key = "";
+ if(code!=null && code.length()!=0) {
+ key = entity+"$"+code;
+ e = (IREntity)entities.get(key);
+ }
+ if(e==null) {
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ if(code!=null) entities.put(key,e);
+ }
+ if(e==null)throw new RulesException("undefined","LoadXMLData.findEntity()","Failed to create the entity "+entity);
+ UpdateReferences(e,info);
+ return e;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ String name = tag; // We assume the tag might create an entity
+ @SuppressWarnings("unused")
+ boolean traceopen = false;
+ EntityInfo info = (EntityInfo) this.map.requests.get(name);
+ AttributeInfo aInfo = (AttributeInfo) this.map.setattributes.get(tag);
+
+
+ // If I get info, then create an entity.
+ // Get the code from this tag.
+ // If a fixed entity name is specified,
+ // or the tag name, use it. Otherwise use the multiple name
+ if(info!=null){
+ Object objCode = attribs.get(info.id);
+ String code = objCode==null?"":objCode.toString();
+ String eName = info.name;
+ if (eName == null || eName.length() <= 0)
+ {
+ eName = (String) attribs.get("name");
+ }
+ IREntity e = findEntity(eName, code, info); // Look up the entity I should create.
+ if(e!=null){ // I hope to goodness I can find it!
+ attribs.put("create entity","true");
+ if(code.length()!=0) {
+ e.put(IREntity.mappingKey,RString.newRString(code));
+ }else{
+ e.put(IREntity.mappingKey,RString.newRString("v"+ (++codeCnt)));
+ }
+
+ state.entitypush(e);
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("createEntity", "name='"+info.name+"' id='"+code+"'");
+ traceopen = true;
+ }
+ }else{
+
+ state.traceInfo("error", null, "The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ throw new Exception("The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ }
+ }
+
+ if(aInfo!=null){ // If we are supposed to set an attribute, then we set ourselves up
+ // to define the entity attribute on the end tag. We may be setting this
+ // Attribute to the value of the Entity we just created/looked up.
+ /**
+ * First check enclosures, then check the blank case. This allows
+ * the user to specify a default mapping, yet still direct some attributes to
+ * specific destinations based on the enclosure.
+ */
+ AttributeInfo.Attrib attrib;
+ { // Not only do you have to match the attribute name,
+ int i=tagstkptr-2; // But you must match the immediately enclosing tag
+ if(i>=0){
+ attrib = aInfo.lookup(tagstk[i]);
+ if(attrib!=null){
+ queueSetAttribute(attrib, attribs);
+ }
+ }
+ }
+ attrib = aInfo.lookup(""); // If I don't find the enclosure defined, look to see
+ queueSetAttribute(attrib,attribs); // if a general default is defined.
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if we created an Entity.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ if (body.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && body.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(body);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(body);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+
+ if ((attr = (String) attribs.get("set attribute"))!=null){
+ // Look and see if we have an attribute name defined.
+ {
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity!=null){
+
+
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.length()==0? "false" : body);
+ } else if (type == IRObject.iTime){
+ if(body.trim().length()>0){
+ value = RTime.getRDate(body);
+ if(value == null){
+ throw new RulesException("MappingError","LoadXMLData","Bad Date... Could not parse '"+body+"'");
+ }
+ }else{
+ value = RNull.getRNull();
+ }
+ } else if (type == IRObject.iEntity){
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadXMLData","Entity Tags have to create some Entity Reference");
+ }
+ }else {
+ value = RString.newRString(body);
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ /**
+ * Does nothing if the info is null... Just means we are not mapping this attribute.
+ * Otherwise it updates the attribs hashmap.
+ *
+ * @param info
+ */
+ private void queueSetAttribute( AttributeInfo.Attrib attrib, HashMap attribs){
+ if(attrib==null)return;
+ switch (attrib.type ){
+ case AttributeInfo.DATE_STRING_CODE :
+ attribs.put("set attribute date",attrib.rAttribute);
+ break;
+ case AttributeInfo.STRING_CODE :
+ case AttributeInfo.NONE_CODE :
+ case AttributeInfo.INTEGER_CODE :
+ case AttributeInfo.BOOLEAN_CODE :
+ case AttributeInfo.FLOAT_CODE :
+ case AttributeInfo.ENTITY_CODE :
+ case AttributeInfo.XMLVALUE_CODE :
+ attribs.put("set attribute",attrib.rAttribute);
+ break;
+ default:
+ throw new RuntimeException("Bad Type Code "+attrib.type+" in com.dtrules.mapping.AttributeInfo: "+attrib.rAttribute);
+ }
+ }
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e, EntityInfo info)throws RulesException {
+ RName listname;
+ if(info!=null && info.list.length()==0){
+ listname = RName.getRName(e.getName().stringValue()+"s");
+ }else{
+ listname = RName.getRName(info.list);
+ }
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IREntity entity = state.getes(i);
+ IRObject elist = entity.get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update the reference to this entity that might be on the Entity Stack.
+ // DON'T go wild. Only look at the top entity (or you may overwrite a reference
+ // you'd rather leave alone.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ int i=state.edepth()-1;
+ if(((IREntity)state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ ((IREntity)state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+import com.dtrules.xmlparser.XMLPrinter;
+
+@SuppressWarnings({"unchecked"})
+public class MapGenerator implements IGenericXMLParser {
+ String[] tagstk;
+ int tagstkptr;
+ String tag;
+ HashMap<String,String> attribs;
+ String body;
+
+ XMLPrinter out = null;
+ String mapping = null;
+
+ /**
+ * These are the list of entities for which at least one
+ * Attribute will be set by this mapping file.
+ */
+ ArrayList <String> entities = new ArrayList<String>();
+ ArrayList <String> unreferenced = new ArrayList<String>();
+ /**
+ * Returns true if the particular mapping here is one of the
+ * input sources for this attribute.
+ */
+ boolean inputMatch(String inputs){
+ /** Deal quickly with the trival case **/
+ if(inputs.trim().length()==0) return false;
+ StringTokenizer tokenizer = new StringTokenizer(inputs," \t\r\n,");
+ while(tokenizer.hasMoreTokens()){
+ if(tokenizer.nextToken().equalsIgnoreCase(mapping))return true;
+ }
+ return false;
+ }
+
+ public void end_entity(){
+ String attribute = (String) attribs.get("attribute");
+ String type = (String) attribs.get("type");
+ String input = (String) attribs.get("input");
+ String entity = attribs.get("entityname").toLowerCase().trim();
+
+ if(inputMatch(input)){
+ out.printdata("setattribute",
+ "tag" ,attribute,
+ "RAttribute" ,attribute,
+ "enclosure" ,entity,
+ "type" ,type,
+ null);
+ if(!entities.contains(entity)){
+ entities.add(entity);
+ }else{
+ if(unreferenced.contains(entity)){
+ unreferenced.remove(entity);
+ }
+ }
+ }else{
+ if(!entities.contains(entity)){
+ entities.add(entity);
+ if(!unreferenced.contains(entity)){
+ unreferenced.add(entity);
+ }
+ }
+ }
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+ this.tagstk = tagstk;
+ this.tagstkptr = tagstkptr;
+ this.tag = tag.toLowerCase();
+ this.attribs = attribs;
+ this.body = null;
+
+ try {
+ this.getClass().getMethod("begin_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println(e.getCause().getMessage());
+ } catch (NoSuchMethodException e) {
+ //Ignore tags we don't know.
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IGenericXMLParser#endTag(java.lang.String[], int, java.lang.String, java.lang.String, java.util.HashMap)
+ */
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+ this.tagstk = tagstk;
+ this.tagstkptr = tagstkptr;
+ this.tag = tag;
+ this.attribs = attribs;
+ this.body = body;
+
+ try {
+ this.getClass().getMethod("end_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println(e.getCause().getMessage());
+ } catch (NoSuchMethodException e) {
+ //System.out.println("Unknown: end_"+tag);
+ }
+ }
+
+ /* Something required of the XML parser.
+ * @see com.dtrules.xmlparser.IGenericXMLParser#error(java.lang.String)
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ public void generateMapping(String mapping, String inputfile, String outputfile) throws Exception {
+ FileInputStream input = new FileInputStream(inputfile);
+ XMLPrinter out = new XMLPrinter(new FileOutputStream(outputfile));
+ generateMapping(mapping,input,out);
+ }
+ /**
+ * Given an EDD XML, makes a good stab at generating a Mapping file for a given
+ * mapping source. The mapping source is specified as an input in the input column
+ * in the EDD.
+ * @param mapping
+ * @param input
+ * @param out
+ * @throws Exception
+ */
+ public void generateMapping(String mapping, InputStream input, XMLPrinter out)throws Exception {
+ this.out = out;
+ this.mapping = mapping;
+ out.opentag("mapping");
+ out.opentag("XMLtoEDD");
+
+ out.opentag("map");
+ GenericXMLParser.load(input,this);
+
+ for(String entity : entities){
+ out.printdata("createentity",
+ "entity", entity,
+ "tag" , entity,
+ "id" , "id",
+ null);
+ }
+ out.closetag();
+
+ out.opentag("entities");
+ for(String entity : entities) {
+ out.printdata("entity","name",entity,"number","*",null);
+ }
+ out.closetag();
+
+ out.opentag("initialization");
+ for(String entity : unreferenced){
+ out.printdata("initialentity","entity",entity,"epush","true",null);
+ }
+ out.closetag();
+
+ out.close();
+ }
+
+
+ public static void main(String args[])throws Exception{
+ String path = "C:/eb/workspace/AutoAssignmentDevelopment/";
+ String mapping = "main";
+ InputStream input = new FileInputStream(path+"xml/ny_eb_edd.xml");
+ MapGenerator mg = new MapGenerator();
+ FileOutputStream os = new FileOutputStream(path+"temp/gen_map.xml");
+ XMLPrinter out = new XMLPrinter(os);
+
+ mg.generateMapping(mapping, input, out);
+
+ }
+
+
+ /**
+ * @return the entities
+ */
+ public ArrayList<String> getEntities() {
+ return entities;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+/**
+ * The Mapping class is used to load XML formated data into an instance of
+ * an EntityFactory.
+ * @author Paul Snow
+ *
+ */
+public class Mapping {
+
+ private final DTState state;
+
+ private final IRSession session;
+
+ HashMap<RName,EntityInfo> entities = new HashMap<RName,EntityInfo>();
+ HashMap<String,String> multiple = new HashMap<String,String>(); // Specifies a tag that uses an attribute to specify what entity to create.
+ HashMap<String,EntityInfo> requests = new HashMap<String,EntityInfo>();
+ HashMap<String,String> entityinfo = new HashMap<String,String>();
+ HashMap<String,ArrayList<DataObjectMap>>dataObjects = new HashMap<String,ArrayList<DataObjectMap>>();
+ /**
+ * List of attribute/list pairs. Every entity that defines the given attribute has every instance saved in the given list.
+ * Each entry is an array of two strings, the attribute and the list name.
+ */
+ ArrayList<String[]> attribute2listPairs = new ArrayList<String[]>();
+
+ /**
+ * A List of entities that should be created at intialization and put on the Entity Stack.
+ */
+ ArrayList<String> entitystack = new ArrayList<String>(); // Specifies what Entities should be on the Entity Stack to begin with.
+
+
+ /**
+ * This is the set of Attribute objects used to map XML tags to Attributes on Entities.
+ */
+ HashMap<String,AttributeInfo> setattributes = new HashMap<String,AttributeInfo>(); // Sets an attribute.
+
+
+ private Mapping(IRSession session){
+ this.session = session;
+ this.state = session.getState();
+ }
+
+ private void initialize(){
+ for(String entity : entitystack){
+ try {
+ IREntity newEntity = ((RSession)session).createEntity(null,entity);
+ session.getState().entitypush(newEntity);
+ } catch (RulesException e) {
+ throw new RuntimeException("Failed to initialize the Entity Stack: "+e);
+ }
+ }
+ }
+
+ /**
+ * For internal use only. If you need a Mapping object, get it from the appropriate
+ * RuleSet object.
+ * @param rd
+ * @param session
+ * @param filename
+ * @return
+ */
+ public static Mapping newMapping(RulesDirectory rd, IRSession session, String filename){
+ Mapping mapping = new Mapping(session);
+ try {
+ InputStream s = session.getRuleSet().openfile(filename);
+ session.getState().traceTagBegin("loadMapping", "file='"+filename+"'");
+ mapping.loadMap(s);
+ session.getState().traceTagEnd("loadMapping",null);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return mapping;
+ }
+
+
+ /**
+ * Clones the mapping structures for use by a given session
+ * @param session
+ * @param amapping
+ * @return
+ */
+ public Mapping clone(IRSession session){
+ Mapping mapping = new Mapping(session);
+ mapping.entities = entities;
+ mapping.multiple = multiple;
+ mapping.requests = requests;
+ mapping.entityinfo = entityinfo;
+ mapping.entitystack = entitystack;
+ mapping.setattributes = setattributes;
+ mapping.attribute2listPairs = attribute2listPairs;
+ mapping.dataObjects = dataObjects;
+ mapping.initialize();
+ return mapping;
+ }
+
+
+ /**
+ * Constructor for creating a Mapping. This has been deprecated because
+ * building a map this way reloads the mapping file over and over. Instead
+ * you should use:
+ *
+ * Mapping map = session.getMapping();
+ *
+ * @param rd
+ * @param session
+ * @param rs
+ * @deprecated
+ */
+ public Mapping(RulesDirectory rd,IRSession session, RuleSet rs){
+ this.session = session;
+ this.state = session.getState();
+ String filename = rs.getMapPath().get(0);
+ try {
+ InputStream s = session.getRuleSet().openfile(filename);
+ session.getState().traceTagBegin("loadMapping", "file='"+filename+"'");
+ this.loadMap(s);
+ session.getState().traceTagEnd("loadMapping",null);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Load parses XML to EDD Map file into a set of actions
+ * which can be used to build an EDD file.
+ * <br><br>
+ *
+ * @param file
+ */
+ protected void loadMap(InputStream xmlStream) throws Exception {
+ LoadMap map = new LoadMap(state,this);
+ GenericXMLParser.load(xmlStream,map);
+ if(!map.isLoadSuccessful()){
+
+ throw new Exception("Map failed to load due to errors!");
+ }
+ }
+
+ public void loadData(IRSession session, String dataSource )throws RulesException {
+ loadData(session, dataSource, dataSource);
+ }
+
+ public void loadData(IRSession session, String dataSource, String source )throws RulesException {
+ InputStream input = session.getRuleSet().openfile(dataSource);
+ if(input == null){
+ throw new RulesException("File Not Found","Mapping.loadData()","Could not open "+dataSource);
+ }
+ loadData(session,input,source);
+ }
+
+ /**
+ * This is the state for dataloading... So that data can be split over multiple files, we
+ * cache our LoadXMLData object between calls to loadData().
+ */
+ LoadXMLData dataloader = null;
+
+ /**
+ * Loads data using this mapping from an XML data Source into the given session.
+ * @param session
+ * @param dataSource
+ * @throws RulesException
+ */
+ public void loadData (IRSession session, InputStream dataSource, String source) throws RulesException {
+ if(dataloader ==null) {
+ dataloader = new LoadXMLData(this,session,session.getRuleSet().getName());
+ }
+ if(source==null){
+ source = "XML file";
+ }
+ try {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagBegin("dataLoad","source='"+source+"'");
+ }
+
+ GenericXMLParser.load(dataSource, dataloader);
+
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("dataLoad",null);
+ }
+ } catch (Exception e) {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("dataLoad",null);
+ }
+ throw new RulesException("Parse Error","LoadMap.loadData()",e.getMessage());
+ }
+ }
+
+ /**
+ * Load an in Memory data structure into the given session.
+ * @param session
+ * @param datasrc
+ * @throws RulesException
+ */
+ public void loadData(IRSession session, DataMap datasrc)throws RulesException {
+ if(dataloader ==null) {
+ dataloader = new LoadDatamapData(this,session,session.getRuleSet().getName());
+ }
+ try {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagBegin("loadData","");
+ }
+ XMLTag tag = datasrc.getRootTag();
+ processTag(tag);
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("loadData",null);
+ }
+ }catch(Exception e){
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("loadData",null);
+ }
+ throw new RulesException("Parse Error","LoadMap.loadData()",e.getMessage());
+ }
+
+ }
+ String tagstk[] = new String[1000];
+ int tagstkptr = 0;
+ /**
+ * Load a tag into a session.
+ */
+ void processTag(XMLTag tag) throws Exception {
+ tagstk[tagstkptr++] = tag.tag;
+ dataloader.beginTag(tagstk, tagstkptr, tag.tag, tag.attribs);
+ for(XMLTag nextTag : tag.tags){
+ state.traceTagBegin("process", null);
+ processTag(nextTag);
+ state.traceTagEnd("process", null);
+ }
+ ((LoadDatamapData)dataloader).endTag(tagstk, tagstkptr, tag, tag.body, tag.attribs);
+ tagstkptr--;
+ tagstk[tagstkptr]= null;
+ }
+
+
+ /**
+ * @return the state
+ */
+ public DTState getState() {
+ return state;
+ }
+
+
+ /**
+ * @return the session
+ */
+ public IRSession getSession() {
+ return session;
+ }
+
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.dtrules.mapping;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This object represents an XML tag, but I avoid serializaiton under
+ * the assumption that any conversion to a string would have been
+ * undone by a conversion from a string back to the object anyway. I
+ * also use the same structure for both tagged data and a tag holding
+ * tags.
+ *
+ * @author Paul Snow
+ * Sep 24, 2007
+ *
+ */
+public class XMLTag {
+ String tag;
+ HashMap<String, Object> attribs = new HashMap<String,Object>();
+ ArrayList<XMLTag> tags = new ArrayList<XMLTag>();
+ Object body = null;
+ XMLTag parent;
+
+ public XMLTag(String tag, XMLTag parent){
+ this.tag = tag;
+ this.parent = parent;
+ }
+
+ public String toString(){
+ String r = "<"+tag;
+ for(String key : attribs.keySet()){
+ r +=" "+key +"='"+attribs.get(key).toString()+"'";
+ }
+ if(body != null){
+ String b = body.toString();
+ if(b.length()>20){
+ b = b.substring(0,18)+"...";
+ }
+ r +=">"+b+"</"+tag+">";
+ }else if( tags.size()==0 ){
+ r += "/>";
+ }else{
+ r += ">";
+ }
+ return r;
+ }
+
+ /**
+ * @return the tag
+ */
+ public String getTag() {
+ return tag;
+ }
+
+ /**
+ * @param tag the tag to set
+ */
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * @return the tags
+ */
+ public ArrayList<XMLTag> getTags() {
+ return tags;
+ }
+
+ /**
+ * @param tags the tags to set
+ */
+ public void setTags(ArrayList<XMLTag> tags) {
+ this.tags = tags;
+ }
+
+ /**
+ * @return the body
+ */
+ public Object getBody() {
+ return body;
+ }
+
+ /**
+ * @param body the body to set
+ */
+ public void setBody(Object body) {
+ this.body = body;
+ }
+
+ /**
+ * @return the parent
+ */
+ public XMLTag getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(XMLTag parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return the attribs
+ */
+ public HashMap<String, Object> getAttribs() {
+ return attribs;
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.session.DTState;
+
+/**
+ * A structure for holding information about Attributes. Instances of AttributeInfo are stored in the setAttributes HashMap.
+ * Note that Attributes are a bit more complex than Entities. We allow not only the tag to be specfied, but the enclosing tag
+ * for the identification of an Attribute. To further complicate things, we can specify different target attributes...
+ * @author ps24876
+ *
+ */
+@SuppressWarnings({"unchecked"})
+class AttributeInfo {
+
+ public static final String DATE_STRING_TYPE = "DateString"; //Strings
+ public static final String STRING_TYPE = "String";
+ public static final String INTEGER_TYPE = "Integer";
+ public static final String NONE_TYPE = "None";
+ public static final String FLOAT_TYPE = "Float";
+ public static final String BOOLEAN_TYPE = "Boolean";
+ public static final String ARRAY_TYPE = "list";
+ public static final String ENTITY_TYPE = "entity";
+ public static final String XMLVALUE_TYPE = "XmlValue";
+
+ public static final int DATE_STRING_CODE = 0; //Codes
+ public static final int STRING_CODE = 1;
+ public static final int NONE_CODE = 2;
+ public static final int INTEGER_CODE = 3;
+ public static final int FLOAT_CODE = 4;
+ public static final int BOOLEAN_CODE = 5;
+ public static final int ARRAY_CODE = 6;
+ public static final int ENTITY_CODE = 7;
+ public static final int XMLVALUE_CODE = 8;
+
+ public static final String int2str[] = {DATE_STRING_TYPE,
+ STRING_TYPE,
+ NONE_TYPE,
+ INTEGER_TYPE,
+ FLOAT_TYPE,
+ BOOLEAN_TYPE,
+ ARRAY_TYPE,
+ ENTITY_TYPE,
+ XMLVALUE_TYPE,
+ };
+
+ /**
+ * This is the information we collect for an attribute
+ */
+ public class Attrib {
+ String enclosure; // This is the XML Tag that must enclose this attribute.
+ String rAttribute; // This is the Rules Engine attribute to assign the value to
+ String rEntity; // If an Entity type, this is the Entity to create.
+ int type; // This is the type for this attribute.
+ }
+ /**
+ * A list of Attrib values for a given attribute mapping.
+ */
+ ArrayList<Attrib> tag_instances = new ArrayList<Attrib>();
+
+ public ArrayList<Attrib> getTag_instances() {
+ return tag_instances;
+ }
+
+ /**
+ * We add an enclosure attribute pair to these arraylists. An
+ * exception is thrown if we get two of the same enclosures.
+ * @param _enclosure
+ * @param _attribute
+ * @param _type
+ */
+ public void add(DTState state,
+ final String tag,
+ final String _enclosure,
+ final String _attribute,
+ String _type)throws RulesException {
+
+ final Iterator iattribs = tag_instances.iterator();
+ int attribType = -1;
+ if(_type.equalsIgnoreCase("date"))_type = "datestring";
+ if(_type.equalsIgnoreCase("time"))_type = "datestring";
+ for(int i=0;i<int2str.length;i++){
+ if(_type.equalsIgnoreCase(int2str[i])){
+ attribType = i;
+ break;
+ }
+ }
+
+ if(attribType == -1){
+ throw new RuntimeException("Invalid mapping type encountered in mapping file: "+_type); //NOPMD
+ }
+
+ while(iattribs.hasNext()){
+ final Attrib attrib = (Attrib)iattribs.next();
+ /* Duplicate attributes may be encountered in mapping xml.
+ So we won't throw this error. */
+ if(attrib.enclosure.equals(_enclosure)) {
+ if (" ".equals(attrib.rAttribute)) {
+ attrib.rAttribute = _attribute;
+ }
+
+ if (attrib.type == NONE_CODE) {
+ attrib.type = attribType;
+ }
+
+ boolean thisisanerror = true;
+
+ if(attrib.rAttribute.equalsIgnoreCase(_attribute)&&
+ int2str[attrib.type].equalsIgnoreCase(_type)){
+ thisisanerror = false;
+ }
+ if (thisisanerror){
+ state.traceInfo("error", null,"Duplicate:" + _enclosure + "." + tag);
+ }
+ state.traceInfo("error", null,
+ (thisisanerror?"ERROR: ":"WARNING: ") + "\n"+
+ "The tag <"+tag+"> and enclosure <"+_enclosure+"> "+
+ "have been encountered more than once in this mapping file\n"+
+ "For "+ (_enclosure==""?"":"<"+_enclosure+"> ") +tag+"> \n"+
+ " Existing: RAttribute '"+attrib.rAttribute+"'\n"+
+ " type '"+int2str[attrib.type]+"'\n"+
+ " New: RAttribute '"+_attribute+"'\n"+
+ " type '"+_type+"'\n");
+ if(thisisanerror) throw new RuntimeException("Duplicate Enclosures encountered");
+ }
+ }
+ final Attrib attrib = new Attrib();
+ attrib.enclosure = _enclosure==null?"":_enclosure;
+ attrib.rAttribute = _attribute;
+ attrib.type = attribType;
+ tag_instances.add(attrib);
+ }
+
+ /**
+ * Looks up the given enclosure, and returns the attribute
+ * associated with that enclosure, or a null if not found.
+ * @param _enclosure
+ * @return
+ */
+ public Attrib lookup(String _enclosure){
+ if(_enclosure==null) _enclosure="";
+ Iterator iattribs = tag_instances.iterator();
+ while(iattribs.hasNext()){
+ Attrib attrib = (Attrib) iattribs.next();
+ if(attrib.enclosure.equals(_enclosure)){
+ return attrib;
+ }
+ }
+ return null;
+ }
+
+ public boolean elementExists(String tag, String _enclosure)
+ {
+ if(_enclosure==null) _enclosure="";
+ Iterator iattribs = tag_instances.iterator();
+ while(iattribs.hasNext()){
+ Attrib attrib = (Attrib)iattribs.next();
+ if(attrib.enclosure.equals(_enclosure))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * The Data Map class holds data for later mapping into the Rules Engine
+ * using the same mapping definition that can be used to upload XML to
+ * an EDD. This interface can also be used to write out XML to a file.
+ *
+ * This isn't a complex implementation. The idea is to collect all the
+ * data we would have written to an XML file, then map it in the same
+ * way with the same tag structure into the EDD. And as a bonus, we
+ * allow for the writing of the data out as XML for debugging or playback
+ * purposes.
+ */
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+import com.dtrules.xmlparser.IXMLPrinter;
+import com.dtrules.xmlparser.XMLPrinter;
+
+
+public class DataMap implements IXMLPrinter{
+ Mapping map;
+ OutputStream out = null;
+ ArrayList<XMLTag> tagStack = new ArrayList<XMLTag>();
+ XMLTag rootTag;
+
+ /**
+ * Write out this DataMap as an XML file. I do not write out
+ * tags with no body (body == null) and no internal structure
+ * (no tag.tags....). This is because the load treats attributes
+ * with null values as having not responded at all. Such
+ * attributes default to the default value specified in the EDD.
+ * When we load the text version however, we can't have a tag
+ * or we will not behave in the same way. A null for a string
+ * will become a zero length string (for example).
+ * @param out
+ */
+ static public void print(XMLPrinter xout, XMLTag tag){
+ if(tag.body == null && tag.tags.size()>0){
+ xout.opentag(tag.tag,tag.attribs);
+ for(XMLTag t : tag.tags){
+ print(xout,t);
+ }
+ xout.closetag();
+ }else{
+ xout.opentag(tag.tag,tag.attribs);
+ xout.printdata(tag.body);
+ xout.closetag();
+ }
+ }
+
+ /**
+ * If created without an output stream, no XML is written.
+ * @param tag
+ */
+ public DataMap(String tag){
+ opentag(tag);
+ rootTag = top();
+ }
+ /**
+ * Constructor you have to use if you wish to use Data Objects to
+ * provide attributes.
+ * @param map - Provides info on the DO's
+ * @param tag
+ * @param xmlOutputStream - Writes an XML file out if specified (not null).
+ */
+ public DataMap(Mapping map, String tag, OutputStream xmlOutputStream){
+ this(tag);
+ this.map = map;
+ this.out = xmlOutputStream;
+ }
+ /**
+ * If created with an output stream, XML is generated and written
+ * to the output stream.
+ * @param tag
+ * @param xmlOutputStream
+ */
+ public DataMap(String tag, OutputStream xmlOutputStream){
+ this(tag);
+ this.out = xmlOutputStream;
+ }
+
+ /**
+ * Write out this DataMap as an XML file
+ * @param out
+ */
+ public void print(OutputStream out){
+ XMLPrinter xout= new XMLPrinter(out);
+ DataMap.print(xout,rootTag);
+ }
+
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth() {
+ return tagStack.size();
+ }
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i){
+ if(i<0 || i>=tagStack.size())return null;
+ return tagStack.get(i).tag;
+ }
+
+ public boolean isInContext(String tag, String key_attribute, Object value){
+ XMLTag t = top();
+ while(t!=null && t!=rootTag){
+ if( t.tag.equals(tag) &&
+ (key_attribute == null ||
+ t.attribs.containsKey(key_attribute) &&
+ (value==null || t.attribs.get(key_attribute).equals(value)))){
+ return true;
+ }
+ t = t.parent;
+ }
+ return false;
+ }
+
+ /**
+ * If we close, then we close all our tags. If an output file has been specified,
+ * we write that out.
+ */
+ public void close() {
+ if(out!=null){
+ print(out);
+ }
+ }
+
+ /**
+ * close the last tag.
+ */
+ public void closetag() {
+ tagStack.remove(tagStack.size()-1);
+ }
+
+ private void newtag(String tag ){
+ XMLTag t = top();
+ if(t!=null && top().body!=null){
+ throw new RuntimeException("You can't have tags and body text within the same XML tag!");
+ }
+ XMLTag newtag = new XMLTag(tag,t);
+ if(t!=null){
+ t.tags.add(newtag);
+ }
+ tagStack.add(newtag);
+ }
+
+ private XMLTag top(){
+ if(tagStack.size()==0)return null;
+ return tagStack.get(tagStack.size()-1);
+ }
+
+ private void addValue(String key, Object value){
+ top().attribs.put(key, value);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ addValue(name9, value9);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9,
+ String name10,Object value10) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ addValue(name9, value9);
+ addValue(name10,value10);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ addValue(name8, value8);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+ addValue(name7, value7);
+ }
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5, String name6, Object value6) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ addValue(name6, value6);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4, String name5, Object value5) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+ addValue(name5, value5);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ addValue(name4, value4);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2, String name3, Object value3) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+ addValue(name3, value3);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1, String name2, Object value2) {
+ newtag(tag);
+ addValue(name1, value1);
+ addValue(name2, value2);
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String, java.lang.String, java.lang.Object)
+ */
+ public void opentag(String tag, String name1, Object value1) {
+ newtag(tag);
+ addValue(name1, value1);
+ }
+
+
+ /*
+ * Open a tag with the given hashmap of values
+ */
+ @SuppressWarnings("unchecked")
+ public void opentag(String tag, HashMap attribs){
+ newtag(tag);
+ for(Object key : attribs.keySet()){
+ addValue((String)key,attribs.get(key));
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#opentag(java.lang.String)
+ */
+ public void opentag(String tag) {
+ newtag(tag);
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#print_error(java.lang.String)
+ */
+ public void print_error(String errorMsg) {
+ opentag("error","msg",errorMsg);
+ closetag();
+
+ }
+
+ /*
+ * We write the data to the body of the top tag. If multiple printdata() calls
+ * are made, then everything is converted to a String and added together.
+ */
+ public void printdata(Object bodyvalue) {
+ XMLTag t = top();
+ if(t.body==null){
+ t.body = bodyvalue;
+ return;
+ }
+ t.body = t.body.toString() + bodyvalue.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.Object)
+ */
+ public void printdata(String tag, Object bodyvalue) {
+ opentag(tag);
+ printdata(bodyvalue);
+ closetag();
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1, Object body) {
+ opentag(tag,name1,value1);
+ printdata(body);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ String name4, Object value4, Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3, name4, value4);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IXMLPrinter#printdata(java.lang.String, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.String, java.lang.Object, java.lang.Object)
+ */
+ public void printdata(String tag, String name1, Object value1,
+ String name2, Object value2, String name3, Object value3,
+ String name4, Object value4, String name5, Object value5,
+ Object bodyvalue) {
+ opentag(tag,name1,value1, name2, value2, name3, value3, name4, value4, name5, value5);
+ printdata(bodyvalue);
+ closetag();
+
+ }
+
+ /**
+ * Return the Root XMLTag of the data structures
+ * @return
+ */
+ public XMLTag getRootTag(){ return rootTag; }
+ /**
+ * Read the attributes of a Data Object and populate an EDD with
+ * those values. This assumes that the class for the Data Object has
+ * been mapped to an Entity in the Map file for a Rule Set
+ * @param obj
+ * @param tag
+ */
+ public void readDO(Object obj, String tag){
+ String do_name = obj.getClass().getName();
+ ArrayList<DataObjectMap> doMaps = map.dataObjects.get(do_name);
+ DataObjectMap doMap = null;
+ for(DataObjectMap DO : doMaps){
+ if(DO.tag.equals(tag)){
+ doMap = DO;
+ break;
+ }
+ }
+ if(doMap==null){
+ throw new RuntimeException("Unknown Data Object: "+do_name);
+ }
+ try {
+ doMap.mapDO(this, obj);
+ } catch (RulesException e) {
+ throw new RuntimeException("Unknown Data Object: "+do_name);
+ }
+ }
+ /**
+ * Looks up the Key from the Data Object and generates the approprate
+ * open tag structure.
+ * @param obj
+ * @param tag
+ */
+ public void opentag(Object obj, String tag){
+ String do_name = obj.getClass().getName();
+ ArrayList<DataObjectMap> doMaps = map.dataObjects.get(do_name);
+ DataObjectMap doMap = null;
+ if(doMaps != null)for(DataObjectMap DO : doMaps){
+ if(DO.tag.equals(tag)){
+ doMap = DO;
+ break;
+ }
+ }
+ if(doMap==null){
+ throw new RuntimeException("Attempt to map data into the EDD using an Unknown Data Object: "+do_name);
+ }
+ doMap.OpenEntityTag(this, obj);
+ }
+
+ private class XmlLoader implements IGenericXMLParser {
+ DataMap datamap;
+
+ XmlLoader(DataMap datamap){
+ this.datamap = datamap;
+ }
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap<String, String> attribs) throws IOException, Exception {
+ datamap.opentag(tag,attribs);
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag,
+ String body, HashMap<String, String> attribs) throws Exception,
+ IOException {
+ if(body!=null && body.length()>0){
+ datamap.printdata(body);
+ }
+ datamap.closetag();
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ }
+
+ /**
+ * Loads an XML File into a DataMap
+ * @param xml
+ */
+ public void loadXML(InputStream xml) throws RulesException {
+ XmlLoader xmlLoader = new XmlLoader(this);
+ try{
+ GenericXMLParser.load(xml, xmlLoader);
+ }catch(Exception e){
+ throw new RulesException("Bad XML","loadXML",e.toString());
+ }
+ }
+
+}
--- /dev/null
+package com.dtrules.mapping;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.AttributeInfo.Attrib;
+
+/**
+ * Defines the DO accesser to Entity Object Attribute Mapping. Each
+ * instance of a DataObjectMap maps a DO to an Entity. If you need
+ * to be able to map the DO to several Entities, then you will need
+ * several DataObjectMaps, one for each Entity.
+ * @author Paul Snow
+ * May 8, 2008
+ *
+ */
+@SuppressWarnings({"unchecked"})
+class DataObjectMap {
+ String tag; // Entity Tag to look for
+ boolean loaded = false; // Have I initialized this object yet?
+ String dataObjName; // Name for this DO
+ Class dataObj; // This is the Data Object Mapped by this Map
+ // Getter to Attribute Map for this DO
+ String entityName = null; // Names of Entities which receive attributes
+ // from this Data Object
+ String key = null; // The Key identifying this DO
+ String keyAccessor = null; // The name of the Accessor to get the Key
+ String key_attribute = null; // The Attribute identifying the Entity in the XML
+
+ // We figure out what accessors in the DO provide values we can
+ // use populate attributes on the Entity, and we store the accessor to tag
+ // mapping here.
+ HashMap<String,String> tagMap= new HashMap<String,String>();
+
+
+ DataObjectMap(String dataObjName,String entity, String tag, String key,String key_attribute) throws Exception {
+ this.dataObjName = dataObjName;
+ this.entityName = entity;
+ this.tag = tag;
+ this.dataObj = Class.forName(dataObjName);
+ this.key = key;
+ this.key_attribute = key_attribute==null?key:key_attribute;
+ if(key!=null){
+ keyAccessor = "get"+key.substring(0,1).toUpperCase();
+ if(key.length()>1){
+ keyAccessor = keyAccessor+key.substring(1);
+ }
+ }
+ }
+
+ /**
+ * Returns true if an Entity tag has been openned.
+ * @param datamap
+ * @param idataObj
+ * @return
+ * @throws Exception
+ */
+ public boolean OpenEntityTag(DataMap datamap, Object idataObj){
+ try{
+ Class params[] = {};
+ Object paramsObj[] = {};
+ Object keyValue = null;
+ if(keyAccessor!=null){
+ keyValue = dataObj.getMethod(keyAccessor,params).invoke(idataObj,paramsObj);
+ }
+ if(!datamap.isInContext(tag, key_attribute, keyValue)){
+ if(key_attribute!=null){
+ datamap.opentag(tag,key_attribute,keyValue);
+ }else{
+ datamap.opentag(tag);
+ }
+ return true;
+ }
+ return false;
+ }catch(Exception e){
+ return false;
+ }
+ }
+
+ public void mapDO(DataMap datamap, Object idataObj)throws RulesException {
+ if(loaded==false){
+ String err = init(datamap);
+ if(err!=null)throw new RulesException("Undefined","DataObjectMap",err);
+ }
+ Class params[] = {};
+ Object paramsObj[] = {};
+
+ try {
+ boolean needToClose = OpenEntityTag(datamap, idataObj);
+ for(String getter : tagMap.keySet()){
+ String tag = tagMap.get(getter);
+ Method getV = dataObj.getMethod(getter, params);
+ Object v = getV.invoke(idataObj, paramsObj);
+ datamap.printdata(tag, v);
+ }
+ if(needToClose){
+ datamap.closetag();
+ }
+ } catch (SecurityException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (IllegalArgumentException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (NoSuchMethodException e) {
+ throw new RulesException("undefined","DataObjectMap",e.toString());
+ } catch (IllegalAccessException e) {
+ throw new RulesException("invalidAccess","DataObjectMap",e.toString());
+ } catch (InvocationTargetException e) {
+ throw new RulesException("unknown","DataObjectMap",e.toString());
+ }
+ }
+ /**
+ * Returns null if the prefix isn't found.
+ * @param prefix
+ * @param n
+ * @return
+ */
+ private String removePrefix(String prefix, Method method){
+ if(method.getParameterTypes().length!=0) return null;
+ String mName = method.getName();
+ int l = prefix.length();
+ if(mName.length() < l) return null;
+ if(!mName.startsWith(prefix))return null;
+ String first = mName.substring(l,l+1);
+ if(mName.length()>l+1){
+ mName = first.toLowerCase()+mName.substring(l+1);
+ }
+ return mName;
+ }
+ /**
+ * Returns an array of error messages if the initialization fails. This
+ * routine looks through all the getters in the DO and looks for matches
+ * with the tags defined in the mapping file.
+ * @return
+ */
+ public String init(DataMap datamap){
+ loaded = true;
+ try {
+ Class c = Class.forName(dataObjName);
+ Method [] methods = c.getMethods();
+ for(Method method : methods){
+ String tag = removePrefix("is", method);
+ if(tag==null) tag = removePrefix("get",method);
+ if(tag!=null){
+ AttributeInfo info = datamap.map.setattributes.get(tag);
+ if(info!= null) for(Attrib attrib : info.getTag_instances() ){
+ if( entityName.equalsIgnoreCase(attrib.enclosure)){
+ tagMap.put(method.getName(), tag);
+ }
+
+ }
+ }
+ }
+ } catch (ClassNotFoundException e) {
+ return "Could not find the DO: "+dataObjName;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+
+/**
+ * Holds information about each entity expected in the XML input data.
+ * @author paul snow
+ *
+ */
+class EntityInfo {
+ String id;
+ String name;
+ IREntity entity;
+ String number;
+ String list;
+ /**
+ * Get a new instance of an Entity upon a reference in the data file.
+ * If only one instance of an Entity is to be created, then return
+ * that one. If the Entity is a constant Entity, return the constant
+ * Entity. Otherwise create a new clone and return that.
+ * @return
+ */
+ IREntity getInstance(IRSession s)throws RulesException{
+ if(number.equals("1"))return entity;
+ DTState state = s.getState();
+ IRObject rarray = state.find(RName.getRName(name+"s"));
+
+ IREntity newentity = (IREntity) entity.clone(s);
+ if(rarray!=null && rarray.type() ==IRObject.iArray){
+ ((RArray)rarray).add(newentity);
+ }
+ return newentity;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.interpreter.RXmlValue;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+
+@SuppressWarnings({"unchecked"})
+public class LoadDatamapData extends LoadXMLData {
+
+ public LoadDatamapData(Mapping _map){
+ super(_map);
+ }
+
+ public LoadDatamapData(Mapping _map, IRSession session, String _ruleSetName){
+ super(_map, session, _ruleSetName);
+ }
+
+ XMLTag xmltag = null;
+
+ public void endTag(String[] tagstk, int tagstkptr, XMLTag tag, Object body,
+ HashMap attribs) throws Exception, IOException {
+ this.xmltag = tag;
+ endTag(tagstk,tagstkptr,tag.tag,body,attribs);
+ }
+
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, Object body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ attribs.remove("create entity");
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if creating an Entity, but it can't be null either.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ attribs.remove("set attribute date");
+ if(body instanceof String){
+ String sbody = body.toString();
+ if (sbody.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && sbody.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(sbody);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(sbody);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+ }else {
+ attr = (String) attribs.get("set attribute");
+ }
+ if (attr != null){
+ attribs.remove("set attribute");
+ // Look and see if we have an attribute name defined.
+ if(body!=null){
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity==null){
+ throw new Exception ("No Entity is in the context that defines "+ a.stringValue());
+ }
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(getLong(body));
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(getDouble(body));
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.toString());
+ } else if (type == IRObject.iTime){
+ value = RTime.getRTime((Date)body);
+ } else if (type == IRObject.iEntity) {
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadDatamapData","Entity Tags have to create some Entity Reference");
+ }
+ } else if (type == IRObject.iString) {
+ value = RString.newRString(body.toString());
+ } else if (type == IRObject.iXmlValue){
+ if(xmltag != null){
+ value = new RXmlValue(state,xmltag);
+ }else{
+ throw new RulesException("MappingError","LoadDatamapData","Somehow we are missing the XML Tag for the attribute: "+a);
+ }
+ } else {
+ throw new RulesException("MappingError","LoadDatamapData","Unsupported type encountered: "+RSession.typeInt2Str(type));
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ state.traceInfo("message",null," /"+a+" \""+body+"\" def");
+ }
+ }
+
+ return;
+ }
+
+ long getLong(Object num){
+ if(num.getClass()==BigDecimal.class)return ((BigDecimal)num).longValue();
+ if(num.getClass()==Long.class)return ((Long)num).longValue();
+ if(num.getClass()==Double.class)return ((Double)num).longValue();
+ if(num.getClass()==Integer.class)return((Integer)num).longValue();
+ if(num.getClass()==String.class)return Long.parseLong(num.toString());
+ throw new RuntimeException("Can't figure out the value "+num.toString()+" "+num.getClass().getName());
+ }
+
+ double getDouble(Object num){
+ if(num.getClass()==BigDecimal.class)return ((BigDecimal)num).doubleValue();
+ if(num.getClass()==Long.class)return ((Long)num).doubleValue();
+ if(num.getClass()==Double.class)return ((Double)num).doubleValue();
+ if(num.getClass()==Integer.class)return((Integer)num).doubleValue();
+ if(num.getClass()==String.class)return Double.parseDouble(num.toString());
+ throw new RuntimeException("Can't figure out the value "+num.toString()+" "+num.getClass().getName());
+ }
+
+
+ @Override
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e)throws RulesException {
+ RName listname = RName.getRName(e.getName().stringValue()+"s");
+
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IRObject elist = state.getes(i).get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update any reference to this entity that might be on the Entity Stack.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ for(int i=0;i< state.edepth(); i++){
+ if((state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ (state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.mapping;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.EntityFactory;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+
+/**
+ * LoadMap class is used by the GenerixXMLParser to load the Map defining
+ * the XML to EDD transformation.
+ *
+ * @author Paul Snow
+ *
+ */
+class LoadMap implements IGenericXMLParser {
+ /**
+ * We track if we encountered any errors, but we print as many messages as we can.
+ * Then we report if we failed to load, assuming anyone cares.
+ */
+ private boolean loadSuccessful = true;
+ private HashMap<String, String > undefinedEntities;
+ private HashMap<String, String > definedAttributes;
+
+ private final DTState state;
+ private final EntityFactory ef;
+ private final Mapping map;
+
+ private HashMap<String,String> _attribs;
+
+ /**
+ * @param map
+ */
+ LoadMap(DTState state, Mapping map) {
+ this.map = map;
+ this.state = state;
+ this.ef = state.getSession().getEntityFactory();
+ }
+
+ /**
+ * This boolean is set at the end of loading a file.
+ * @return the loadSuccessful
+ */
+ public boolean isLoadSuccessful() {
+ return loadSuccessful;
+ }
+ /**
+ *
+ */
+
+ public void begin_dataobjects(){}
+
+ public void begin_do2entitymap(){
+
+ String doClass = _attribs.get("class");
+ String key = _attribs.get("key");
+ String key_attribute = _attribs.get("key_attribute");
+ String entity = _attribs.get("entity");
+ String entity_tag = _attribs.get("entity_tag");
+ ArrayList<DataObjectMap> dataobjmaps = map.dataObjects.get(doClass);
+
+ if(dataobjmaps==null){
+ dataobjmaps = new ArrayList<DataObjectMap>();
+ map.dataObjects.put(doClass, dataobjmaps);
+ }
+
+ for(DataObjectMap dataobjmap : dataobjmaps){
+ if(dataobjmap.entityName.equals(entity) &&
+ dataobjmap.tag.equals(entity_tag)){
+ throw new RuntimeException("Duplicate DO to Entity mappings for: "+entity);
+ }
+ }
+
+ try {
+ DataObjectMap dataobjmap = new DataObjectMap(doClass,entity,entity_tag,key,key_attribute);
+ dataobjmaps.add(dataobjmap);
+ } catch (Exception e) {
+ // System.out.println("Undefined Data Object: '"+doClass+"'\n");
+ }
+ }
+
+ /**
+ * Mapping tag. <mapping>
+ * used simply to organize the mapping xml under a single tag.
+ * This does any initialization of the mapping state
+ *
+ */
+ public void begin_mapping () {
+ undefinedEntities = new HashMap<String,String>();
+ definedAttributes = new HashMap<String,String>();
+ loadSuccessful = true;
+ }
+
+ /**
+ * Contains the tags that define the XML to EDD mapping. Right
+ * now that is all we implement. In the future we will add an
+ * EDD to XML mapping set of tags, maybe.
+ *
+ */
+ public void begin_XMLtoEDD () {}
+
+ /**
+ * Tag groups all the entity tags.
+ */
+ public void begin_entities () {}
+
+
+ /**
+ * Process an Entity tag. Example:
+ * <entity name="individual" number="+"/>
+ * Valid number specifications are:
+ * "*" (0 or more)
+ * "+" (1 or more)
+ * "1" (1)
+ */
+ public void begin_entity () {
+ String entity = ((String) _attribs.get("name")).toLowerCase();
+ String number = (String) _attribs.get("number");
+
+ IREntity rEntity = map.getSession().getEntityFactory().findRefEntity(RName.getRName(entity));
+ if(rEntity==null){
+ System.out.println("The Entity specified, '"+entity+"' is not defined");
+ loadSuccessful = false;
+ }
+ if(number.equals("1") || number.equals("+") || number.equals("*")){
+ this.map.entityinfo.put(entity,number);
+ }else{
+
+ try {
+ state.traceInfo("error", null,
+ "Number value must be '1', '*', or '+'. Encounterd: "+number);
+ } catch (RulesException e) {} // Ignore because we are going to throw an exception anyway.
+ throw new RuntimeException("Number value must be '1', '*', or '+'. Encounterd: "+number);
+ }
+ }
+
+ /**
+ * Every entity that defines the given attribute gets its instances logged
+ * in to the given list.
+ */
+ public void addalltolist () {
+ String withAttribute = (String) _attribs.get("withAttribute");
+ String toList = (String) _attribs.get("toList");
+ String pair[] = {withAttribute.toLowerCase(),toList.toLowerCase()};
+ map.attribute2listPairs.add(pair);
+
+ }
+
+ /**
+ * Groups initalentity tags.
+ *
+ */
+ public void begin_initialization(){}
+
+ /**
+ * Defines an entity to be placed on the Entity Stack at initialization.
+ *
+ */
+ public void begin_initialentity(){
+ String entity = (String) _attribs.get("entity");
+ this.map.entitystack.add(entity.toLowerCase());
+ }
+
+ /**
+ * Groups all of the mapping tags.
+ *
+ */
+ public void begin_map(){}
+
+
+ /**
+ * Saves away the information required to create an entity.
+ *
+ */
+ public void begin_createentity(){
+ final String entity = (String) _attribs.get("entity");
+ final String tag = (String) _attribs.get("tag");
+ final String attribute = (String) _attribs.get("attribute");
+ final String value = (String) _attribs.get("value");
+ final String id = (String) _attribs.get("id");
+ String list = (String) _attribs.get("list");
+ list = list==null?"":list;
+
+ try {
+ IREntity theentity = ef.findRefEntity(RName.getRName(entity));
+ if(theentity==null)throw new Exception();
+ } catch (Exception e) {
+ System.out.println("\nThe Entity "+entity+" isn't defined by the EDD");
+ loadSuccessful = false;
+ }
+
+ EntityInfo info = new EntityInfo();
+ info.id = id;
+ info.name = entity.toLowerCase();
+ info.list = list.toLowerCase().trim();
+ if(attribute== null || value==null ){
+ this.map.requests.put(tag,info);
+ }else{
+ this.map.multiple.put(tag,attribute);
+ this.map.requests.put(value,info);
+ }
+ }
+
+
+
+ /**
+ * The Rules Engine expects everything to be lowercase!!
+ * Be careful how you use attributes!
+ */
+ public void begin_setattribute(){
+ String tag = (String) _attribs.get("tag");
+ String type = (String) _attribs.get("type");
+ String enclosure = (String) _attribs.get("enclosure"); // This is an optional tag enclosure....
+ String rattribute = (String) _attribs.get("RAttribute"); // This is the Entity Attribute name
+
+ if(rattribute == null)rattribute = tag; // If no rattribute name is specified, default to the tag.
+
+ AttributeInfo info = (AttributeInfo) this.map.setattributes.get(tag);
+ if(info==null){
+ info = new AttributeInfo();
+ }
+ try {
+ IREntity e = ef.findRefEntity(RName.getRName(enclosure));
+ if(e==null){
+ if(!undefinedEntities.containsKey(enclosure)){
+ System.out.println("The entity "+enclosure+" isn't defined in the EDD");
+ loadSuccessful = false;
+ undefinedEntities.put(enclosure, enclosure);
+ }
+ }else{
+ if(definedAttributes.containsKey(enclosure+"*"+rattribute)){
+ System.out.println("The Entity "+enclosure+" and Attribute "+rattribute +" have multiple definitions");
+ loadSuccessful = false;
+ }
+ if(e.getEntry(RName.getRName(rattribute))==null){
+ System.out.println("The Attribute "+rattribute+" isn't defined by "+enclosure);
+ loadSuccessful = false;
+ }
+ info.add(state,tag, enclosure,rattribute.toLowerCase(),type);
+ }
+ } catch (RulesException e) {}
+
+ this.map.setattributes.put(tag,info);
+ }
+
+
+ /**
+ * Because all of the tags possible within a Mapping XML are defined, and because we only have to load the Mapping
+ * File once at initialization, all we do here is take our parameters and store them away within our class, then
+ * by intraspection load the proper method for this tag, and execute it.
+ */
+ @SuppressWarnings({"unchecked"})
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+
+ _attribs = (HashMap<String,String>)attribs;
+
+ if(state.testState(DTState.VERBOSE)){
+ String data = "<"+tag+" ";
+ for(Object v : attribs.keySet()){
+ data += v+" = '"+attribs.get(v)+"'";
+ }
+ state.traceInfo("Load",null,data+">\n");
+ }
+
+ try {
+ this.getClass().getMethod("begin_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println( e.getCause().getMessage());
+ loadSuccessful = false;
+ } catch (NoSuchMethodException e) {
+ System.out.println("No implmentation for "+tag+"()");
+ throw new RuntimeException("Undefined tag found in mapping file: "+tag);
+ }
+ }
+
+ /**
+ * We are not doing anything on an end tag right now.
+ */
+ @SuppressWarnings({"unchecked"})
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+
+
+ }
+ /**
+ * All errors throw an Exception. If we run into problems, there is no
+ * recovery, no fix.
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+/**
+ * Loads the mapping file (the description of how data should be moved
+ * from XML to the EDD)
+ *
+ */
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class LoadMapping implements IGenericXMLParser {
+ Mapping map;
+ int codeCnt = 0;
+ IRSession session;
+ IRObject def;
+ DTState state;
+ String ruleSetName;
+ static DateFormat df_in = new SimpleDateFormat ("yyyy-MM-dd");
+
+ static DateFormat df_out = new SimpleDateFormat ("MM/dd/yyyy");
+
+
+ public LoadMapping(Mapping _map){
+ map = _map;
+ }
+
+ public LoadMapping(Mapping _map, IRSession session, String _ruleSetName){
+ map = _map;
+ this.session = session;
+ this.state = session.getState();
+ this.ruleSetName = _ruleSetName;
+
+ try{ // Cache the def operator.
+ def = session.getState().find(RName.getRName("def"));
+ }catch(Exception e){
+ try {
+ state.traceInfo("error", null,"General Rules Engine Failure");
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+
+ Iterator<RName> es = this.map.entities.keySet().iterator();
+ while(es.hasNext()){
+ RName ename = (RName) es.next();
+ try {
+ IREntity e = findEntity(ename.stringValue().toLowerCase(),null,null);
+ state.entitypush(e);
+ } catch (RulesException e) {
+ try {
+ state.traceInfo("error", null,"Failed to initialize the Entity Stack (Failed on "+ename+")\n"+e);
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Looks to make sure that we have not yet created an Entity
+ * of this name with the given code. If we have, we return the
+ * earlier created Entity. Otherwise, we create a new instance.
+ * @param entity -- We assume this is a valid Entity name (no dot syntax)
+ * @param code
+ * @return
+ * @throws RulesException
+ */
+ IREntity findEntity( String entity, String code, EntityInfo info) throws RulesException{
+ String number = (String) this.map.entityinfo.get(entity);
+ IREntity e;
+ if(number==null){
+ number = "*";
+ }
+ if(number.equals("1")){
+ e = (IREntity)entities.get(entity);
+ if(e==null){
+ e = session.getState().findEntity(RName.getRName(entity+"."+entity));
+ if(e==null){
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ entities.put(entity,e);
+ }
+ }else { // We assume number.equals("*") || number.equals("+")
+ e = null;
+ String key = "";
+ if(code!=null && code.length()!=0) {
+ key = entity+"$"+code;
+ e = (IREntity)entities.get(key);
+ }
+ if(e==null) {
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ if(code!=null) entities.put(key,e);
+ }
+ if(e==null)throw new RulesException("undefined","LoadMapping.findEntity()","Failed to create the entity "+entity);
+ UpdateReferences(e,info);
+ return e;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ String name = tag; // We assume the tag might create an entity
+ @SuppressWarnings("unused")
+ boolean traceopen = false;
+ EntityInfo info = (EntityInfo) this.map.requests.get(name);
+ AttributeInfo aInfo = (AttributeInfo) this.map.setattributes.get(tag);
+
+
+ // If I get info, then create an entity.
+ // Get the code from this tag.
+ // If a fixed entity name is specified,
+ // or the tag name, use it. Otherwise use the multiple name
+ if(info!=null){
+ Object objCode = attribs.get(info.id);
+ String code = objCode==null?"":objCode.toString();
+ String eName = info.name;
+ if (eName == null || eName.length() <= 0)
+ {
+ eName = (String) attribs.get("name");
+ }
+ IREntity e = findEntity(eName, code, info); // Look up the entity I should create.
+ if(e!=null){ // I hope to goodness I can find it!
+ attribs.put("create entity","true");
+ if(code.length()!=0) {
+ e.put(IREntity.mappingKey,RString.newRString(code));
+ }else{
+ e.put(IREntity.mappingKey,RString.newRString("v"+ (++codeCnt)));
+ }
+
+ state.entitypush(e);
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("createEntity", "name='"+info.name+"' id='"+code+"'");
+ traceopen = true;
+ }
+ }else{
+
+ state.traceInfo("error", null, "The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ throw new Exception("The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ }
+ }
+
+ if(aInfo!=null){ // If we are supposed to set an attribute, then we set ourselves up
+ // to define the entity attribute on the end tag. We may be setting this
+ // Attribute to the value of the Entity we just created/looked up.
+ /**
+ * First check enclosures, then check the blank case. This allows
+ * the user to specify a default mapping, yet still direct some attributes to
+ * specific destinations based on the enclosure.
+ */
+ AttributeInfo.Attrib attrib;
+ { // Not only do you have to match the attribute name,
+ int i=tagstkptr-2; // But you must match the immediately enclosing tag
+ attrib = aInfo.lookup(tagstk[i]);
+ if(attrib!=null){
+ queueSetAttribute(attrib, attribs);
+ }
+ }
+ attrib = aInfo.lookup(""); // If I don't find the enclosure defined, look to see
+ queueSetAttribute(attrib,attribs); // if a general default is defined.
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if we created an Entity.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ if (body.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && body.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(body);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(body);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+
+ if ((attr = (String) attribs.get("set attribute"))!=null){
+ // Look and see if we have an attribute name defined.
+ {
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity!=null){
+
+
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.length()==0? "false" : body);
+ } else if (type == IRObject.iTime){
+ if(body.trim().length()>0){
+ value = RTime.getRDate(body);
+ if(value == null){
+ throw new RulesException("MappingError","LoadMapping","Bad Date... Could not parse '"+body+"'");
+ }
+ }else{
+ value = RNull.getRNull();
+ }
+ } else if (type == IRObject.iEntity){
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadMapping","Entity Tags have to create some Entity Reference");
+ }
+ }else {
+ value = RString.newRString(body);
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ /**
+ * Does nothing if the info is null... Just means we are not mapping this attribute.
+ * Otherwise it updates the attribs hashmap.
+ *
+ * @param info
+ */
+ private void queueSetAttribute( AttributeInfo.Attrib attrib, HashMap attribs){
+ if(attrib==null)return;
+ switch (attrib.type ){
+ case AttributeInfo.DATE_STRING_CODE :
+ attribs.put("set attribute date",attrib.rAttribute);
+ break;
+ case AttributeInfo.STRING_CODE :
+ case AttributeInfo.NONE_CODE :
+ case AttributeInfo.INTEGER_CODE :
+ case AttributeInfo.BOOLEAN_CODE :
+ case AttributeInfo.FLOAT_CODE :
+ case AttributeInfo.ENTITY_CODE :
+ case AttributeInfo.XMLVALUE_CODE :
+ attribs.put("set attribute",attrib.rAttribute);
+ break;
+ default:
+ throw new RuntimeException("Bad Type Code "+attrib.type+" in com.dtrules.mapping.AttributeInfo: "+attrib.rAttribute);
+ }
+ }
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e, EntityInfo info)throws RulesException {
+ RName listname;
+ if(info!=null && info.list.length()==0){
+ listname = RName.getRName(e.getName().stringValue()+"s");
+ }else{
+ listname = RName.getRName(info.list);
+ }
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IREntity entity = state.getes(i);
+ IRObject elist = entity.get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update the reference to this entity that might be on the Entity Stack.
+ // DON'T go wild. Only look at the top entity (or you may overwrite a reference
+ // you'd rather leave alone.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ int i=state.edepth()-1;
+ if(((IREntity)state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ ((IREntity)state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+/**
+ * Loads the mapping file (the description of how data should be moved
+ * from XML to the EDD)
+ *
+ */
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class LoadXMLData implements IGenericXMLParser {
+ Mapping map;
+ int codeCnt = 0;
+ IRSession session;
+ IRObject def;
+ DTState state;
+ String ruleSetName;
+ static DateFormat df_in = new SimpleDateFormat ("yyyy-MM-dd");
+
+ static DateFormat df_out = new SimpleDateFormat ("MM/dd/yyyy");
+
+
+ public LoadXMLData(Mapping _map){
+ map = _map;
+ }
+
+ public LoadXMLData(Mapping _map, IRSession session, String _ruleSetName){
+ map = _map;
+ this.session = session;
+ this.state = session.getState();
+ this.ruleSetName = _ruleSetName;
+
+ try{ // Cache the def operator.
+ def = session.getState().find(RName.getRName("def"));
+ }catch(Exception e){
+ try {
+ state.traceInfo("error", null,"General Rules Engine Failure");
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+
+ for(RName ename : this.map.entities.keySet()){
+ try {
+ IREntity e = findEntity(ename.stringValue().toLowerCase(),null,null);
+ state.entitypush(e);
+ } catch (RulesException e) {
+ try {
+ state.traceInfo("error", null,"Failed to initialize the Entity Stack (Failed on "+ename+")\n"+e);
+ } catch (RulesException e1) { } // Ignore since we are going to throw anyway...
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Looks to make sure that we have not yet created an Entity
+ * of this name with the given code. If we have, we return the
+ * earlier created Entity. Otherwise, we create a new instance.
+ * @param entity -- We assume this is a valid Entity name (no dot syntax)
+ * @param code
+ * @return
+ * @throws RulesException
+ */
+ IREntity findEntity( String entity, String code, EntityInfo info) throws RulesException{
+ String number = (String) this.map.entityinfo.get(entity);
+ IREntity e;
+ if(number==null){
+ number = "*";
+ }
+ if(number.equals("1")){
+ e = (IREntity)entities.get(entity);
+ if(e==null){
+ e = session.getState().findEntity(RName.getRName(entity+"."+entity));
+ if(e==null){
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ entities.put(entity,e);
+ }
+ }else { // We assume number.equals("*") || number.equals("+")
+ e = null;
+ String key = "";
+ if(code!=null && code.length()!=0) {
+ key = entity+"$"+code;
+ e = (IREntity)entities.get(key);
+ }
+ if(e==null) {
+ e = ((RSession)session).createEntity(null,entity);
+ }
+ if(code!=null) entities.put(key,e);
+ }
+ if(e==null)throw new RulesException("undefined","LoadXMLData.findEntity()","Failed to create the entity "+entity);
+ UpdateReferences(e,info);
+ return e;
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ String name = tag; // We assume the tag might create an entity
+ @SuppressWarnings("unused")
+ boolean traceopen = false;
+ EntityInfo info = (EntityInfo) this.map.requests.get(name);
+ AttributeInfo aInfo = (AttributeInfo) this.map.setattributes.get(tag);
+
+
+ // If I get info, then create an entity.
+ // Get the code from this tag.
+ // If a fixed entity name is specified,
+ // or the tag name, use it. Otherwise use the multiple name
+ if(info!=null){
+ Object objCode = attribs.get(info.id);
+ String code = objCode==null?"":objCode.toString();
+ String eName = info.name;
+ if (eName == null || eName.length() <= 0)
+ {
+ eName = (String) attribs.get("name");
+ }
+ IREntity e = findEntity(eName, code, info); // Look up the entity I should create.
+ if(e!=null){ // I hope to goodness I can find it!
+ attribs.put("create entity","true");
+ if(code.length()!=0) {
+ e.put(IREntity.mappingKey,RString.newRString(code));
+ }else{
+ e.put(IREntity.mappingKey,RString.newRString("v"+ (++codeCnt)));
+ }
+
+ state.entitypush(e);
+ if(state.testState(DTState.TRACE)){
+ state.traceTagBegin("createEntity", "name='"+info.name+"' id='"+code+"'");
+ traceopen = true;
+ }
+ }else{
+
+ state.traceInfo("error", null, "The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ throw new Exception("The Mapping defines '"+info.entity+"', but this entity isn't defined in the EDD");
+ }
+ }
+
+ if(aInfo!=null){ // If we are supposed to set an attribute, then we set ourselves up
+ // to define the entity attribute on the end tag. We may be setting this
+ // Attribute to the value of the Entity we just created/looked up.
+ /**
+ * First check enclosures, then check the blank case. This allows
+ * the user to specify a default mapping, yet still direct some attributes to
+ * specific destinations based on the enclosure.
+ */
+ AttributeInfo.Attrib attrib;
+ { // Not only do you have to match the attribute name,
+ int i=tagstkptr-2; // But you must match the immediately enclosing tag
+ if(i>=0){
+ attrib = aInfo.lookup(tagstk[i]);
+ if(attrib!=null){
+ queueSetAttribute(attrib, attribs);
+ }
+ }
+ }
+ attrib = aInfo.lookup(""); // If I don't find the enclosure defined, look to see
+ queueSetAttribute(attrib,attribs); // if a general default is defined.
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body,
+ HashMap attribs) throws Exception, IOException
+ {
+ String attr;
+ REntity entity = null;
+
+ if(attribs.containsKey("create entity")){ // For create Entity Tags, we pop the Entity from the Entity Stack on the End Tag.
+ entity = (REntity) state.entitypop();
+ Iterator pairs = map.attribute2listPairs.iterator();
+ body = ""; // Don't care about the Body if we created an Entity.
+ while(pairs.hasNext()){
+ Object [] pair = (Object []) pairs.next();
+ if(entity.containsAttribute(RName.getRName((String)pair[0]))){
+ RName.getRName((String) pair[1],true).execute(state);
+ state.entitypush(entity);
+ RName.getRName("addto",true).execute(state);
+
+ }
+ }
+ if(state.testState(DTState.TRACE)){
+ state.traceTagEnd("createEntity", null);
+ }
+ }
+
+ // If this is a Date format, we are going to reformat it, and let it feed into
+ // the regular set attribute code.
+ if ((attr = (String) attribs.get("set attribute date"))!=null){ // Look and see if we have an attribute name defined.
+ if (body.trim().length() > 0)
+ {
+ Date date;
+ try {
+ if(false && body.indexOf("7777")>=0){
+ date = new Date(0x7FFFFFFFFFFFL);
+ }else{
+ date = df_in.parse(body);
+ }
+ } catch (ParseException e) {
+ try{
+ date = df_out.parse(body);
+ }catch (ParseException e2){
+ date = df_out.parse("01/05/2008");
+ //throw new RuntimeException("Bad Date encountered: ("+tag+")="+body);
+ }
+ }
+ body = df_out.format(date);
+ attribs.put("set attribute",attr);
+ }
+ }
+
+ if ((attr = (String) attribs.get("set attribute"))!=null){
+ // Look and see if we have an attribute name defined.
+ {
+ RName a = RName.getRName(attr);
+ IRObject value;
+
+ IREntity enclosingEntity = session.getState().findEntity(a);
+ if(enclosingEntity!=null){
+
+
+ int type = enclosingEntity.getEntry(a).type;
+
+ if(type == IRObject.iInteger){
+ value = RInteger.getRIntegerValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iDouble) {
+ value = RDouble.getRDoubleValue(body.length()==0? "0" : body);
+ } else if (type == IRObject.iBoolean){
+ value = RBoolean.getRBoolean(body.length()==0? "false" : body);
+ } else if (type == IRObject.iTime){
+ if(body.trim().length()>0){
+ value = RTime.getRDate(body);
+ if(value == null){
+ throw new RulesException("MappingError","LoadXMLData","Bad Date... Could not parse '"+body+"'");
+ }
+ }else{
+ value = RNull.getRNull();
+ }
+ } else if (type == IRObject.iEntity){
+ if(entity!=null){
+ value = entity;
+ }else{
+ throw new RulesException("MappingError","LoadXMLData","Entity Tags have to create some Entity Reference");
+ }
+ }else {
+ value = RString.newRString(body);
+ }
+ // conversion in the Rules Engine to do the proper thing.
+ state.def(a,value,false);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ /**
+ * Does nothing if the info is null... Just means we are not mapping this attribute.
+ * Otherwise it updates the attribs hashmap.
+ *
+ * @param info
+ */
+ private void queueSetAttribute( AttributeInfo.Attrib attrib, HashMap attribs){
+ if(attrib==null)return;
+ switch (attrib.type ){
+ case AttributeInfo.DATE_STRING_CODE :
+ attribs.put("set attribute date",attrib.rAttribute);
+ break;
+ case AttributeInfo.STRING_CODE :
+ case AttributeInfo.NONE_CODE :
+ case AttributeInfo.INTEGER_CODE :
+ case AttributeInfo.BOOLEAN_CODE :
+ case AttributeInfo.FLOAT_CODE :
+ case AttributeInfo.ENTITY_CODE :
+ case AttributeInfo.XMLVALUE_CODE :
+ attribs.put("set attribute",attrib.rAttribute);
+ break;
+ default:
+ throw new RuntimeException("Bad Type Code "+attrib.type+" in com.dtrules.mapping.AttributeInfo: "+attrib.rAttribute);
+ }
+ }
+
+ /**
+ * We collect all the Entities we create as we go. These
+ * are stored as a value, and their id as the key. Then if
+ * we encounter the same key in the XML, we return the same
+ * Entity.
+ */
+ HashMap entities = new HashMap();
+
+ IREntity UpdateReferences(IREntity e, EntityInfo info)throws RulesException {
+ RName listname;
+ if(info!=null && info.list.length()==0){
+ listname = RName.getRName(e.getName().stringValue()+"s");
+ }else{
+ listname = RName.getRName(info.list);
+ }
+ // First add this entity to any list found on the entity stack.
+ for(int i=0; i< state.edepth(); i++){
+ // Look for all Array Lists on the Entity Stack that look like lists of this Entity
+ IREntity entity = state.getes(i);
+ IRObject elist = entity.get(listname);
+ if(elist!=null && elist.type()==IRObject.iArray){
+ // If not a member of this list, then add it.
+ if(!((RArray)elist).contains(e)){
+ ((RArray)elist).add(e);
+ }
+ }
+ }
+ // Then update the reference to this entity that might be on the Entity Stack.
+ // DON'T go wild. Only look at the top entity (or you may overwrite a reference
+ // you'd rather leave alone.
+ // DON'T mess with any entity's self reference though! That is BAD.
+ int i=state.edepth()-1;
+ if(((IREntity)state.getes(i)).get(e.getName())!=null){
+ IREntity refto = state.getes(i);
+ if(! refto.getName().equals(e.getName())) // Update a reference to an Entity of the same name,
+ ((IREntity)state.getes(i)).put(e.getName(), e); // but only if it isn't a self reference.
+
+ }
+
+ return e;
+ }
+
+
+ }
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+import com.dtrules.xmlparser.XMLPrinter;
+
+@SuppressWarnings({"unchecked"})
+public class MapGenerator implements IGenericXMLParser {
+ String[] tagstk;
+ int tagstkptr;
+ String tag;
+ HashMap<String,String> attribs;
+ String body;
+
+ XMLPrinter out = null;
+ String mapping = null;
+
+ /**
+ * These are the list of entities for which at least one
+ * Attribute will be set by this mapping file.
+ */
+ ArrayList <String> entities = new ArrayList<String>();
+ ArrayList <String> unreferenced = new ArrayList<String>();
+ /**
+ * Returns true if the particular mapping here is one of the
+ * input sources for this attribute.
+ */
+ boolean inputMatch(String inputs){
+ /** Deal quickly with the trival case **/
+ if(inputs.trim().length()==0) return false;
+ StringTokenizer tokenizer = new StringTokenizer(inputs," \t\r\n,");
+ while(tokenizer.hasMoreTokens()){
+ if(tokenizer.nextToken().equalsIgnoreCase(mapping))return true;
+ }
+ return false;
+ }
+
+ public void end_entity(){
+ String attribute = (String) attribs.get("attribute");
+ String type = (String) attribs.get("type");
+ String input = (String) attribs.get("input");
+ String entity = attribs.get("entityname").toLowerCase().trim();
+
+ if(inputMatch(input)){
+ out.printdata("setattribute",
+ "tag" ,attribute,
+ "RAttribute" ,attribute,
+ "enclosure" ,entity,
+ "type" ,type,
+ null);
+ if(!entities.contains(entity)){
+ entities.add(entity);
+ }else{
+ if(unreferenced.contains(entity)){
+ unreferenced.remove(entity);
+ }
+ }
+ }else{
+ if(!entities.contains(entity)){
+ entities.add(entity);
+ if(!unreferenced.contains(entity)){
+ unreferenced.add(entity);
+ }
+ }
+ }
+ }
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+ this.tagstk = tagstk;
+ this.tagstkptr = tagstkptr;
+ this.tag = tag.toLowerCase();
+ this.attribs = attribs;
+ this.body = null;
+
+ try {
+ this.getClass().getMethod("begin_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println(e.getCause().getMessage());
+ } catch (NoSuchMethodException e) {
+ //Ignore tags we don't know.
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see com.dtrules.xmlparser.IGenericXMLParser#endTag(java.lang.String[], int, java.lang.String, java.lang.String, java.util.HashMap)
+ */
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+ this.tagstk = tagstk;
+ this.tagstkptr = tagstkptr;
+ this.tag = tag;
+ this.attribs = attribs;
+ this.body = body;
+
+ try {
+ this.getClass().getMethod("end_"+tag, (Class[])null).invoke(this,(Object [])null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ System.out.println(e.getCause().getMessage());
+ } catch (NoSuchMethodException e) {
+ //System.out.println("Unknown: end_"+tag);
+ }
+ }
+
+ /* Something required of the XML parser.
+ * @see com.dtrules.xmlparser.IGenericXMLParser#error(java.lang.String)
+ */
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ public void generateMapping(String mapping, String inputfile, String outputfile) throws Exception {
+ FileInputStream input = new FileInputStream(inputfile);
+ XMLPrinter out = new XMLPrinter(new FileOutputStream(outputfile));
+ generateMapping(mapping,input,out);
+ }
+ /**
+ * Given an EDD XML, makes a good stab at generating a Mapping file for a given
+ * mapping source. The mapping source is specified as an input in the input column
+ * in the EDD.
+ * @param mapping
+ * @param input
+ * @param out
+ * @throws Exception
+ */
+ public void generateMapping(String mapping, InputStream input, XMLPrinter out)throws Exception {
+ this.out = out;
+ this.mapping = mapping;
+ out.opentag("mapping");
+ out.opentag("XMLtoEDD");
+
+ out.opentag("map");
+ GenericXMLParser.load(input,this);
+
+ for(String entity : entities){
+ out.printdata("createentity",
+ "entity", entity,
+ "tag" , entity,
+ "id" , "id",
+ null);
+ }
+ out.closetag();
+
+ out.opentag("entities");
+ for(String entity : entities) {
+ out.printdata("entity","name",entity,"number","*",null);
+ }
+ out.closetag();
+
+ out.opentag("initialization");
+ for(String entity : unreferenced){
+ out.printdata("initialentity","entity",entity,"epush","true",null);
+ }
+ out.closetag();
+
+ out.close();
+ }
+
+
+ public static void main(String args[])throws Exception{
+ String path = "C:/eb/workspace/AutoAssignmentDevelopment/";
+ String mapping = "main";
+ InputStream input = new FileInputStream(path+"xml/ny_eb_edd.xml");
+ MapGenerator mg = new MapGenerator();
+ FileOutputStream os = new FileOutputStream(path+"temp/gen_map.xml");
+ XMLPrinter out = new XMLPrinter(os);
+
+ mg.generateMapping(mapping, input, out);
+
+ }
+
+
+ /**
+ * @return the entities
+ */
+ public ArrayList<String> getEntities() {
+ return entities;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.mapping;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+/**
+ * The Mapping class is used to load XML formated data into an instance of
+ * an EntityFactory.
+ * @author Paul Snow
+ *
+ */
+public class Mapping {
+
+ private final DTState state;
+
+ private final IRSession session;
+
+ HashMap<RName,EntityInfo> entities = new HashMap<RName,EntityInfo>();
+ HashMap<String,String> multiple = new HashMap<String,String>(); // Specifies a tag that uses an attribute to specify what entity to create.
+ HashMap<String,EntityInfo> requests = new HashMap<String,EntityInfo>();
+ HashMap<String,String> entityinfo = new HashMap<String,String>();
+ HashMap<String,ArrayList<DataObjectMap>>dataObjects = new HashMap<String,ArrayList<DataObjectMap>>();
+ /**
+ * List of attribute/list pairs. Every entity that defines the given attribute has every instance saved in the given list.
+ * Each entry is an array of two strings, the attribute and the list name.
+ */
+ ArrayList<String[]> attribute2listPairs = new ArrayList<String[]>();
+
+ /**
+ * A List of entities that should be created at intialization and put on the Entity Stack.
+ */
+ ArrayList<String> entitystack = new ArrayList<String>(); // Specifies what Entities should be on the Entity Stack to begin with.
+
+
+ /**
+ * This is the set of Attribute objects used to map XML tags to Attributes on Entities.
+ */
+ HashMap<String,AttributeInfo> setattributes = new HashMap<String,AttributeInfo>(); // Sets an attribute.
+
+
+ private Mapping(IRSession session){
+ this.session = session;
+ this.state = session.getState();
+ }
+
+ private void initialize(){
+ for(String entity : entitystack){
+ try {
+ IREntity newEntity = ((RSession)session).createEntity(null,entity);
+ session.getState().entitypush(newEntity);
+ } catch (RulesException e) {
+ throw new RuntimeException("Failed to initialize the Entity Stack: "+e);
+ }
+ }
+ }
+
+ /**
+ * For internal use only. If you need a Mapping object, get it from the appropriate
+ * RuleSet object.
+ * @param rd
+ * @param session
+ * @param filename
+ * @return
+ */
+ public static Mapping newMapping(RulesDirectory rd, IRSession session, String filename){
+ Mapping mapping = new Mapping(session);
+ try {
+ InputStream s = session.getRuleSet().openfile(filename);
+ session.getState().traceTagBegin("loadMapping", "file='"+filename+"'");
+ mapping.loadMap(s);
+ session.getState().traceTagEnd("loadMapping",null);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return mapping;
+ }
+
+
+ /**
+ * Clones the mapping structures for use by a given session
+ * @param session
+ * @param amapping
+ * @return
+ */
+ public Mapping clone(IRSession session){
+ Mapping mapping = new Mapping(session);
+ mapping.entities = entities;
+ mapping.multiple = multiple;
+ mapping.requests = requests;
+ mapping.entityinfo = entityinfo;
+ mapping.entitystack = entitystack;
+ mapping.setattributes = setattributes;
+ mapping.attribute2listPairs = attribute2listPairs;
+ mapping.dataObjects = dataObjects;
+ mapping.initialize();
+ return mapping;
+ }
+
+
+ /**
+ * Constructor for creating a Mapping. This has been deprecated because
+ * building a map this way reloads the mapping file over and over. Instead
+ * you should use:
+ *
+ * Mapping map = session.getMapping();
+ *
+ * @param rd
+ * @param session
+ * @param rs
+ * @deprecated
+ */
+ public Mapping(RulesDirectory rd,IRSession session, RuleSet rs){
+ this.session = session;
+ this.state = session.getState();
+ String filename = rs.getMapPath().get(0);
+ try {
+ InputStream s = session.getRuleSet().openfile(filename);
+ session.getState().traceTagBegin("loadMapping", "file='"+filename+"'");
+ this.loadMap(s);
+ session.getState().traceTagEnd("loadMapping",null);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Load parses XML to EDD Map file into a set of actions
+ * which can be used to build an EDD file.
+ * <br><br>
+ *
+ * @param file
+ */
+ protected void loadMap(InputStream xmlStream) throws Exception {
+ LoadMap map = new LoadMap(state,this);
+ GenericXMLParser.load(xmlStream,map);
+ if(!map.isLoadSuccessful()){
+
+ throw new Exception("Map failed to load due to errors!");
+ }
+ }
+
+ public void loadData(IRSession session, String dataSource )throws RulesException {
+ loadData(session, dataSource, dataSource);
+ }
+
+ public void loadData(IRSession session, String dataSource, String source )throws RulesException {
+ InputStream input = session.getRuleSet().openfile(dataSource);
+ if(input == null){
+ throw new RulesException("File Not Found","Mapping.loadData()","Could not open "+dataSource);
+ }
+ loadData(session,input,source);
+ }
+
+ /**
+ * This is the state for dataloading... So that data can be split over multiple files, we
+ * cache our LoadXMLData object between calls to loadData().
+ */
+ LoadXMLData dataloader = null;
+
+ /**
+ * Loads data using this mapping from an XML data Source into the given session.
+ * @param session
+ * @param dataSource
+ * @throws RulesException
+ */
+ public void loadData (IRSession session, InputStream dataSource, String source) throws RulesException {
+ if(dataloader ==null) {
+ dataloader = new LoadXMLData(this,session,session.getRuleSet().getName());
+ }
+ if(source==null){
+ source = "XML file";
+ }
+ try {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagBegin("dataLoad","source='"+source+"'");
+ }
+
+ GenericXMLParser.load(dataSource, dataloader);
+
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("dataLoad",null);
+ }
+ } catch (Exception e) {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("dataLoad",null);
+ }
+ throw new RulesException("Parse Error","LoadMap.loadData()",e.getMessage());
+ }
+ }
+
+ /**
+ * Load an in Memory data structure into the given session.
+ * @param session
+ * @param datasrc
+ * @throws RulesException
+ */
+ public void loadData(IRSession session, DataMap datasrc)throws RulesException {
+ if(dataloader ==null) {
+ dataloader = new LoadDatamapData(this,session,session.getRuleSet().getName());
+ }
+ try {
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagBegin("loadData","");
+ }
+ XMLTag tag = datasrc.getRootTag();
+ processTag(tag);
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("loadData",null);
+ }
+ }catch(Exception e){
+ if(session.getState().testState(DTState.TRACE)){
+ session.getState().traceTagEnd("loadData",null);
+ }
+ throw new RulesException("Parse Error","LoadMap.loadData()",e.getMessage());
+ }
+
+ }
+ String tagstk[] = new String[1000];
+ int tagstkptr = 0;
+ /**
+ * Load a tag into a session.
+ */
+ void processTag(XMLTag tag) throws Exception {
+ tagstk[tagstkptr++] = tag.tag;
+ dataloader.beginTag(tagstk, tagstkptr, tag.tag, tag.attribs);
+ for(XMLTag nextTag : tag.tags){
+ state.traceTagBegin("process", null);
+ processTag(nextTag);
+ state.traceTagEnd("process", null);
+ }
+ ((LoadDatamapData)dataloader).endTag(tagstk, tagstkptr, tag, tag.body, tag.attribs);
+ tagstkptr--;
+ tagstk[tagstkptr]= null;
+ }
+
+
+ /**
+ * @return the state
+ */
+ public DTState getState() {
+ return state;
+ }
+
+
+ /**
+ * @return the session
+ */
+ public IRSession getSession() {
+ return session;
+ }
+
+
+}
--- /dev/null
+/**
+ *
+ */
+package com.dtrules.mapping;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This object represents an XML tag, but I avoid serializaiton under
+ * the assumption that any conversion to a string would have been
+ * undone by a conversion from a string back to the object anyway. I
+ * also use the same structure for both tagged data and a tag holding
+ * tags.
+ *
+ * @author Paul Snow
+ * Sep 24, 2007
+ *
+ */
+public class XMLTag {
+ String tag;
+ HashMap<String, Object> attribs = new HashMap<String,Object>();
+ ArrayList<XMLTag> tags = new ArrayList<XMLTag>();
+ Object body = null;
+ XMLTag parent;
+
+ public XMLTag(String tag, XMLTag parent){
+ this.tag = tag;
+ this.parent = parent;
+ }
+
+ public String toString(){
+ String r = "<"+tag;
+ for(String key : attribs.keySet()){
+ r +=" "+key +"='"+attribs.get(key).toString()+"'";
+ }
+ if(body != null){
+ String b = body.toString();
+ if(b.length()>20){
+ b = b.substring(0,18)+"...";
+ }
+ r +=">"+b+"</"+tag+">";
+ }else if( tags.size()==0 ){
+ r += "/>";
+ }else{
+ r += ">";
+ }
+ return r;
+ }
+
+ /**
+ * @return the tag
+ */
+ public String getTag() {
+ return tag;
+ }
+
+ /**
+ * @param tag the tag to set
+ */
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * @return the tags
+ */
+ public ArrayList<XMLTag> getTags() {
+ return tags;
+ }
+
+ /**
+ * @param tags the tags to set
+ */
+ public void setTags(ArrayList<XMLTag> tags) {
+ this.tags = tags;
+ }
+
+ /**
+ * @return the body
+ */
+ public Object getBody() {
+ return body;
+ }
+
+ /**
+ * @param body the body to set
+ */
+ public void setBody(Object body) {
+ this.body = body;
+ }
+
+ /**
+ * @return the parent
+ */
+ public XMLTag getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent the parent to set
+ */
+ public void setParent(XMLTag parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return the attribs
+ */
+ public HashMap<String, Object> getAttribs() {
+ return attribs;
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/session
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RulesDirectory.java
+file
+
+
+
+
+2008-08-21T15:13:04.281250Z
+aabfcbd047fa3a8c47cf3e5c070fe181
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+EDDLoader.java
+file
+
+
+
+
+2008-08-25T05:00:36.609375Z
+6d79ce467c8dc921c6cbb9f19f4d34f8
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+ICompiler.java
+file
+
+
+
+
+2008-08-21T15:12:35.906250Z
+3b39ce202af2b0278217bd33f9a940e2
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+RuleSet.java
+file
+
+
+
+
+2008-09-09T03:46:38.125000Z
+efee01935d9546bcd15fd4c2b8553565
+2008-09-09T03:51:00.405544Z
+11672
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+11965
+\f
+EntityFactory.java
+file
+
+
+
+
+2008-09-08T18:00:07.781250Z
+7c1fccf46860da3dc65189524f965047
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12125
+\f
+RSession.java
+file
+
+
+
+
+2008-09-03T20:03:26.750000Z
+d046026b9d6fe00d1f83e48a41afc504
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17794
+\f
+DTState.java
+file
+
+
+
+
+2008-08-21T15:19:15.296875Z
+eee6c23a2e260b1eedbbc3431e53f091
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+ICompilerError.java
+file
+
+
+
+
+2008-08-21T15:17:31.156250Z
+a85579e8e378cca5ce7df9c041e21215
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+IRSession.java
+file
+
+
+
+
+2008-09-03T20:04:21.296875Z
+8afa10936adbc37a347323d039c78675
+2008-09-09T03:09:54.799966Z
+11666
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3146
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Random;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+public class DTState {
+
+ public Calendar calendar;
+ { // Work around for a Java Bug
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045774
+ //
+ try{
+ calendar = new GregorianCalendar();
+ }catch(Throwable t){}
+ }
+
+ private RDecisionTable currentTable;
+ private String currentTableSection;
+ private int numberInSection;
+
+ /**
+ * The interpreter is a stack based interpreter. The implementation
+ * is much like a Postscript Interpreter.
+ *
+ * The control stack is used to implement a stack frame for
+ * decision tables. The control stack has no analog in a PostScript
+ * interpreter.
+ *
+ * The Entity stack is used to define the context for associating
+ * attributes with values. This is much like the PostScript Dictionary
+ * Stack.
+ *
+ * The Data stack is used to pass data to operators and to return
+ * results from operators.
+ */
+
+ private final int stklimit = 1000;
+
+ IRObject ctrlstk[] = new IRObject[stklimit];
+ IRObject datastk[] = new IRObject[stklimit];
+ IREntity entitystk[] = new IREntity[stklimit];
+
+ int ctrlstkptr = 0;
+ int datastkptr = 0;
+ int entitystkptr = 0;
+
+ int frames[] = new int[stklimit];
+ int framestkptr = 0;
+ int currentframe = 0;
+
+ final IRSession session;
+
+ ArrayList<String> tagstk = new ArrayList<String>();
+ int tracePoint = 0;
+ boolean newline = true;
+
+
+ public long seed = 0x711083186866559L;
+ public Random rand = new Random(seed);
+ /**
+ * The default debugging printstream is Standard Out.
+ * The default error printstream is Standard Out.
+ */
+ private PrintStream out = System.out;
+ private PrintStream err = System.out;
+
+ public PrintStream getErrorOut() { return err; }
+ public PrintStream getDebugOut() { return out; }
+ public PrintStream getTraceOut() { return out; }
+
+ public static final int DEBUG = 0x00000001;
+ public static final int TRACE = 0x00000002;
+ public static final int ECHO = 0x00000004;
+ public static final int VERBOSE = 0x00000008;
+
+ private int state = 0;
+
+
+ /**
+ * Set the output streams for debug and trace.
+ */
+ public void setOutput(OutputStream debugtrace, OutputStream error){
+ out = new PrintStream(debugtrace);
+ err = new PrintStream(error);
+ }
+
+ /**
+ * Set the output streams for debug and trace.
+ */
+ public void setOutput(PrintStream debugtrace, PrintStream error){
+ out = debugtrace;
+ err = error;
+ }
+
+ /**
+ * We always print the error stream. But this may not
+ * be true forever.
+ * @param s
+ * @return
+ */
+ public boolean error(String s){
+ err.print(s);
+ return true;
+ }
+
+ public void traceStart(){
+ setState(TRACE);
+ tracePoint = 0;
+ traceTagBegin("DTRulesTrace",null);
+ }
+ public void traceEnd() throws RulesException {
+ traceTagEnd("DTRulesTrace",null);
+ clearState(TRACE);
+ }
+
+
+ /**
+ * Returns a trace point. The trace Point is incremented each time a
+ * point is generated. The idea is that the RulesEngine state can be
+ * reset to the state represented by one of these trace points.
+ * @return
+ */
+ public int tracePt(){ return tracePoint++; }
+
+ /**
+ * Begins an execution tag. The execution (of something) is
+ * contained between the traceStart and traceEnd tags. If any
+ * attributes should be included, pass them as a string, i.e.
+ * " dt='Compute Policy" col='5' "
+ * If ECHO is set, then the output is also echoed to
+ * Standard out.
+ */
+ public void traceTagBegin(String tag, String attribs){
+ if(testState(TRACE)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(tag + " "+attribs);
+ }
+ out.print("<"+tag+ (attribs!=null ?" "+attribs+">":">"));
+ newline = false;
+ tagstk.add(tag);
+ }
+ }
+ /**
+ * Prints a single tag, i.e. "<tag attribs />"
+ * @param tag
+ * @param attribs
+ */
+ public void traceInfo(String tag, String attribs){
+ if(testState(TRACE)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(tag + " "+attribs);
+ }
+ out.println("<"+tag+ (attribs!=null ?" "+attribs+"/>":"/>"));
+ newline = true;
+ }
+ }
+ /**
+ * Prints a tag, attributes, body, and the end tag.
+ * @param info The tag to use in the XML
+ * @param attribs Any attibutes you want
+ * @param body The body of the tag.
+ */
+ public void traceInfo(String info, String attribs, String body)throws RulesException{
+ traceTagBegin(info, attribs);
+ traceTagEnd(info,body);
+ }
+
+ /**
+ * Ends an execution tag. The execution (of something) is
+ * contained between the traceTagBegin and traceTagEnd calls.
+ * Tags are checked for balance (if the tag is supplied.)
+ * If ECHO is on, the body is written to standard.out.
+ * Standard out.
+ * Returns true if it printed something.
+ */
+ public void traceTagEnd(String tag, String body) throws RulesException {
+ if(testState(TRACE)){
+ if(testState(ECHO) && out != System.out && body!=null){
+ System.out.print(body);
+ System.out.print("\n");
+ }
+ int index = tagstk.size()-1;
+ if(index<0){
+ System.out.println("tag underflow");
+ }
+ String btag = tagstk.get(index);
+ tagstk.remove(index);
+ if(tag!=null && !btag.equals(tag)){
+ System.out.println("tag_error tag1='"+GenericXMLParser.encode(btag)+"' "+
+ "expectedtag='"+GenericXMLParser.encode(tag)+"'");
+ }
+ if(body!=null) out.print(GenericXMLParser.encode(body));
+ out.println("</"+btag+">");
+ newline=true;
+ }
+ }
+
+ /**
+ * Prints a string to the output file if DEBUG is on.
+ * If ECHO is set, then the output is also echoed to
+ * Standard out.
+ * Returns true if it printed something.
+ */
+ public boolean debug(String s){
+ if(testState(DEBUG)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(s);
+ }
+ s = GenericXMLParser.encode(s);
+ out.print("<dbg>"+s+"</dbg>");
+ newline=false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Prints the Data Stack, Entity Stack, and Control Stack to
+ * the debugging output stream.
+ */
+ public void pstack() {
+ try{
+ traceTagBegin("pstack", null);
+
+ traceTagBegin("datastk", null);
+ for (int i = 0; i < ddepth(); i++) {
+ traceTagBegin("e",null);
+ traceTagEnd ("e",getds(i).stringValue());
+ }
+ traceTagEnd("datastk",null);
+
+ traceTagBegin("entitystk", null);
+ for (int i = 0; i < edepth(); i++) {
+ traceTagBegin("e",null);
+ traceTagEnd ("e",getes(i).stringValue());
+ }
+ traceTagEnd("entitystk",null);
+
+ traceTagEnd("pstack", null);
+ }catch(RulesException e){
+ err.print("ERROR printing the stacks!\n");
+ err.print(e.toString()+"\n");
+ }
+ }
+ /**
+ * Returns the count of the number of elements on the data
+ * stack.
+ * @return data stack depth
+ */
+ public int ddepth(){
+ return datastkptr;
+ }
+ /**
+ * Returns the element on the data stack at the given depth
+ * If there are 3 elements on the data stack, getds(2) will
+ * return the top element. A stack underflow or overflow will
+ * be thrown if the index is out of range.
+ */
+ public IRObject getds(int i) throws RulesException{
+ if(i>=datastkptr){
+ throw new RulesException(
+ "Data Stack Overflow",
+ "getds",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException(
+ "Data Stack Underflow",
+ "getds",
+ "index out of range: "+i);
+ }
+ return datastk[i];
+ }
+
+ /**
+ * Returns the element on the entity stack at the given depth
+ * If there are 3 entities on the entity stack, getes(2) will
+ * return the top entity. A stack underflow or overflow will
+ * be thrown if the index is out of range.
+ */
+ public IREntity getes(int i) throws RulesException{
+ if(i>=entitystkptr){
+ throw new RulesException(
+ "Entity Stack Overflow", "getes",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException(
+ "Entity Stack Underflow", "getes",
+ "index out of range: "+i);
+ }
+ return entitystk[i];
+ }
+
+ /**
+ * While the state holds the stacks, the Session holds changes
+ * to Entities and other Rules Engine objects. On rare occasions
+ * we need to get our session, so we save it in the DTState.
+ * @param rs
+ */
+ DTState(IRSession rs){
+ session = rs;
+ }
+
+ /**
+ * Get Session
+ * @return the session assocaited with this state
+ */
+ public IRSession getSession(){ return session; }
+
+ /**
+ * Returns the index of the Entity Stack.
+ * @return
+ */
+ public int edepth () { return entitystkptr; }
+ /**
+ * Pushes an IRObject onto the data stack.
+ * @param o
+ * @throws RulesException
+ */
+ public void datapush(IRObject o) throws RulesException {
+ if(datastkptr>=1000) {
+ throw new RulesException(
+ "Data Stack Overflow",
+ o.stringValue(),
+ "Data Stack overflow.");
+ }
+ datastk[datastkptr++]=o;
+ }
+ /**
+ * Pops an IRObject off the data stack and returns that object.
+ * @return
+ * @throws RulesException
+ */
+ public IRObject datapop() throws RulesException {
+ if(datastkptr<=0) {
+ throw new RulesException( "Data Stack Underflow", "datapop()", "Data Stack underflow.");
+ }
+ IRObject rval = datastk[--datastkptr];
+ datastk[datastkptr]=null;
+ return(rval);
+ }
+
+ /**
+ * Pushes an entity on the entity stack.
+ * @param o
+ * @throws RulesException
+ */
+ public void entitypush(IREntity o) throws RulesException {
+ if(entitystkptr>=1000) {
+ throw new RulesException("Entity Stack Overflow",
+ o.stringValue(),
+ "Entity Stack overflow.");
+ }
+ entitystk[entitystkptr++]=o;
+ }
+ /**
+ * Pops an Entity off of the Entity stack.
+ * @return
+ * @throws RulesException
+ */
+ public IREntity entitypop() throws RulesException {
+ if(entitystkptr<=0) {
+ throw new RulesException("Entity Stack Underflow",
+ "entitypop", "Entity Stack underflow.");
+ }
+ IREntity rval = entitystk[--entitystkptr];
+ entitystk[entitystkptr] = null;
+ return(rval);
+ }
+ /**
+ * Returns the nth element from the top of the entity stack
+ * (0 returns the top element, 1 returns the 1 from the top, 2
+ * the 2 from the top, etc.)
+ * @return
+ * @throws RulesException
+ */
+ public IREntity entityfetch(int i) throws RulesException {
+ if(entitystkptr<=i) {
+ throw new RulesException("Entity Stack Underflow",
+ "entityfetch", "Entity Stack underflow.");
+ }
+ IREntity rval = entitystk[entitystkptr-1-i];
+ return(rval);
+ }
+
+ /**
+ * Test to see if the given flag is set.
+ * @param flag
+ * @return
+ */
+ public boolean testState(int flag){
+ return (state&flag)!=0;
+ }
+
+ /**
+ * Clear the given flag (By and'ing the not of the flag
+ * into the state)
+ */
+ public void clearState(int flag){
+ state &= flag^0xFFFFFFFF;
+ }
+
+ /**
+ * Set the given flag by or'ing the flag into the state
+ * @param flag
+ */
+ public void setState(int flag){
+ state |= flag;
+ }
+
+
+ /**
+ * Returns the current depth of the control stack.
+ * @return
+ */
+ public int cdepth(){ return ctrlstkptr; }
+
+ public void pushframe() throws RulesException{
+ if(framestkptr>=stklimit){
+ throw new RulesException("Control Stack Overflow",
+ "pushframe", "Control Stack Overflow.");
+
+ }
+ frames[framestkptr++] = currentframe;
+ currentframe = ctrlstkptr;
+ }
+
+ public void popframe() throws RulesException{
+ if(framestkptr<=0){
+ throw new RulesException("Control Stack Underflow",
+ "popframe", "Control Stack underflow.");
+ }
+ ctrlstkptr = currentframe; // Pop off this frame,
+ currentframe = frames[--framestkptr]; // Then set the currentframe back to its previous value.
+ }
+
+ public IRObject getFrameValue(int i) throws RulesException{
+ if(currentframe+i >= ctrlstkptr){
+ throw new RulesException("OutOfRange","getFrameValue","");
+ }
+ return getcs(currentframe+i);
+ }
+
+ public void setFrameValue(int i, IRObject value) throws RulesException{
+ if(currentframe+i >= ctrlstkptr){
+ throw new RulesException("OutOfRange","getFrameValue","");
+ }
+ setcs(currentframe+i, value);
+ }
+
+ /**
+ * Push an Object onto the control stack.
+ * @param o
+ */
+ public void cpush(IRObject o){
+ ctrlstk[ctrlstkptr++]= o;
+ }
+
+ /**
+ * Pop the top element from the control stack and return it.
+ * @return
+ */
+ public IRObject cpop(){
+ IRObject r = ctrlstk[--ctrlstkptr];
+ ctrlstk[ctrlstkptr]= null;
+ return r;
+ }
+
+ public IRObject getcs(int i) throws RulesException{
+ if(i>=ctrlstkptr){
+ throw new RulesException("Control Stack Overflow","getcs",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException("Control Stack Underflow","getcs",
+ "index out of range: "+i);
+ }
+ return ctrlstk[i];
+ }
+
+ public void setcs(int i, IRObject v) throws RulesException{
+ if(i>=ctrlstkptr){
+ throw new RulesException("Control Stack Overflow","setcs",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException("Control Stack Underflow","getcs",
+ "index out of range: "+i);
+ }
+ ctrlstk[i] = v;
+ }
+
+ /**
+ * This method evalates a condition, or any other set of PostFix code that produces
+ * a boolean value. The code must only add one element to the data stack, and that
+ * element must have a valid boolean value.
+ * @param c -- Condition to execute
+ * @return -- Returns the boolean value of c
+ * @throws RulesException
+ */
+ public boolean evaluateCondition(IRObject c) throws RulesException {
+ int stackindex = datastkptr; // We make sure the object only produces one boolean.
+ c.execute(this); // Execute the condition.
+ if(datastkptr-1 != stackindex){
+ throw new RulesException("Stack Check Exception","Evaluation of Condition","Stack not balanced");
+ }
+ return datapop().booleanValue();
+ }
+ /**
+ * This method executes an action, or any other set of Postfix code. This code can
+ * have side effects, but it cannot change the depth of the data stack.
+ * @param c -- Object to execute
+ * @throws RulesException
+ */
+ public void evaluate(IRObject c) throws RulesException {
+ int stackindex = datastkptr;
+ c.execute(this);
+ if(datastkptr != stackindex){
+ throw new RulesException("Stack Check Exception","Evaluation of Action","Stack not balanced");
+ }
+ }
+
+ /**
+ * Looks up the entity stack for an Entity that defines an
+ * attribute that matches the name provided. When such an Entity
+ * with an attribute that matches the name is found, that Entity
+ * is returned. A null is returned if no match is found, which
+ * means no Entity on the entity Stack defines an attribute with
+ * a name that mathches the name provided.
+ * @param name
+ */
+ public IREntity findEntity(RName name) throws RulesException{
+ RName entityname = name.getEntityName(); // If the RName does not spec an Enttiy Name
+ if(entityname == null){ // then we simply look for the RName in each
+ for(int i=entitystkptr-1;i>=0;i--){ // entity on the Entity Stack.
+ IREntity e = entitystk[i];
+ if(e.containsAttribute(name)) return e;
+ }
+ }else{ // Otherwise, we insist that the Entity name
+ for(int i=entitystkptr-1;i>=0;i--){ // match as well as insist that the Entity
+ IREntity e = entitystk[i]; // have an attribute that matches this name.
+ if(e.getName().equals(entityname)){
+ if(e.containsAttribute(name)){
+ return e;
+ }
+ }
+ }
+ }
+
+ return null; // No matach found? return a null.
+ }
+
+ /**
+ * Looks up the Entity Stack and returns the value for the
+ * given named attribute.
+ *
+ * When getting data out of the rules Engine, it is useful to
+ * take string values rather than RNames. This should never be
+ * done within the Rules Engine where RNames should be the
+ * coin of the realm.
+ *
+ * This routine simply returns a null if an error occurs or if
+ * the name is undefined.
+ */
+ public IRObject find(String name){
+ try {
+ return find(RName.getRName(name));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Looks up the entity stack and returns the entity which
+ * defines the value of the given attribute.
+ *
+ * When getting data out of the rules Engine, it is useful to
+ * take string values rather than RNames. This should never be
+ * done within the Rules Engine where RNames should be the
+ * coin of the realm.
+ *
+ * This routine simply returns a null if an error occurs or if
+ * the name is undefined.
+ */
+ public IREntity findEntity(String name){
+ try {
+ return findEntity(RName.getRName(name));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Looks up the entity stack for a match for the RName. When a match is found, the
+ * value is returned. A null is returned if no match is found.
+ * @param name
+ */
+ public IRObject find(RName name) throws RulesException{
+ IREntity entity = findEntity(name);
+ if(entity == null) return null;
+ return entity.get(name);
+ }
+
+ /**
+ * Looks up the entity stack for a match for the RName. When a match is found, the
+ * value is placed there and a true is returned.
+ * If no match is found, def returns false.
+ * @param name
+ * @param value
+ */
+ public boolean def(RName name, IRObject value, boolean protect) throws RulesException{
+
+ RName entityname = name.getEntityName();
+
+
+ for(int i=entitystkptr-1;i>=0;i--){
+ IREntity e = entitystk[i];
+ if(!e.isReadOnly() && (entityname == null || e.getName().equals(entityname) )){
+ REntityEntry entry = e.getEntry(name);
+ if(entry!=null &&(!protect || entry.writable)){
+ if(testState(TRACE)){
+ traceTagBegin("def", "entity='"+e.postFix()+"' name='"+name.stringValue()+"'");
+ traceTagEnd("def",value.postFix());
+ }
+
+ e.put(name, value);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ public RDecisionTable getCurrentTable() {
+ return currentTable;
+ }
+ public void setCurrentTable(RDecisionTable currentTable) {
+ this.currentTable = currentTable;
+ }
+ /**
+ * Condition, Action, Context, etc.
+ * @return the currentTableSection
+ */
+ public String getCurrentTableSection() {
+ return currentTableSection;
+ }
+ /**
+ * Condition, Action, Context, etc.
+ * @param currentTableSection the currentTableSection to set
+ */
+ public void setCurrentTableSection(String currentTableSection,int number) {
+ this.currentTableSection = currentTableSection;
+ this.numberInSection = number;
+ }
+ /**
+ * Condition number, context number, initial Action number, etc. -1 means not set
+ * @return the numberInSection
+ */
+ public int getNumberInSection() {
+ return numberInSection;
+ }
+ /**
+ * Condition number, context number, initial Action number, etc. -1 means not set
+ * @param numberInSection the numberInSection to set
+ */
+ public void setNumberInSection(int numberInSection) {
+ this.numberInSection = numberInSection;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class EDDLoader implements IGenericXMLParser {
+
+ final EntityFactory ef;
+ final String filename;
+ boolean succeeded = true;
+ String errorMsgs = "";
+
+ EDDLoader(String _filename, EntityFactory _ef){
+ ef = _ef;
+ filename = _filename;
+ }
+
+ /**
+ * If this string has a non-zero length, the EDD did not load
+ * properly. The caller is responsible for checking this. Otherwise
+ * the loader can only report a single error.
+ *
+ * @return
+ */
+
+
+ public String getErrorMsgs() {
+ return errorMsgs;
+ }
+
+
+
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ }
+
+ public void endTag(String[] tagstk,
+ int tagstkptr,
+ String tag,
+ String body,
+ HashMap attribs) throws Exception, IOException {
+
+ if(tag.equals("entity")){
+ String entityname = (String) attribs.get("entityname");
+ String attribute = (String) attribs.get("attribute");
+ String type = (String) attribs.get("type");
+ String subtype = (String) attribs.get("subtype");
+ String access = (String) attribs.get("access");
+ String defaultv = (String) attribs.get("default");
+
+ boolean writeable = true; // We need to convert access to a boolean
+ boolean readable = true; // Make an assumption of r/w
+ int itype = -1; // We need to convert the type to an int.
+ IRObject defaultO = null; // We need to convert the default into a Rules Engine Object.
+
+ //First deal with the access thing... Compute the boolean we need.
+ if(access==null){ // Check to see if we need to handle TIERS EDD files.
+ access = (String) attribs.get("cdd_i_c_flag");
+ if(access!=null){
+ writeable = access.toLowerCase().indexOf("i")<0;
+ }
+ }else{ // Nope? Then handle the more rational DTRules EDD files
+ writeable = access.toLowerCase().indexOf("w")>=0;
+ readable = access.toLowerCase().indexOf("r")>=0;
+ if(!writeable && !readable){
+ errorMsgs +="\nThe attribute "+attribute+" has to be either readable or writable\r\n";
+ succeeded=false;
+ }
+ }
+
+ // Now the type. An easy thing.
+ try {
+ itype = RSession.typeStr2Int(type,entityname,attribute);
+ } catch (RulesException e1) {
+ errorMsgs+= e1.getMessage()+"\n";
+ succeeded = false;
+ }
+
+ // Now deal with the default specified.
+ if (defaultv==null){ // Do we need to handle TIERS EDD files?
+ defaultv = (String) attribs.get("cdd_default_value");
+ }
+
+ defaultO = EntityFactory.computeDefaultValue(ef, ef.ruleset, defaultv, itype) ;
+
+ RName entityRName = RName.getRName(entityname.trim(),false);
+ RName attributeRName = RName.getRName(attribute.trim(),false);
+ REntity entity = ef.findcreateRefEntity(false,entityRName);
+ int intType = -1;
+ try {
+ intType = RSession.typeStr2Int(type,entityname,attribute);
+ } catch (RulesException e) {
+ errorMsgs += "Bad Type: '"+type+"' encountered on entity: '"+entityname+"' attribute: '"+attribute+"' \n";
+ succeeded = false;
+ }
+ String errstr = entity.addAttribute(attributeRName,
+ defaultv,
+ defaultO,
+ writeable,
+ readable,
+ intType,
+ subtype);
+ if(errstr!=null){
+ succeeded = false;
+ errorMsgs += errstr;
+ }
+ }
+ //else if(tag.equals("obj")){
+ // String javaclass = (String)attribs.get("class");
+ // Class javaobj = getClass().getClassLoader().loadClass(javaclass);
+ //new REntityWrapper(ef,javaobj,false,RName.getRName(body));
+ //}
+
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.decisiontables.DTLoader;
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTable;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class EntityFactory {
+
+ String create_stamp;
+ int uniqueID = 10; // Leave room for some fixed IDs. Primitives have an ID = 1, decisiontables have an ID=2;
+ boolean frozen = false;
+ RuleSet ruleset;
+ HashMap<Object,IREntity> javaObjectEntityMap = new HashMap<Object,IREntity>();
+ HashMap<IREntity,Object> entityJavaObjectMap = new HashMap<IREntity,Object>();
+ HashMap<RName,IREntity> referenceEntities = new HashMap<RName,IREntity>();
+
+ ArrayList<RName> decisiontablelist = new ArrayList<RName>();
+
+ IREntity decisiontables = new REntity(2,true,RName.getRName("decisiontables"));
+
+ /**
+ * Provides a HashMap that provides a mapping of Java Objects (as a key)
+ * to Rules Entity objects.
+ * @return
+ */
+ public HashMap<Object,IREntity> getJavaObjectEntityMap(){
+ return javaObjectEntityMap;
+ }
+
+ /**
+ * Provides a HashMap that provides a mapping of Rules Entities (as a key)
+ * to Java Objects.
+ * @return
+ */
+ public HashMap<IREntity,Object> getEntityJavaObjectMap(){
+ return entityJavaObjectMap;
+ }
+
+ /**
+ * Map the given Java Object and Entity to each other
+ */
+ public void map(Object obj, IREntity entity){
+ javaObjectEntityMap.put(obj, entity);
+ entityJavaObjectMap.put(entity,obj);
+ }
+
+ /**
+ * Creates and returns a new Decision Table object.
+ * @param name -- The name of the new decision table.
+ * @return -- The new decision table
+ */
+ public RDecisionTable newDecisionTable(String name, IRSession session)throws RulesException{
+ RName rname = RName.getRName(name);
+ return newDecisionTable(rname, session);
+ }
+
+ /**
+ * Creates and returns a new Decision Table object.
+ * @param name -- The name of the new decision table.
+ * @return -- The new decision table
+ */
+ public RDecisionTable newDecisionTable(RName name, IRSession session)throws RulesException{
+ IRObject table = decisiontables.get(name);
+ if(table !=null && table.type() != IRObject.iDecisiontable){
+ throw new RulesException("ParsingError","New Decision Table","For some reason, "+name.stringValue()+" isn't a decision table");
+ }
+ if(table != null){
+ session.getState().debug("Overwritting the Decision Table: "+name.stringValue());
+ }
+ RDecisionTable dtTable = new RDecisionTable(session,ruleset,name.stringValue());
+ decisiontablelist.add(name);
+ decisiontables.addAttribute(name, "", dtTable, false, true, IRObject.iDecisiontable,null);
+ decisiontables.put(name, dtTable);
+ return dtTable;
+ }
+ /**
+ * Delete Decision Table doesn't really delete the decision table, but removes it
+ * from the structures in the entityfactory.
+ */
+ public void deleteDecisionTable(RName name)throws RulesException {
+ IRObject table = getDecisionTable(name);
+ if(table==null)return;
+ decisiontables.removeAttribute(name);
+ decisiontablelist.remove(name);
+ }
+ /**
+ * Returns an Iterator which provides each Entity name.
+ * @return
+ */
+ public Iterator<RName> getEntityRNameIterator (){
+ return referenceEntities.keySet().iterator();
+ }
+ /**
+ * Provides an Iterator that provides each decision table name.
+ * @return
+ */
+ public Iterator<RName> getDecisionTableRNameIterator () {
+ return decisiontablelist.iterator();
+ }
+
+ /**
+ * Look up a Decision Table in the decision tables held in this Rule Set.
+ * @param name
+ * @return
+ * @throws RulesException
+ */
+ public RDecisionTable getDecisionTable(RName name)throws RulesException{
+ IRObject dt = decisiontables.get(name);
+ if(dt==null || dt.type()!=IRObject.iDecisiontable){
+ return null;
+ }
+ return (RDecisionTable) dt;
+ }
+
+ public EntityFactory(RuleSet rs) {
+ ruleset = rs;
+ ((REntity)decisiontables).removeAttribute(RName.getRName("decisiontables"));
+ }
+
+
+ public RDecisionTable findTable(RName tablename){
+ return (RDecisionTable) decisiontables.get(tablename);
+ }
+
+ /**
+ * Looks up the reference Entity given by name. Returns
+ * a null if it isn't defined.
+ * @param name
+ * @return
+ */
+ public REntity findRefEntity(RName name){
+ return (REntity) referenceEntities.get(name);
+ }
+ /**
+ * Looks up the reference Entity given by name. Creates a new
+ * reference entity if it doesn't yet exist. Otherwise it returns
+ * the existing reference entity.
+ *
+ * @param name
+ */
+ public REntity findcreateRefEntity(boolean readonly, RName name)throws RulesException {
+ if(!referenceEntities.containsKey(name)){
+ IREntity entity = new REntity(getUniqueID(), readonly, name);
+ referenceEntities.put(name,entity);
+ }
+ return (REntity) referenceEntities.get(name);
+ }
+
+ public void loadedd(String filename, InputStream edd) throws RulesException {
+ EDDLoader loader = new EDDLoader(filename, this);
+ try {
+ GenericXMLParser.load(edd,loader);
+ if(loader.succeeded==false){
+ throw new RulesException("Parsing Error(s)","EDD Loader",loader.errorMsgs);
+ }
+ } catch(Exception e){
+ throw new RulesException("Parsing Error","EDD Loader",e.toString());
+ }
+ }
+
+ /**
+ * Looks up the given Decision Table in the list of tables and returns
+ * it.
+ * @param dt
+ * @return
+ */
+ public RDecisionTable findDecisionTable(RName dt){
+ IRObject dttable = decisiontables.get(dt);
+ if(dttable==null || dttable.type()!=IRObject.iDecisiontable){
+ return null;
+ }
+ return (RDecisionTable) dttable;
+ }
+ /**
+ * Loads a set of decision tables from the given input stream.
+ * @param dt Source of Decision Tables in XML.
+ * @throws RulesException
+ */
+ public void loaddt(IRSession session, InputStream dt) throws RulesException {
+ DTLoader loader = new DTLoader(session, this);
+ try {
+ GenericXMLParser.load(dt, loader);
+ }catch (Exception e) {
+ throw new RulesException("Parsing Error","Decision Table Loader",e.toString());
+ }
+ }
+
+ @Override
+ public String toString() {
+ Iterator ikeys = referenceEntities.keySet().iterator();
+ StringBuffer buff = new StringBuffer();
+ while(ikeys.hasNext()){
+ IREntity e = referenceEntities.get(ikeys.next());
+ buff.append(e.getName().toString());
+ buff.append("\r\n");
+ Iterator iattribs = e.getAttributeIterator();
+ while(iattribs.hasNext()){
+ RName entryname = (RName)iattribs.next();
+ REntityEntry entry = e.getEntry(entryname);
+ buff.append(" ");
+ buff.append(entryname);
+ if(entry.defaultvalue!=null){
+ buff.append(" -- default value: ");
+ buff.append(entry.defaultvalue.toString());
+ }
+ buff.append("\r\n");
+ }
+ }
+ return buff.toString();
+ }
+ public static IRObject computeDefaultValue(EntityFactory ef, RuleSet ruleset, String defaultstr, int type) throws RulesException {
+
+ if(defaultstr==null ) defaultstr="";
+ defaultstr = defaultstr.trim();
+ if(defaultstr.equalsIgnoreCase("null")) defaultstr="";
+
+ switch(type){
+ case IRObject.iArray :
+ if(defaultstr.length()==0) return new RArray(ef.getUniqueID(), true,false);
+ RArray v = (RArray) RString.compile(ruleset, defaultstr, false); // We assume any values are
+ // surrounded by brackets, and regardless make
+ RArray rval = v.get(0).getNonExecutable().rArrayValue(); // sure they are non-executable.
+ return rval;
+ case IRObject.iString :
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RString.newRString(defaultstr);
+ case IRObject.iName :
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RName.getRName(defaultstr.trim(),false);
+ case IRObject.iBoolean : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RBoolean.getRBoolean(defaultstr);
+ }
+ case IRObject.iDouble : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ double value = Double.parseDouble(defaultstr);
+ return RDouble.getRDoubleValue(value);
+ }
+ case IRObject.iInteger : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ long value = Long.parseLong(defaultstr);
+ return RInteger.getRIntegerValue(value);
+ }
+ case IRObject.iTime : {
+ if(defaultstr.length()==0) return RNull.getRNull();
+ SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yyyy");
+ try {
+ Date date = fmt.parse(defaultstr);
+ return RTime.getRTime(date);
+ } catch (ParseException e) {
+ throw new RulesException("Invalid Date Format","EntityFactory.computeDefaultValue","Only support dates in 'MM/dd/yyyy' form.");
+ }
+ }
+ case IRObject.iTable : {
+ if(defaultstr.length()==0) return RNull.getRNull();
+ RTable table = RTable.newRTable(ef, null, defaultstr, -1);
+ table.setValues(ruleset, defaultstr);
+ return table;
+ }
+ default: return RNull.getRNull();
+ }
+ }
+ /**
+ * EntityFactories create things that need IDs. The EntityFactory
+ * has to be created prior to any sessions that are going to
+ * execute against the entityfactory.
+ * @return uniqueID (a long)
+ */
+ public int getUniqueID() throws RulesException{
+ if(frozen)throw new RulesException("No UniqueID","EntityFactory.getUniqueID()","Once a session has been created, you can't modify the EntityFactory");
+ return uniqueID++;
+
+ }
+
+ /**
+ * @return the decisiontables
+ */
+ public IREntity getDecisiontables() {
+ return decisiontables;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.session;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+
+@SuppressWarnings({"unchecked"})
+public interface ICompiler {
+
+ /**
+ * Return the list of unreferenced attributes so far in the use
+ * of this compiler.
+ * @return
+ */
+ public ArrayList<String> getUnReferenced();
+ /**
+ * Return the list of possible referenced attributes so far in the
+ * use of this compiler.
+ * @return
+ */
+ public ArrayList<String> getPossibleReferenced();
+ /**
+ * Last set of tokens parsed prior to the error.
+ * @return
+ */
+ public ArrayList<String> getParsedTokens();
+
+ /**
+ * Returns the last Prefix (Lisp style) string representation of the AST
+ * tree generated by this compiler instance.
+ * @return
+ */
+ public abstract String getLastPreFixExp();
+
+ /**
+ * Compiles a single Action. Returns the postfix string needed by the Rules Engine.
+ * @param action The String in "Formal" to be compiled.
+ * @return The postfix string representing the action.
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileAction(String action) throws Exception;
+
+ /**
+ * Compiles a Context Wrapper Returns the postfix string needed by the Rules Engine.
+ * @param context The String in "Formal" to be compiled.
+ * @return The postfix string representing the action.
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileContext(String context) throws Exception;
+
+ /**
+ * Compiles a single Condition. Returns the postfix string needed by the Rules Engine.
+ * @param condition The String in "Formal" to be compiled.
+ * @return The postfix string representing the condition
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileCondition(String condition) throws Exception;
+
+ /**
+ * Returns the types HashMap.
+ * @return
+ */
+ public abstract HashMap getTypes();
+
+ /**
+ * Prints all of the types known by the compiler.
+ * @throws RulesException
+ */
+ public void printTypes(PrintStream out) throws RulesException;
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.session;
+
+/**
+ * ICompilerError defines a linked list of errors generated when compiling
+ * a decision table. The error types are:
+ * <br><br>
+ * 1 -- Condition <br>
+ * 2 -- Action <br>
+ * 3 -- Table <br>
+ * 4 -- InitialAction <br>
+ * 5 -- Context <br>
+ * <br><br>
+ * @author paul snow
+ * Feb 20, 2007
+ *
+ */
+public interface ICompilerError {
+
+ enum Type { CONDITION, ACTION, TABLE, INITIALACTION, CONTEXT};
+
+ /**
+ * Returns the Error type, which will be a 1 if the error was in the
+ * compilation of a Condition, a 2 if the error was in the compliation
+ * of an Action, or a 3 if it was in building the Table.
+ * @return ErrorTypeNumber
+ */
+ Type getErrorType();
+ /**
+ * Returns the text provided the compiler which generated the error. If
+ * the error type is a 3, this function returns null.
+ * @return Source code of error
+ */
+ String getSource();
+ /**
+ * Returns an error message explaining the error.
+ * @return message explaining the error
+ */
+ String getMessage();
+ /**
+ * Returns the index (1 based) of the condition that triggered the error.
+ * Returns a value > 0 if compling a condition caused the error, and a
+ * zero otherwise. Error types 2 and 3 will always return zero.
+ * @return index of condition
+ */
+ int getConditionIndex();
+ /**
+ * Returns the index (1 based) of the action that triggered the error.
+ * Returns a value > 0 if compling an action caused the error, and a zero
+ * otherwise. Error types 1 and 3 will always return zero.
+ * @return index of action
+ */
+ int getActionIndex();
+ /**
+ * Really, we should toss the getConditionIndex and getActionIndex in
+ * favor of a getIndex which returns a 1 or greater for valid indexes,
+ * and a zero otherwise. Use the errorType to decide if this is an
+ * index into InitialActions, Conditions, or Actions.
+ */
+ int getIndex();
+ /**
+ * If the error was due to an unbalanced decision table, this funciton
+ * returns the row in the condition table where the error was detected.
+ * @return row index of error
+ */
+ int getRow();
+ /**
+ * If the error was due to an unbalanced decision table, this funciton
+ * returns the column in the condition table where the error was detected.
+ * @return column index of error
+ */
+ int getCol();
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.PrintStream;
+import java.rmi.RemoteException;
+
+import javax.rules.InvalidRuleSessionException;
+import javax.rules.RuleExecutionSetMetadata;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.xmlparser.IXMLPrinter;
+
+public interface IRSession {
+
+ /**
+ * Returns the RulesDirectory used to create this session.
+ * @return RulesDirectory
+ */
+ public abstract RulesDirectory getRulesDirectory();
+ /**
+ * Returns the RuleSet associated with this Session.
+ * @return
+ */
+ public abstract RuleSet getRuleSet();
+
+ /**
+ * Creates a new uniqueID. This ID is unique within the RSession, but
+ * not across all RSessions. Unique IDs are used to relate references
+ * between objects when writing out trace files, or to reconstruct a RSession
+ * when reading in a trace file.
+ *
+ * @return A unique integer.
+ */
+ public abstract int getUniqueID();
+
+ public abstract RuleExecutionSetMetadata getRuleExecutionSetMetadata();
+
+ public abstract void release() throws RemoteException,
+ InvalidRuleSessionException;
+
+ public abstract int getType() throws RemoteException,
+ InvalidRuleSessionException;
+
+ public abstract void execute(String s) throws RulesException;
+
+ /**
+ * Returns the Rules Engine State for this Session.
+ * @return
+ */
+ public abstract DTState getState();
+
+ public abstract EntityFactory getEntityFactory() ;
+
+ /**
+ * Debugging aid that allows you to dump an Entity and its attributes.
+ * @param e
+ */
+ public void dump(REntity e) throws RulesException;
+
+ public void printEntity(IXMLPrinter rpt, String tag, IREntity e) throws Exception ;
+
+ public void printEntityReport(IXMLPrinter rpt, DTState state, String iRObjname );
+
+ public void printEntityReport(IXMLPrinter rpt, boolean verbose, DTState state, String iRObjname );
+
+ public void printBalancedTables(PrintStream out)throws RulesException;
+
+ /**
+ * Get the default mapping
+ * @return
+ */
+ public Mapping getMapping ();
+
+ /**
+ * Get a named mapping file
+ * @param filename
+ * @return
+ */
+ public Mapping getMapping (String filename);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+
+import java.io.PrintStream;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.rules.InvalidRuleSessionException;
+import javax.rules.RuleExecutionSetMetadata;
+import javax.rules.RuleSession;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.operators.ROperator;
+import com.dtrules.xmlparser.IXMLPrinter;
+import com.dtrules.mapping.Mapping;
+
+@SuppressWarnings("unchecked")
+public class RSession implements RuleSession, IRSession {
+
+ final RuleSet rs;
+ final DTState dtstate;
+ final EntityFactory ef;
+ int uniqueID = 1;
+ HashMap<Object,IREntity> entityInstances = new HashMap<Object,IREntity>();
+ ICompiler compiler = null;
+
+ /**
+ * Get the default mapping
+ * @return
+ */
+ public Mapping getMapping () {
+ return rs.getMapping(this);
+ }
+
+ /**
+ * Get a named mapping file
+ * @param filename
+ * @return
+ */
+ public Mapping getMapping (String filename){
+ return rs.getMapping(filename, this);
+ }
+
+ /**
+ * Gets the Rules Directory used to create this session
+ * @return The Rules Directory used to create this session
+ */
+ public RulesDirectory getRulesDirectory() {
+ return rs.getRulesDirectory();
+ }
+ /**
+ * If the session is provided a compiler object, then it can compile
+ * the Formal syntax into posfix using this compiler. A Compiler is
+ * really specific to the RuleSet. However, in the future we may
+ * wish that a compiler be specific to the decision table.
+ *
+ * @param _compiler
+ */
+ public void setCompiler(ICompiler _compiler){
+ compiler = _compiler;
+ }
+
+ /**
+ * Each RSession is associated with a particular RuleSet
+ * @param _ef
+ * @throws RulesException
+ */
+ public RSession(RuleSet _rs) throws RulesException {
+ rs = _rs;
+ dtstate = new DTState(this);
+ ef = _rs.getEntityFactory(this);
+ if(ef.getUniqueID()<100000){
+ uniqueID = 100000;
+ }else{
+ uniqueID = ef.getUniqueID()+100000;
+ }
+ /**
+ * Add all the reference entities to the session list
+ * of entities.
+ */
+ Iterator<RName> ie = ef.referenceEntities.keySet().iterator();
+ while(ie.hasNext()){
+ IREntity e = ef.findRefEntity(ie.next());
+ String id = e.getID()+"";
+ if(entityInstances.containsKey(id)){
+ throw new RulesException("duplicate","new RSession()","Duplicate id "+id+" found between:\n"
+ +e.getName()+" and "+entityInstances.get(id).getName());
+ }
+ entityInstances.put(id,e);
+ }
+ try {
+ dtstate.entitypush(ROperator.getPrimitives());
+ dtstate.entitypush(ef.decisiontables);
+ } catch (RulesException e) {
+ throw new RulesException("Initialization Error",
+ "RSession",
+ "Failed to initialize dtstate in init()");
+ }
+ }
+
+ /**
+ * Does a recursive dump of the given entity to standard out.
+ * This is a debugging thing. If DEBUG isn't set in the State of the Session,
+ * calling this routine does nothing at all.
+ * @param e
+ */
+ public void dump(REntity e) throws RulesException {
+
+ if(!dtstate.testState(DTState.DEBUG))return; // Leave if nothing to do.
+ dtstate.traceTagBegin("entity", "name='"+e.getName().stringValue()+"' id='"+e.getID()+"'");
+ dump(e,1);
+ dtstate.traceTagEnd("entity", null);
+ }
+
+ private HashMap<REntity,ArrayList> boundries = new HashMap<REntity,ArrayList>(); // Track printing Entity from Entity boundries to stop recursive printing.
+
+ private String getType(REntity e, RName n) throws RulesException{
+ int type = e.getEntry(n).type;
+ return RSession.typeInt2Str(type);
+ }
+
+ /**
+ * Dumps the Entity and its attributes to the debug output source. However,
+ * if debug isn't enabled, the routine does absolutely nothing.
+ * @param e The Entity to be dumped.
+ * @param depth Dumping is a private, recursive thing. depth helps us track its recursive nature.
+ */
+ private void dump(REntity e,int depth){
+ Iterator<RName> anames = e.getAttributeIterator();
+ while(anames.hasNext()){
+ try {
+ RName aname = anames.next();
+ IRObject value = e.get(aname);
+
+ dtstate.traceTagBegin("attribute", "name='"+aname.stringValue()+"' type='"+getType(e,aname)+"'");
+ switch(e.getEntry(aname).type){
+ case IRObject.iEntity: {
+ if(value.type()==IRObject.iNull){
+ dtstate.traceInfo("value","type ='null' value='null'");
+ break;
+ }
+ dtstate.traceTagBegin("entity",
+ "name='"+((REntity)value).getName().stringValue()+
+ "' id='"+((REntity)value).getID()+"'");
+
+ if(!(boundries.get(e)!= null && boundries.get(e).contains(value))){
+ dtstate.debug(" recurse\n");
+ }else{
+ if(boundries.get(e)==null)boundries.put(e, new ArrayList());
+ boundries.get(e).add(value);
+ dump((REntity)value, depth+1);
+ }
+ dtstate.traceTagEnd("entity", null);
+ break;
+ }
+ case IRObject.iArray: {
+ ArrayList values = value.arrayValue();
+ Iterator iv = values.iterator();
+ while(iv.hasNext()){
+ IRObject v = (IRObject) iv.next();
+ if(v.type()==IRObject.iEntity){
+ dump((REntity)v,depth+2);
+ }else{
+ dtstate.traceInfo("value","v='"+v.stringValue()+"'");
+ }
+ }
+ break;
+ }
+ default : {
+ dtstate.traceInfo("value","v='"+value.stringValue()+"'");
+ }
+ }
+ dtstate.traceTagEnd("attribute",null);
+ } catch (RulesException e1) {
+ dtstate.debug("Rules Engine Exception\n");
+ e1.printStackTrace(dtstate.getErrorOut());
+ }
+ }
+ }
+
+
+ /**
+ * Return an ID that is unique for this session. The ID is generated using a simple
+ * counter. This ID will not be unique across all sessions, nor is it very likely to
+ * be unique when compared to IDs generated with by methods.
+ * <br><br>
+ * Unique IDs are used to distinguish various instances of entities apart during
+ * exectuion and/or during the generation or loading of a Trace file. They can be
+ * used for other purposes as well, under the assumption that the number of unique IDs
+ * are less than or equal to 0x7FFFFFFF hex or 2147483647 decimal.
+ *
+ * @return a Unique ID generated by a simple counter.
+ */
+ public int getUniqueID(){
+ return uniqueID++;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#getRuleExecutionSetMetadata()
+ */
+ public RuleExecutionSetMetadata getRuleExecutionSetMetadata(){
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#release()
+ */
+ public void release() throws RemoteException, InvalidRuleSessionException {
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#getType()
+ */
+ public int getType() throws RemoteException, InvalidRuleSessionException {
+ return 1;
+ }
+
+ /**
+ * Compiles the given string into an executable array, per the Rules Engine's interpreter.
+ * Assuming this compile completes, the given array is executed. A RulesException can be
+ * thrown either by the compile of the string, or the execution of the resulting array.
+ * @param s String to be compiled.
+ * @exception RulesException thrown if any problem occurs compiling or executing the string.
+ * @see com.dtrules.session.IRSession#execute(java.lang.String)
+ */
+ public void execute(String s) throws RulesException {
+ RString.newRString(s,true).execute(dtstate);
+ return;
+ }
+ /**
+ * Converts the string representation of a type into an index.
+ * @param type
+ * @return
+ * @throws RulesException
+ */
+ static public int typeStr2Int(String type, String entity, String attribute)throws RulesException{
+ type = type.trim();
+ if(type.equalsIgnoreCase("list"))type = IRObject.rArray;
+ if(type.equalsIgnoreCase("date"))type = IRObject.rTime;
+ if(type.equalsIgnoreCase("double"))type = IRObject.rFloat;
+ for(int i=0;i<IRObject.types.length;i++){
+ if(IRObject.types[i].equalsIgnoreCase(type))return i;
+ }
+ throw new RulesException("Undefined","typeStr2Int on entity: '"+entity+"' attribute: '"+attribute+"'","Bad Type Encountered:"+type);
+ }
+ /**
+ * Converts the index representation of a type into a String.
+ * @param type
+ * @return
+ * @throws RulesException
+ */
+ static public String typeInt2Str(int type)throws RulesException {
+ if(type<0 || type > IRObject.types.length){
+ throw new RulesException("Undefined","typeInt2Str","Bad Type Index Encountered: "+type);
+ }
+ return IRObject.types[type];
+ }
+
+ /**
+ * Returns the state object for this Session. The state is used by the Rules Engine in
+ * the interpretation of the decision tables.
+ * @return DTState The object holds the Data Stack, Entity Stack, and other state of the Rules Engine.
+ */
+ public DTState getState(){return dtstate; }
+
+ /**
+ * @return the ef
+ */
+ public EntityFactory getEntityFactory() {
+ return ef;
+ }
+ /**
+ * Create an Instance of an Entity of the given name.
+ * @param name The name of the Entity to create
+ * @return The entity created.
+ * @throws RulesException Thrown if any problem occurs (such as an undefined Entity name)
+ */
+ public IREntity createEntity(Object id, String name) throws RulesException{
+ RName entity = RName.getRName(name);
+ return createEntity(id, entity);
+ }
+
+ /**
+ * Create an Instance of an Entity of the given name.
+ * @param name The name of the Entity to create
+ * @return The entity created.
+ * @throws RulesException Thrown if any problem occurs (such as an undefined Entity name)
+ */
+ public IREntity createEntity(Object id, RName name) throws RulesException{
+ if(id==null){
+ id = getUniqueID()+"";
+ }
+ REntity ref = ef.findRefEntity(name);
+ if(ref==null){
+ throw new RulesException("undefined","session.createEntity","An attempt ws made to create the entity "+name.stringValue()+"\n" +
+ "This entity isn't defined in the EDD");
+ }
+ if(!ref.isReadOnly()){
+ REntity e = (REntity) ref.clone(this);
+ entityInstances.put(e.getID(),e);
+ return e;
+ }
+ return ref;
+ }
+
+
+ /**
+ * @return the rs
+ */
+ public RuleSet getRuleSet() {
+ return rs;
+ }
+
+
+ public void printEntity(IXMLPrinter rpt, String tag, IREntity e) throws Exception {
+ if(tag==null)tag = e.getName().stringValue();
+ IRObject id = e.get(RName.getRName("mapping*key"));
+ String idString = id!=null?id.stringValue():"--none--";
+ rpt.opentag(tag,"DTRulesId",e.getID()+"","id",idString);
+ Iterator<RName> names = e.getAttributeIterator();
+ while(names.hasNext()){
+ RName name = names.next();
+ IRObject v = e.get(name);
+ if(v.type()==IRObject.iArray && v.rArrayValue().size()==0) continue;
+ String vstr = v==null?"":v.stringValue();
+ rpt.printdata("attribute","name",name.stringValue(), vstr);
+ }
+ }
+
+
+ public void printArray(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, String name, RArray rarray)throws RulesException{
+ if(name!=null && name.length()>0){
+ rpt.opentag("array","name",name, "id", rarray.getID());
+ }else{
+ rpt.opentag("array");
+ }
+ for(IRObject element : rarray){
+ printIRObject(rpt, entitypath, printed, state,"",element);
+ }
+ rpt.closetag();
+ }
+
+ public void printEntityReport(IXMLPrinter rpt, DTState state, String objname ) {
+ printEntityReport(rpt,false,state,objname);
+ }
+
+ public void printEntityReport(IXMLPrinter rpt, boolean verbose, DTState state, String name ) {
+ ArrayList<IRObject> entitypath = new ArrayList<IRObject>();
+ ArrayList<IRObject> printed = null;
+ if (!verbose) printed = new ArrayList<IRObject>();
+ try {
+ IRObject obj = state.find(name);
+ if(obj==null){
+ rpt.printdata("unknown", "object", name,null);
+ }else{
+ printIRObject(rpt,entitypath, printed,state,name,obj);
+ }
+ } catch (RulesException e) {
+ rpt.print_error(e.toString());
+ }
+ }
+
+ public void printIRObject(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, String name, IRObject v) throws RulesException {
+ switch(v.type()){
+ case IRObject.iEntity :
+ if(name.length()!=0)rpt.opentag(name);
+ printAllEntities(rpt, entitypath, printed, state, v.rEntityValue());
+ if(name.length()!=0)rpt.closetag();
+ break;
+ case IRObject.iArray :
+ if(name.length()!=0)rpt.opentag(name);
+ printArray(rpt, entitypath, printed, state, name, v.rArrayValue());
+ if(name.length()!=0)rpt.closetag();
+ break;
+ default:
+ String vstr = v==null?"":v.stringValue();
+ rpt.printdata("attribute","name",name, vstr);
+ }
+ }
+
+ public void printAllEntities(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, IREntity e) throws RulesException {
+ String entityName = e.getName().stringValue();
+ if(entitypath.contains(e) && entitypath.get(entitypath.size()-1)==e){
+ rpt.printdata("entity","name",entityName, "self reference");
+ }else if (printed!= null && printed.contains(e)){
+ rpt.printdata("entity","name",entityName,"DTRulesId",e.getID(),"id",e.get("mapping*key").stringValue(),"multiple reference");
+ }else{
+ entitypath.add(e);
+ if(printed!=null) printed.add(e);
+ IRObject id = e.get(RName.getRName("mapping*key"));
+ String idString = id!=null?id.stringValue():"--none--";
+ rpt.opentag("entity","name",entityName,"DTRulesId",e.getID()+"","id",idString);
+ Iterator<RName> names = e.getAttributeIterator();
+ while(names.hasNext()){
+ RName name = names.next();
+ IRObject v = e.get(name);
+ printIRObject(rpt, entitypath, printed, state, name.stringValue(), v);
+ }
+ rpt.closetag();
+ entitypath.remove(entitypath.size()-1);
+ }
+ }
+ /**
+ * Prints all the balanced form of all the decision tables in this session to
+ * the given output stream
+ * @throws RulesException
+ */
+ public void printBalancedTables(PrintStream out)throws RulesException {
+ Iterator<RName> dts = this.getEntityFactory().getDecisionTableRNameIterator();
+ while(dts.hasNext()){
+ RName dtname = dts.next();
+ RDecisionTable dt = this.getEntityFactory().findDecisionTable(dtname);
+ String t = dt.getBalancedTable().getPrintableTable();
+
+ out.println();
+ out.println(dtname.stringValue());
+ out.println();
+ out.println(t);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.HashMap;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+/**
+ * Defines the set of artifacts which make up a logical set of
+ * rules. These include the schema for the rules (The Entity
+ * Description Dictionary or EDD) as well as the entityfactory
+ * created from the EDD. A Rule Set also includes the decision
+ * tables, and a set of mappings to map XML data into the
+ * Schema defined by the EDD.
+ * <br><br>
+ * This implementation is really just a place holder. We need
+ * to explore how to define sets of Rules, their schemas, their
+ * decision tables and the entry points into these tables, the
+ * connections between rules and databases, and rules and
+ * perhaps several UI implementations. This is a much more
+ * complex problem than it first appears.
+ *
+ * @author paul snow
+ * Jan 17, 2007
+ *
+ */
+public class RuleSet {
+ protected RName name;
+ protected boolean resource = false;
+ protected ArrayList<String> edd_names = new ArrayList<String>();
+ protected ArrayList<String> dt_names = new ArrayList<String>();
+ protected ArrayList<String> map_paths = new ArrayList<String>();
+ protected String excel_edd = null;
+ protected String excel_dtfolder = null;
+
+ protected HashMap<String,Mapping> mappings = new HashMap<String,Mapping>();
+ protected EntityFactory ef = null;
+ protected RulesDirectory rd;
+ protected String firstDecisionTableName;
+
+ protected String resourcepath =null;
+ protected String filepath =null;
+ protected String workingdirectory =null;
+
+ /**
+ * Get the default mapping (the first mapping file)
+ * @param session
+ * @return
+ */
+ public Mapping getMapping(IRSession session){
+ String filename = map_paths.get(0);
+ return getMapping(filename,session);
+ }
+
+ /**
+ * get Mapping.
+ * We create an instance that has a reference to this
+ * session, but is otherwise identical to the reference
+ * mapping.
+ */
+ public synchronized Mapping getMapping(String filename,IRSession session){
+ Mapping map = mappings.get(filename);
+ if(map != null)return map.clone(session);
+ if(map_paths.indexOf(filename)<0){
+ throw new RuntimeException("Bad Mapping File: "+filename+" For the rule set: "+name.stringValue());
+ }
+ map = Mapping.newMapping(rd, session, filename);
+ mappings.put(filename, map);
+ return map.clone(session);
+ }
+
+ /**
+ * Tries openning the filename as it is. Then attempts to open
+ * the file with the resource path. Then the file path. If everything
+ * fails, returns a null.
+ * @param filename
+ * @return InputStream
+ */
+ public InputStream openfile(String filename){
+ InputStream s = null;
+ s = RulesDirectory.openstream(this,filename);
+ if(s!=null)return s;
+ s = RulesDirectory.openstream(this,getFilepath()+"/"+filename);
+ if(s!=null)return s;
+ s = RulesDirectory.openstream(this,getResourcepath()+filename);
+ return s;
+ }
+
+ /**
+ * @return the excel_dtfolder
+ */
+ public String getExcel_dtfolder() {
+ return excel_dtfolder;
+ }
+
+ /**
+ * @param excel_dtfolder the excel_dtfolder to set
+ */
+ public void setExcel_dtfolder(String excel_dtfolder) {
+ if(excel_dtfolder.startsWith("/") || excel_dtfolder.startsWith("\\")){
+ excel_dtfolder = excel_dtfolder.substring(1);
+ }
+ this.excel_dtfolder = excel_dtfolder;
+ }
+
+ /**
+ * @return the excel_edd
+ */
+ public String getExcel_edd() {
+ return excel_edd;
+ }
+
+ /**
+ * @param excel_edd the excel_edd to set
+ */
+ public void setExcel_edd(String excel_edd) {
+ if(excel_edd.startsWith("/") || excel_edd.startsWith("\\")){
+ excel_edd = excel_edd.substring(1);
+ }
+ this.excel_edd = excel_edd;
+ }
+
+ /**
+ * Appends the directory specified in the RulesDirectory (if present) to the
+ * filepath for the Rule Set.
+ * @return the filepath
+ */
+ public String getFilepath() {
+ return rd.getFilepath()+"/"+filepath;
+ }
+
+ /**
+ * @param filepath the filepath to set
+ */
+ public void setFilepath(String filepath) {
+ filepath = filepath.trim();
+ if( !filepath.endsWith("/") && !filepath.endsWith("\\")){
+ filepath = filepath + "/";
+ }
+ //Remove any leading slash.
+ if(filepath.startsWith("/")||filepath.startsWith("\\")){
+ filepath = filepath.substring(1);
+ }
+ this.filepath = filepath;
+ }
+
+ /**
+ * @return the resourcepath
+ */
+ public String getResourcepath() {
+ return resourcepath;
+ }
+
+ /**
+ * @param resourcepath the resourcepath to set
+ */
+ public void setResourcepath(String resourcepath) {
+ this.resourcepath = resourcepath;
+ }
+
+ /**
+ * @return the workingdirectory
+ */
+ public String getWorkingdirectory() {
+ return rd.getFilepath()+"/"+workingdirectory;
+ }
+
+ /**
+ * @param workingdirectory the workingdirectory to set
+ */
+ public void setWorkingdirectory(String workingdirectory) {
+ workingdirectory = workingdirectory.trim();
+ if( !workingdirectory.endsWith("/") && !workingdirectory.endsWith("\\")){
+ workingdirectory = workingdirectory + "/";
+ }
+ //Remove any leading slash.
+ if(workingdirectory.startsWith("/")||workingdirectory.startsWith("\\")){
+ workingdirectory = workingdirectory.substring(1);
+ }
+
+ this.workingdirectory = workingdirectory;
+ }
+
+ /**
+ * Accessor for getting the Rules Directory used to create this Rule Set
+ * @return
+ */
+ RulesDirectory getRulesDirectory(){
+ return rd;
+ }
+
+ RuleSet(RulesDirectory _rd){
+ rd = _rd;
+ }
+ /**
+ * Returns an interator for the paths used to define the
+ * decision tables. These paths may point to XML files on
+ * the file system, or to resources within a jar.
+ * @return
+ */
+ public Iterator<String> DTPathIterator(){
+ return dt_names.iterator();
+ }
+
+ /**
+ * Returns an iterator for the paths used to define the
+ * EDD for this rule set. These paths may point to XML files
+ * on the file system, or to resources within a jar.
+ * @return
+ */
+ public Iterator<String> eDDPathIterator(){
+ return edd_names.iterator();
+ }
+
+ /**
+ * Creates a new Session set up to execute rules within this
+ * Rule Set. Note that a RuleSet is stateless, so a Session
+ * can point to a RuleSet, but a RuleSet can belong to many
+ * sessions.
+ * @return
+ * @throws RulesException
+ */
+ public IRSession newSession () throws RulesException{
+ return new RSession(this);
+ }
+
+ /**
+ * Get the EntityFactory associated with this ruleset.
+ * An EntityFactory is stateless, so many sessions can use
+ * the reference to a single EntityFactory.
+ * @return
+ * @throws RulesException
+ */
+ public EntityFactory getEntityFactory(IRSession session) throws RulesException{
+ if(ef==null){
+ ef = new EntityFactory(this);
+ Iterator<String> iedds = edd_names.iterator();
+ while(iedds.hasNext()){
+ String filename = iedds.next();
+ String filenameused = "";
+ InputStream s= openfile(filename);
+ if(s==null){
+ if(s==null){
+ System.out.println("No EDD XML found");
+ }
+ }
+ if(s!=null) ef.loadedd(filenameused,s);
+ }
+ Iterator<String> idts = dt_names.iterator();
+ while(idts.hasNext()){
+ String filename = idts.next();
+ InputStream s = openfile(filename);
+ if(s==null){
+ if(s==null){
+ System.out.println("No Decision Table XML found");
+ }
+ }
+ if(s!=null) ef.loaddt(session, s);
+ }
+
+ }
+ return ef;
+ }
+
+ /**
+ * Returns the path to load the mapping file. Ultimately, we
+ * should support multiple mappings into the same EDD.
+ * @return the map_path
+ */
+ public ArrayList<String> getMapPath() {
+ return map_paths;
+ }
+
+ /**
+ * Sets the path to the mapping file.
+ * @param map_path the map_path to set
+ */
+ public void setMapPath(ArrayList<String> map_path) {
+ this.map_paths = map_path;
+ }
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name.stringValue();
+ }
+
+ /**
+ * Get the name as a RName
+ */
+ public RName getRName(){
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = RName.getRName(name);
+ }
+ /**
+ * @return the dt_paths
+ */
+ public ArrayList<String> getDt_paths() {
+ return dt_names;
+ }
+ /**
+ * @param dt_paths the dt_paths to set
+ */
+ public void setDt_paths(ArrayList<String> dt_paths) {
+ this.dt_names = dt_paths;
+ }
+
+ /**
+ * Returns the single DecisionTable XML. If there are more, or none, an
+ * error is thrown.
+ * @return filename
+ * @throws RulesException
+ */
+ public String getDT_XMLName() throws RulesException{
+ if(dt_names.size()!=1){
+ throw new RulesException("UnsupportedConfiguration","RuleSet","We can only have one DecisionTable XML file");
+ }
+ return dt_names.get(0);
+ }
+ /**
+ * Returns the single EDD XML. If there are more, or none, an error is
+ * thrown.
+ * @return filename
+ * @throws RulesException
+ */
+ public String getEDD_XMLName() throws RulesException{
+ if(edd_names.size()!=1){
+ throw new RulesException("UnsupportedConfiguration","RuleSet","We can only have one EDD XML file");
+ }
+ return edd_names.get(0);
+ }
+ /**
+ * @return the edd_paths
+ */
+ public ArrayList<String> getEdd_paths() {
+ return edd_names;
+ }
+ /**
+ * @param edd_paths the edd_paths to set
+ */
+ public void setEdd_paths(ArrayList<String> edd_paths) {
+ this.edd_names = edd_paths;
+ }
+ /**
+ * @return the firstDecisionTableName
+ */
+ public String getFirstDecisionTableName() {
+ return firstDecisionTableName;
+ }
+ /**
+ * @param firstDecisionTableName the firstDecisionTableName to set
+ */
+ public void setFirstDecisionTableName(String firstDecisionTableName) {
+ this.firstDecisionTableName = firstDecisionTableName;
+ }
+
+ public String getSystemPath () {
+ return rd.getSystemPath();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class RulesDirectory {
+
+ boolean loaded;
+ HashMap<RName,RuleSet> rulesets;
+ String systemPath=""; // Path to the directory on the File System
+ // where files can be read and written. If
+ // present, it is appended to paths used by
+ // rule sets.
+
+ public void addRuleSet(RuleSet ruleset) throws RulesException {
+
+ }
+
+ /**
+ * Returns the ruleset associated with the given name. The conversion
+ * of the String to an RName is done by this routine.
+ * All hash tables in DTRules should use RNames as keys.
+ *
+ * Returns true if the RulesDirectory has been successfully loaded.
+ * @return
+ */
+ public boolean isLoaded(){return loaded;}
+
+ public RuleSet getRuleSet(String setname){
+ return getRuleSet(RName.getRName(setname));
+ }
+
+ /**
+ * Returns the ruleset associated with the given name. Note that the
+ * key is an RName. All hash tables in DTRules should use RNames as keys.
+ *
+ * @param setname
+ * @return
+ */
+ public RuleSet getRuleSet(RName setname){
+ return (RuleSet) rulesets.get(setname);
+ }
+
+
+ /**
+ * We attempt to open the streamname as a resource in our jar.
+ * Then failing that, we attempt to open it as a URL.
+ * Then failing that, we attempt to open it as a file.
+ *
+ * @param streamname
+ * @return
+ */
+ public static InputStream openstream(Object object, String streamname){
+ // First try and open the stream as a resource
+ // InputStream s = System.class.getResourceAsStream(streamname);
+
+ InputStream s = object.getClass().getResourceAsStream(streamname);
+
+ if(s!=null)return s;
+
+ // If that fails, try and open it as a URL
+ try {
+ URL url = new URL(streamname);
+ URLConnection urlc = url.openConnection();
+ s = urlc.getInputStream();
+ if(s!=null)return s;
+ } catch (MalformedURLException e) {
+ } catch (Exception e){}
+
+ // If that fails, try and open it as a file.
+ try {
+ s = new FileInputStream(streamname);
+ return s;
+ } catch (FileNotFoundException e) {}
+
+ // If all these fail, return a null.
+ return null;
+
+ }
+
+
+ String propertyfile;
+
+ /**
+ * The RulesDirectory manages the various RuleSets and the versions of
+ * RuleSets. We need to do a good bit of work to make all of this
+ * managable. For right now, I am loading the property list from the
+ * path provided this class. It first attempts to use this path as a
+ * jar resource, then an URL, then a file.
+ *
+ * The systemPath is assumed to be the name of a directory, either with
+ * or without a ending '/' or '\'.
+ *
+ * @param propertyfile
+ */
+ public RulesDirectory(String systemPath, String propertyfile) {
+ if(systemPath.endsWith("/")||systemPath.endsWith("\\")){
+ // If it has an ending slash, chop it off.
+ systemPath = systemPath.substring(0,systemPath.length()-1);
+ }
+ if(propertyfile.startsWith("/")||propertyfile.startsWith("\\")){
+ // If the propertyfile has a leading slash, chop that off.
+ propertyfile = propertyfile.substring(1);
+ }
+ this.propertyfile = propertyfile;
+ this.systemPath = systemPath.trim();
+
+ InputStream s = openstream(this,systemPath +"/"+ propertyfile);
+ loadRulesDirectory(s);
+ }
+
+ public RulesDirectory(String systemPath, InputStream s) {
+ if(systemPath.endsWith("/")||systemPath.endsWith("\\")){
+ systemPath = systemPath+"/";
+ }
+ this.systemPath = systemPath.trim();
+ propertyfile = s.toString();
+
+ loadRulesDirectory(s);
+ }
+
+ public void loadRulesDirectory(InputStream s){
+ LoadDirectory parser = new LoadDirectory(this);
+
+ if(s==null){
+ throw new RuntimeException("Could not find the file/inputstream :"+propertyfile);
+ }
+ try {
+ GenericXMLParser.load(s,parser);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing property file/inputstream: "+propertyfile+"\n"+e);
+ }
+ loaded = true;
+ }
+
+ static class LoadDirectory implements IGenericXMLParser {
+
+ final RulesDirectory rd;
+ LoadDirectory(RulesDirectory _rd){
+ rd=_rd;
+ rd.rulesets = new HashMap<RName,RuleSet>();
+ }
+ RuleSet currentset=null;
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+ if (tag.equals("RuleSet")){
+ currentset = new RuleSet(rd);
+ currentset.setName((String) attribs.get("name"));
+ if(currentset.name==null){
+ throw new RuntimeException("Missing name in RuleSet");
+ }
+ rd.rulesets.put(currentset.name, currentset);
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+ if(tag.equals("RuleSetResourcePath")){
+ currentset.setResourcepath(body.trim());
+ }else if (tag.equals("RuleSetFilePath")){
+ currentset.setFilepath(body.trim());
+ }else if (tag.equals("WorkingDirectory")){
+ currentset.setWorkingdirectory(body.trim());
+ }else if (tag.equals("Entities")){
+ currentset.edd_names.add((String) attribs.get("name"));
+ }else if (tag.equals("Decisiontables")){
+ currentset.dt_names.add((String) attribs.get("name"));
+ }else if (tag.equals("Map")){
+ currentset.map_paths.add((String) attribs.get("name"));
+ }else if (tag.equals("DTExcelFolder")){
+ currentset.setExcel_dtfolder(body.trim());
+ }else if (tag.equals("EDDExcelFile")){
+ currentset.setExcel_edd(body.trim());
+ }
+ }
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ }
+
+ /**
+ * @return the rulesets
+ */
+ public HashMap getRulesets() {
+ return rulesets;
+ }
+ /**
+ * @return the filepath
+ */
+ public String getFilepath() {
+ return systemPath;
+ }
+ /**
+ * @param filepath the filepath to set
+ */
+ public void setFilepath(String filepath) {
+ this.systemPath = filepath;
+ }
+ /**
+ * @return the systemPath
+ */
+ public String getSystemPath() {
+ return systemPath;
+ }
+ /**
+ * @param systemPath the systemPath to set
+ */
+ public void setSystemPath(String systemPath) {
+ this.systemPath = systemPath;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Random;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+public class DTState {
+
+ public Calendar calendar;
+ { // Work around for a Java Bug
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045774
+ //
+ try{
+ calendar = new GregorianCalendar();
+ }catch(Throwable t){}
+ }
+
+ private RDecisionTable currentTable;
+ private String currentTableSection;
+ private int numberInSection;
+
+ /**
+ * The interpreter is a stack based interpreter. The implementation
+ * is much like a Postscript Interpreter.
+ *
+ * The control stack is used to implement a stack frame for
+ * decision tables. The control stack has no analog in a PostScript
+ * interpreter.
+ *
+ * The Entity stack is used to define the context for associating
+ * attributes with values. This is much like the PostScript Dictionary
+ * Stack.
+ *
+ * The Data stack is used to pass data to operators and to return
+ * results from operators.
+ */
+
+ private final int stklimit = 1000;
+
+ IRObject ctrlstk[] = new IRObject[stklimit];
+ IRObject datastk[] = new IRObject[stklimit];
+ IREntity entitystk[] = new IREntity[stklimit];
+
+ int ctrlstkptr = 0;
+ int datastkptr = 0;
+ int entitystkptr = 0;
+
+ int frames[] = new int[stklimit];
+ int framestkptr = 0;
+ int currentframe = 0;
+
+ final IRSession session;
+
+ ArrayList<String> tagstk = new ArrayList<String>();
+ int tracePoint = 0;
+ boolean newline = true;
+
+
+ public long seed = 0x711083186866559L;
+ public Random rand = new Random(seed);
+ /**
+ * The default debugging printstream is Standard Out.
+ * The default error printstream is Standard Out.
+ */
+ private PrintStream out = System.out;
+ private PrintStream err = System.out;
+
+ public PrintStream getErrorOut() { return err; }
+ public PrintStream getDebugOut() { return out; }
+ public PrintStream getTraceOut() { return out; }
+
+ public static final int DEBUG = 0x00000001;
+ public static final int TRACE = 0x00000002;
+ public static final int ECHO = 0x00000004;
+ public static final int VERBOSE = 0x00000008;
+
+ private int state = 0;
+
+
+ /**
+ * Set the output streams for debug and trace.
+ */
+ public void setOutput(OutputStream debugtrace, OutputStream error){
+ out = new PrintStream(debugtrace);
+ err = new PrintStream(error);
+ }
+
+ /**
+ * Set the output streams for debug and trace.
+ */
+ public void setOutput(PrintStream debugtrace, PrintStream error){
+ out = debugtrace;
+ err = error;
+ }
+
+ /**
+ * We always print the error stream. But this may not
+ * be true forever.
+ * @param s
+ * @return
+ */
+ public boolean error(String s){
+ err.print(s);
+ return true;
+ }
+
+ public void traceStart(){
+ setState(TRACE);
+ tracePoint = 0;
+ traceTagBegin("DTRulesTrace",null);
+ }
+ public void traceEnd() throws RulesException {
+ traceTagEnd("DTRulesTrace",null);
+ clearState(TRACE);
+ }
+
+
+ /**
+ * Returns a trace point. The trace Point is incremented each time a
+ * point is generated. The idea is that the RulesEngine state can be
+ * reset to the state represented by one of these trace points.
+ * @return
+ */
+ public int tracePt(){ return tracePoint++; }
+
+ /**
+ * Begins an execution tag. The execution (of something) is
+ * contained between the traceStart and traceEnd tags. If any
+ * attributes should be included, pass them as a string, i.e.
+ * " dt='Compute Policy" col='5' "
+ * If ECHO is set, then the output is also echoed to
+ * Standard out.
+ */
+ public void traceTagBegin(String tag, String attribs){
+ if(testState(TRACE)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(tag + " "+attribs);
+ }
+ out.print("<"+tag+ (attribs!=null ?" "+attribs+">":">"));
+ newline = false;
+ tagstk.add(tag);
+ }
+ }
+ /**
+ * Prints a single tag, i.e. "<tag attribs />"
+ * @param tag
+ * @param attribs
+ */
+ public void traceInfo(String tag, String attribs){
+ if(testState(TRACE)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(tag + " "+attribs);
+ }
+ out.println("<"+tag+ (attribs!=null ?" "+attribs+"/>":"/>"));
+ newline = true;
+ }
+ }
+ /**
+ * Prints a tag, attributes, body, and the end tag.
+ * @param info The tag to use in the XML
+ * @param attribs Any attibutes you want
+ * @param body The body of the tag.
+ */
+ public void traceInfo(String info, String attribs, String body)throws RulesException{
+ traceTagBegin(info, attribs);
+ traceTagEnd(info,body);
+ }
+
+ /**
+ * Ends an execution tag. The execution (of something) is
+ * contained between the traceTagBegin and traceTagEnd calls.
+ * Tags are checked for balance (if the tag is supplied.)
+ * If ECHO is on, the body is written to standard.out.
+ * Standard out.
+ * Returns true if it printed something.
+ */
+ public void traceTagEnd(String tag, String body) throws RulesException {
+ if(testState(TRACE)){
+ if(testState(ECHO) && out != System.out && body!=null){
+ System.out.print(body);
+ System.out.print("\n");
+ }
+ int index = tagstk.size()-1;
+ if(index<0){
+ System.out.println("tag underflow");
+ }
+ String btag = tagstk.get(index);
+ tagstk.remove(index);
+ if(tag!=null && !btag.equals(tag)){
+ System.out.println("tag_error tag1='"+GenericXMLParser.encode(btag)+"' "+
+ "expectedtag='"+GenericXMLParser.encode(tag)+"'");
+ }
+ if(body!=null) out.print(GenericXMLParser.encode(body));
+ out.println("</"+btag+">");
+ newline=true;
+ }
+ }
+
+ /**
+ * Prints a string to the output file if DEBUG is on.
+ * If ECHO is set, then the output is also echoed to
+ * Standard out.
+ * Returns true if it printed something.
+ */
+ public boolean debug(String s){
+ if(testState(DEBUG)){
+ if(!newline)out.println();
+ if(testState(ECHO) && out != System.out){
+ System.out.print(s);
+ }
+ s = GenericXMLParser.encode(s);
+ out.print("<dbg>"+s+"</dbg>");
+ newline=false;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Prints the Data Stack, Entity Stack, and Control Stack to
+ * the debugging output stream.
+ */
+ public void pstack() {
+ try{
+ traceTagBegin("pstack", null);
+
+ traceTagBegin("datastk", null);
+ for (int i = 0; i < ddepth(); i++) {
+ traceTagBegin("e",null);
+ traceTagEnd ("e",getds(i).stringValue());
+ }
+ traceTagEnd("datastk",null);
+
+ traceTagBegin("entitystk", null);
+ for (int i = 0; i < edepth(); i++) {
+ traceTagBegin("e",null);
+ traceTagEnd ("e",getes(i).stringValue());
+ }
+ traceTagEnd("entitystk",null);
+
+ traceTagEnd("pstack", null);
+ }catch(RulesException e){
+ err.print("ERROR printing the stacks!\n");
+ err.print(e.toString()+"\n");
+ }
+ }
+ /**
+ * Returns the count of the number of elements on the data
+ * stack.
+ * @return data stack depth
+ */
+ public int ddepth(){
+ return datastkptr;
+ }
+ /**
+ * Returns the element on the data stack at the given depth
+ * If there are 3 elements on the data stack, getds(2) will
+ * return the top element. A stack underflow or overflow will
+ * be thrown if the index is out of range.
+ */
+ public IRObject getds(int i) throws RulesException{
+ if(i>=datastkptr){
+ throw new RulesException(
+ "Data Stack Overflow",
+ "getds",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException(
+ "Data Stack Underflow",
+ "getds",
+ "index out of range: "+i);
+ }
+ return datastk[i];
+ }
+
+ /**
+ * Returns the element on the entity stack at the given depth
+ * If there are 3 entities on the entity stack, getes(2) will
+ * return the top entity. A stack underflow or overflow will
+ * be thrown if the index is out of range.
+ */
+ public IREntity getes(int i) throws RulesException{
+ if(i>=entitystkptr){
+ throw new RulesException(
+ "Entity Stack Overflow", "getes",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException(
+ "Entity Stack Underflow", "getes",
+ "index out of range: "+i);
+ }
+ return entitystk[i];
+ }
+
+ /**
+ * While the state holds the stacks, the Session holds changes
+ * to Entities and other Rules Engine objects. On rare occasions
+ * we need to get our session, so we save it in the DTState.
+ * @param rs
+ */
+ DTState(IRSession rs){
+ session = rs;
+ }
+
+ /**
+ * Get Session
+ * @return the session assocaited with this state
+ */
+ public IRSession getSession(){ return session; }
+
+ /**
+ * Returns the index of the Entity Stack.
+ * @return
+ */
+ public int edepth () { return entitystkptr; }
+ /**
+ * Pushes an IRObject onto the data stack.
+ * @param o
+ * @throws RulesException
+ */
+ public void datapush(IRObject o) throws RulesException {
+ if(datastkptr>=1000) {
+ throw new RulesException(
+ "Data Stack Overflow",
+ o.stringValue(),
+ "Data Stack overflow.");
+ }
+ datastk[datastkptr++]=o;
+ }
+ /**
+ * Pops an IRObject off the data stack and returns that object.
+ * @return
+ * @throws RulesException
+ */
+ public IRObject datapop() throws RulesException {
+ if(datastkptr<=0) {
+ throw new RulesException( "Data Stack Underflow", "datapop()", "Data Stack underflow.");
+ }
+ IRObject rval = datastk[--datastkptr];
+ datastk[datastkptr]=null;
+ return(rval);
+ }
+
+ /**
+ * Pushes an entity on the entity stack.
+ * @param o
+ * @throws RulesException
+ */
+ public void entitypush(IREntity o) throws RulesException {
+ if(entitystkptr>=1000) {
+ throw new RulesException("Entity Stack Overflow",
+ o.stringValue(),
+ "Entity Stack overflow.");
+ }
+ entitystk[entitystkptr++]=o;
+ }
+ /**
+ * Pops an Entity off of the Entity stack.
+ * @return
+ * @throws RulesException
+ */
+ public IREntity entitypop() throws RulesException {
+ if(entitystkptr<=0) {
+ throw new RulesException("Entity Stack Underflow",
+ "entitypop", "Entity Stack underflow.");
+ }
+ IREntity rval = entitystk[--entitystkptr];
+ entitystk[entitystkptr] = null;
+ return(rval);
+ }
+ /**
+ * Returns the nth element from the top of the entity stack
+ * (0 returns the top element, 1 returns the 1 from the top, 2
+ * the 2 from the top, etc.)
+ * @return
+ * @throws RulesException
+ */
+ public IREntity entityfetch(int i) throws RulesException {
+ if(entitystkptr<=i) {
+ throw new RulesException("Entity Stack Underflow",
+ "entityfetch", "Entity Stack underflow.");
+ }
+ IREntity rval = entitystk[entitystkptr-1-i];
+ return(rval);
+ }
+
+ /**
+ * Test to see if the given flag is set.
+ * @param flag
+ * @return
+ */
+ public boolean testState(int flag){
+ return (state&flag)!=0;
+ }
+
+ /**
+ * Clear the given flag (By and'ing the not of the flag
+ * into the state)
+ */
+ public void clearState(int flag){
+ state &= flag^0xFFFFFFFF;
+ }
+
+ /**
+ * Set the given flag by or'ing the flag into the state
+ * @param flag
+ */
+ public void setState(int flag){
+ state |= flag;
+ }
+
+
+ /**
+ * Returns the current depth of the control stack.
+ * @return
+ */
+ public int cdepth(){ return ctrlstkptr; }
+
+ public void pushframe() throws RulesException{
+ if(framestkptr>=stklimit){
+ throw new RulesException("Control Stack Overflow",
+ "pushframe", "Control Stack Overflow.");
+
+ }
+ frames[framestkptr++] = currentframe;
+ currentframe = ctrlstkptr;
+ }
+
+ public void popframe() throws RulesException{
+ if(framestkptr<=0){
+ throw new RulesException("Control Stack Underflow",
+ "popframe", "Control Stack underflow.");
+ }
+ ctrlstkptr = currentframe; // Pop off this frame,
+ currentframe = frames[--framestkptr]; // Then set the currentframe back to its previous value.
+ }
+
+ public IRObject getFrameValue(int i) throws RulesException{
+ if(currentframe+i >= ctrlstkptr){
+ throw new RulesException("OutOfRange","getFrameValue","");
+ }
+ return getcs(currentframe+i);
+ }
+
+ public void setFrameValue(int i, IRObject value) throws RulesException{
+ if(currentframe+i >= ctrlstkptr){
+ throw new RulesException("OutOfRange","getFrameValue","");
+ }
+ setcs(currentframe+i, value);
+ }
+
+ /**
+ * Push an Object onto the control stack.
+ * @param o
+ */
+ public void cpush(IRObject o){
+ ctrlstk[ctrlstkptr++]= o;
+ }
+
+ /**
+ * Pop the top element from the control stack and return it.
+ * @return
+ */
+ public IRObject cpop(){
+ IRObject r = ctrlstk[--ctrlstkptr];
+ ctrlstk[ctrlstkptr]= null;
+ return r;
+ }
+
+ public IRObject getcs(int i) throws RulesException{
+ if(i>=ctrlstkptr){
+ throw new RulesException("Control Stack Overflow","getcs",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException("Control Stack Underflow","getcs",
+ "index out of range: "+i);
+ }
+ return ctrlstk[i];
+ }
+
+ public void setcs(int i, IRObject v) throws RulesException{
+ if(i>=ctrlstkptr){
+ throw new RulesException("Control Stack Overflow","setcs",
+ "index out of range: "+i);
+ }
+ if(i<0){
+ throw new RulesException("Control Stack Underflow","getcs",
+ "index out of range: "+i);
+ }
+ ctrlstk[i] = v;
+ }
+
+ /**
+ * This method evalates a condition, or any other set of PostFix code that produces
+ * a boolean value. The code must only add one element to the data stack, and that
+ * element must have a valid boolean value.
+ * @param c -- Condition to execute
+ * @return -- Returns the boolean value of c
+ * @throws RulesException
+ */
+ public boolean evaluateCondition(IRObject c) throws RulesException {
+ int stackindex = datastkptr; // We make sure the object only produces one boolean.
+ c.execute(this); // Execute the condition.
+ if(datastkptr-1 != stackindex){
+ throw new RulesException("Stack Check Exception","Evaluation of Condition","Stack not balanced");
+ }
+ return datapop().booleanValue();
+ }
+ /**
+ * This method executes an action, or any other set of Postfix code. This code can
+ * have side effects, but it cannot change the depth of the data stack.
+ * @param c -- Object to execute
+ * @throws RulesException
+ */
+ public void evaluate(IRObject c) throws RulesException {
+ int stackindex = datastkptr;
+ c.execute(this);
+ if(datastkptr != stackindex){
+ throw new RulesException("Stack Check Exception","Evaluation of Action","Stack not balanced");
+ }
+ }
+
+ /**
+ * Looks up the entity stack for an Entity that defines an
+ * attribute that matches the name provided. When such an Entity
+ * with an attribute that matches the name is found, that Entity
+ * is returned. A null is returned if no match is found, which
+ * means no Entity on the entity Stack defines an attribute with
+ * a name that mathches the name provided.
+ * @param name
+ */
+ public IREntity findEntity(RName name) throws RulesException{
+ RName entityname = name.getEntityName(); // If the RName does not spec an Enttiy Name
+ if(entityname == null){ // then we simply look for the RName in each
+ for(int i=entitystkptr-1;i>=0;i--){ // entity on the Entity Stack.
+ IREntity e = entitystk[i];
+ if(e.containsAttribute(name)) return e;
+ }
+ }else{ // Otherwise, we insist that the Entity name
+ for(int i=entitystkptr-1;i>=0;i--){ // match as well as insist that the Entity
+ IREntity e = entitystk[i]; // have an attribute that matches this name.
+ if(e.getName().equals(entityname)){
+ if(e.containsAttribute(name)){
+ return e;
+ }
+ }
+ }
+ }
+
+ return null; // No matach found? return a null.
+ }
+
+ /**
+ * Looks up the Entity Stack and returns the value for the
+ * given named attribute.
+ *
+ * When getting data out of the rules Engine, it is useful to
+ * take string values rather than RNames. This should never be
+ * done within the Rules Engine where RNames should be the
+ * coin of the realm.
+ *
+ * This routine simply returns a null if an error occurs or if
+ * the name is undefined.
+ */
+ public IRObject find(String name){
+ try {
+ return find(RName.getRName(name));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Looks up the entity stack and returns the entity which
+ * defines the value of the given attribute.
+ *
+ * When getting data out of the rules Engine, it is useful to
+ * take string values rather than RNames. This should never be
+ * done within the Rules Engine where RNames should be the
+ * coin of the realm.
+ *
+ * This routine simply returns a null if an error occurs or if
+ * the name is undefined.
+ */
+ public IREntity findEntity(String name){
+ try {
+ return findEntity(RName.getRName(name));
+ } catch (RulesException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Looks up the entity stack for a match for the RName. When a match is found, the
+ * value is returned. A null is returned if no match is found.
+ * @param name
+ */
+ public IRObject find(RName name) throws RulesException{
+ IREntity entity = findEntity(name);
+ if(entity == null) return null;
+ return entity.get(name);
+ }
+
+ /**
+ * Looks up the entity stack for a match for the RName. When a match is found, the
+ * value is placed there and a true is returned.
+ * If no match is found, def returns false.
+ * @param name
+ * @param value
+ */
+ public boolean def(RName name, IRObject value, boolean protect) throws RulesException{
+
+ RName entityname = name.getEntityName();
+
+
+ for(int i=entitystkptr-1;i>=0;i--){
+ IREntity e = entitystk[i];
+ if(!e.isReadOnly() && (entityname == null || e.getName().equals(entityname) )){
+ REntityEntry entry = e.getEntry(name);
+ if(entry!=null &&(!protect || entry.writable)){
+ if(testState(TRACE)){
+ traceTagBegin("def", "entity='"+e.postFix()+"' name='"+name.stringValue()+"'");
+ traceTagEnd("def",value.postFix());
+ }
+
+ e.put(name, value);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ public RDecisionTable getCurrentTable() {
+ return currentTable;
+ }
+ public void setCurrentTable(RDecisionTable currentTable) {
+ this.currentTable = currentTable;
+ }
+ /**
+ * Condition, Action, Context, etc.
+ * @return the currentTableSection
+ */
+ public String getCurrentTableSection() {
+ return currentTableSection;
+ }
+ /**
+ * Condition, Action, Context, etc.
+ * @param currentTableSection the currentTableSection to set
+ */
+ public void setCurrentTableSection(String currentTableSection,int number) {
+ this.currentTableSection = currentTableSection;
+ this.numberInSection = number;
+ }
+ /**
+ * Condition number, context number, initial Action number, etc. -1 means not set
+ * @return the numberInSection
+ */
+ public int getNumberInSection() {
+ return numberInSection;
+ }
+ /**
+ * Condition number, context number, initial Action number, etc. -1 means not set
+ * @param numberInSection the numberInSection to set
+ */
+ public void setNumberInSection(int numberInSection) {
+ this.numberInSection = numberInSection;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class EDDLoader implements IGenericXMLParser {
+
+ final EntityFactory ef;
+ final String filename;
+ boolean succeeded = true;
+ String errorMsgs = "";
+
+ EDDLoader(String _filename, EntityFactory _ef){
+ ef = _ef;
+ filename = _filename;
+ }
+
+ /**
+ * If this string has a non-zero length, the EDD did not load
+ * properly. The caller is responsible for checking this. Otherwise
+ * the loader can only report a single error.
+ *
+ * @return
+ */
+
+
+ public String getErrorMsgs() {
+ return errorMsgs;
+ }
+
+
+
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag,
+ HashMap attribs) throws IOException, Exception {
+ }
+
+ public void endTag(String[] tagstk,
+ int tagstkptr,
+ String tag,
+ String body,
+ HashMap attribs) throws Exception, IOException {
+
+ if(tag.equals("entity")){
+ String entityname = (String) attribs.get("entityname");
+ String attribute = (String) attribs.get("attribute");
+ String type = (String) attribs.get("type");
+ String subtype = (String) attribs.get("subtype");
+ String access = (String) attribs.get("access");
+ String defaultv = (String) attribs.get("default");
+
+ boolean writeable = true; // We need to convert access to a boolean
+ boolean readable = true; // Make an assumption of r/w
+ int itype = -1; // We need to convert the type to an int.
+ IRObject defaultO = null; // We need to convert the default into a Rules Engine Object.
+
+ //First deal with the access thing... Compute the boolean we need.
+ if(access==null){ // Check to see if we need to handle TIERS EDD files.
+ access = (String) attribs.get("cdd_i_c_flag");
+ if(access!=null){
+ writeable = access.toLowerCase().indexOf("i")<0;
+ }
+ }else{ // Nope? Then handle the more rational DTRules EDD files
+ writeable = access.toLowerCase().indexOf("w")>=0;
+ readable = access.toLowerCase().indexOf("r")>=0;
+ if(!writeable && !readable){
+ errorMsgs +="\nThe attribute "+attribute+" has to be either readable or writable\r\n";
+ succeeded=false;
+ }
+ }
+
+ // Now the type. An easy thing.
+ try {
+ itype = RSession.typeStr2Int(type,entityname,attribute);
+ } catch (RulesException e1) {
+ errorMsgs+= e1.getMessage()+"\n";
+ succeeded = false;
+ }
+
+ // Now deal with the default specified.
+ if (defaultv==null){ // Do we need to handle TIERS EDD files?
+ defaultv = (String) attribs.get("cdd_default_value");
+ }
+
+ defaultO = EntityFactory.computeDefaultValue(ef, ef.ruleset, defaultv, itype) ;
+
+ RName entityRName = RName.getRName(entityname.trim(),false);
+ RName attributeRName = RName.getRName(attribute.trim(),false);
+ REntity entity = ef.findcreateRefEntity(false,entityRName);
+ int intType = -1;
+ try {
+ intType = RSession.typeStr2Int(type,entityname,attribute);
+ } catch (RulesException e) {
+ errorMsgs += "Bad Type: '"+type+"' encountered on entity: '"+entityname+"' attribute: '"+attribute+"' \n";
+ succeeded = false;
+ }
+ String errstr = entity.addAttribute(attributeRName,
+ defaultv,
+ defaultO,
+ writeable,
+ readable,
+ intType,
+ subtype);
+ if(errstr!=null){
+ succeeded = false;
+ errorMsgs += errstr;
+ }
+ }
+ //else if(tag.equals("obj")){
+ // String javaclass = (String)attribs.get("class");
+ // Class javaobj = getClass().getClassLoader().loadClass(javaclass);
+ //new REntityWrapper(ef,javaobj,false,RName.getRName(body));
+ //}
+
+ }
+
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.dtrules.decisiontables.DTLoader;
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.entity.REntityEntry;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RBoolean;
+import com.dtrules.interpreter.RDouble;
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.RTable;
+import com.dtrules.interpreter.RTime;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class EntityFactory {
+
+ String create_stamp;
+ int uniqueID = 10; // Leave room for some fixed IDs. Primitives have an ID = 1, decisiontables have an ID=2;
+ boolean frozen = false;
+ RuleSet ruleset;
+ HashMap<Object,IREntity> javaObjectEntityMap = new HashMap<Object,IREntity>();
+ HashMap<IREntity,Object> entityJavaObjectMap = new HashMap<IREntity,Object>();
+ HashMap<RName,IREntity> referenceEntities = new HashMap<RName,IREntity>();
+
+ ArrayList<RName> decisiontablelist = new ArrayList<RName>();
+
+ IREntity decisiontables = new REntity(2,true,RName.getRName("decisiontables"));
+
+ /**
+ * Provides a HashMap that provides a mapping of Java Objects (as a key)
+ * to Rules Entity objects.
+ * @return
+ */
+ public HashMap<Object,IREntity> getJavaObjectEntityMap(){
+ return javaObjectEntityMap;
+ }
+
+ /**
+ * Provides a HashMap that provides a mapping of Rules Entities (as a key)
+ * to Java Objects.
+ * @return
+ */
+ public HashMap<IREntity,Object> getEntityJavaObjectMap(){
+ return entityJavaObjectMap;
+ }
+
+ /**
+ * Map the given Java Object and Entity to each other
+ */
+ public void map(Object obj, IREntity entity){
+ javaObjectEntityMap.put(obj, entity);
+ entityJavaObjectMap.put(entity,obj);
+ }
+
+ /**
+ * Creates and returns a new Decision Table object.
+ * @param name -- The name of the new decision table.
+ * @return -- The new decision table
+ */
+ public RDecisionTable newDecisionTable(String name, IRSession session)throws RulesException{
+ RName rname = RName.getRName(name);
+ return newDecisionTable(rname, session);
+ }
+
+ /**
+ * Creates and returns a new Decision Table object.
+ * @param name -- The name of the new decision table.
+ * @return -- The new decision table
+ */
+ public RDecisionTable newDecisionTable(RName name, IRSession session)throws RulesException{
+ IRObject table = decisiontables.get(name);
+ if(table !=null && table.type() != IRObject.iDecisiontable){
+ throw new RulesException("ParsingError","New Decision Table","For some reason, "+name.stringValue()+" isn't a decision table");
+ }
+ if(table != null){
+ session.getState().debug("Overwritting the Decision Table: "+name.stringValue());
+ }
+ RDecisionTable dtTable = new RDecisionTable(session,ruleset,name.stringValue());
+ decisiontablelist.add(name);
+ decisiontables.addAttribute(name, "", dtTable, false, true, IRObject.iDecisiontable,null);
+ decisiontables.put(name, dtTable);
+ return dtTable;
+ }
+ /**
+ * Delete Decision Table doesn't really delete the decision table, but removes it
+ * from the structures in the entityfactory.
+ */
+ public void deleteDecisionTable(RName name)throws RulesException {
+ IRObject table = getDecisionTable(name);
+ if(table==null)return;
+ decisiontables.removeAttribute(name);
+ decisiontablelist.remove(name);
+ }
+ /**
+ * Returns an Iterator which provides each Entity name.
+ * @return
+ */
+ public Iterator<RName> getEntityRNameIterator (){
+ return referenceEntities.keySet().iterator();
+ }
+ /**
+ * Provides an Iterator that provides each decision table name.
+ * @return
+ */
+ public Iterator<RName> getDecisionTableRNameIterator () {
+ return decisiontablelist.iterator();
+ }
+
+ /**
+ * Look up a Decision Table in the decision tables held in this Rule Set.
+ * @param name
+ * @return
+ * @throws RulesException
+ */
+ public RDecisionTable getDecisionTable(RName name)throws RulesException{
+ IRObject dt = decisiontables.get(name);
+ if(dt==null || dt.type()!=IRObject.iDecisiontable){
+ return null;
+ }
+ return (RDecisionTable) dt;
+ }
+
+ public EntityFactory(RuleSet rs) {
+ ruleset = rs;
+ ((REntity)decisiontables).removeAttribute(RName.getRName("decisiontables"));
+ }
+
+
+ public RDecisionTable findTable(RName tablename){
+ return (RDecisionTable) decisiontables.get(tablename);
+ }
+
+ /**
+ * Looks up the reference Entity given by name. Returns
+ * a null if it isn't defined.
+ * @param name
+ * @return
+ */
+ public REntity findRefEntity(RName name){
+ return (REntity) referenceEntities.get(name);
+ }
+ /**
+ * Looks up the reference Entity given by name. Creates a new
+ * reference entity if it doesn't yet exist. Otherwise it returns
+ * the existing reference entity.
+ *
+ * @param name
+ */
+ public REntity findcreateRefEntity(boolean readonly, RName name)throws RulesException {
+ if(!referenceEntities.containsKey(name)){
+ IREntity entity = new REntity(getUniqueID(), readonly, name);
+ referenceEntities.put(name,entity);
+ }
+ return (REntity) referenceEntities.get(name);
+ }
+
+ public void loadedd(String filename, InputStream edd) throws RulesException {
+ EDDLoader loader = new EDDLoader(filename, this);
+ try {
+ GenericXMLParser.load(edd,loader);
+ if(loader.succeeded==false){
+ throw new RulesException("Parsing Error(s)","EDD Loader",loader.errorMsgs);
+ }
+ } catch(Exception e){
+ throw new RulesException("Parsing Error","EDD Loader",e.toString());
+ }
+ }
+
+ /**
+ * Looks up the given Decision Table in the list of tables and returns
+ * it.
+ * @param dt
+ * @return
+ */
+ public RDecisionTable findDecisionTable(RName dt){
+ IRObject dttable = decisiontables.get(dt);
+ if(dttable==null || dttable.type()!=IRObject.iDecisiontable){
+ return null;
+ }
+ return (RDecisionTable) dttable;
+ }
+ /**
+ * Loads a set of decision tables from the given input stream.
+ * @param dt Source of Decision Tables in XML.
+ * @throws RulesException
+ */
+ public void loaddt(IRSession session, InputStream dt) throws RulesException {
+ DTLoader loader = new DTLoader(session, this);
+ try {
+ GenericXMLParser.load(dt, loader);
+ }catch (Exception e) {
+ throw new RulesException("Parsing Error","Decision Table Loader",e.toString());
+ }
+ }
+
+ @Override
+ public String toString() {
+ Iterator ikeys = referenceEntities.keySet().iterator();
+ StringBuffer buff = new StringBuffer();
+ while(ikeys.hasNext()){
+ IREntity e = referenceEntities.get(ikeys.next());
+ buff.append(e.getName().toString());
+ buff.append("\r\n");
+ Iterator iattribs = e.getAttributeIterator();
+ while(iattribs.hasNext()){
+ RName entryname = (RName)iattribs.next();
+ REntityEntry entry = e.getEntry(entryname);
+ buff.append(" ");
+ buff.append(entryname);
+ if(entry.defaultvalue!=null){
+ buff.append(" -- default value: ");
+ buff.append(entry.defaultvalue.toString());
+ }
+ buff.append("\r\n");
+ }
+ }
+ return buff.toString();
+ }
+ public static IRObject computeDefaultValue(EntityFactory ef, RuleSet ruleset, String defaultstr, int type) throws RulesException {
+
+ if(defaultstr==null ) defaultstr="";
+ defaultstr = defaultstr.trim();
+ if(defaultstr.equalsIgnoreCase("null")) defaultstr="";
+
+ switch(type){
+ case IRObject.iArray :
+ if(defaultstr.length()==0) return new RArray(ef.getUniqueID(), true,false);
+ RArray v = (RArray) RString.compile(ruleset, defaultstr, false); // We assume any values are
+ // surrounded by brackets, and regardless make
+ RArray rval = v.get(0).getNonExecutable().rArrayValue(); // sure they are non-executable.
+ return rval;
+ case IRObject.iString :
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RString.newRString(defaultstr);
+ case IRObject.iName :
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RName.getRName(defaultstr.trim(),false);
+ case IRObject.iBoolean : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ return RBoolean.getRBoolean(defaultstr);
+ }
+ case IRObject.iDouble : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ double value = Double.parseDouble(defaultstr);
+ return RDouble.getRDoubleValue(value);
+ }
+ case IRObject.iInteger : {
+ if(defaultstr.length()==0)return RNull.getRNull();
+ long value = Long.parseLong(defaultstr);
+ return RInteger.getRIntegerValue(value);
+ }
+ case IRObject.iTime : {
+ if(defaultstr.length()==0) return RNull.getRNull();
+ SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yyyy");
+ try {
+ Date date = fmt.parse(defaultstr);
+ return RTime.getRTime(date);
+ } catch (ParseException e) {
+ throw new RulesException("Invalid Date Format","EntityFactory.computeDefaultValue","Only support dates in 'MM/dd/yyyy' form.");
+ }
+ }
+ case IRObject.iTable : {
+ if(defaultstr.length()==0) return RNull.getRNull();
+ RTable table = RTable.newRTable(ef, null, defaultstr, -1);
+ table.setValues(ruleset, defaultstr);
+ return table;
+ }
+ default: return RNull.getRNull();
+ }
+ }
+ /**
+ * EntityFactories create things that need IDs. The EntityFactory
+ * has to be created prior to any sessions that are going to
+ * execute against the entityfactory.
+ * @return uniqueID (a long)
+ */
+ public int getUniqueID() throws RulesException{
+ if(frozen)throw new RulesException("No UniqueID","EntityFactory.getUniqueID()","Once a session has been created, you can't modify the EntityFactory");
+ return uniqueID++;
+
+ }
+
+ /**
+ * @return the decisiontables
+ */
+ public IREntity getDecisiontables() {
+ return decisiontables;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.session;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+
+@SuppressWarnings({"unchecked"})
+public interface ICompiler {
+
+ /**
+ * Return the list of unreferenced attributes so far in the use
+ * of this compiler.
+ * @return
+ */
+ public ArrayList<String> getUnReferenced();
+ /**
+ * Return the list of possible referenced attributes so far in the
+ * use of this compiler.
+ * @return
+ */
+ public ArrayList<String> getPossibleReferenced();
+ /**
+ * Last set of tokens parsed prior to the error.
+ * @return
+ */
+ public ArrayList<String> getParsedTokens();
+
+ /**
+ * Returns the last Prefix (Lisp style) string representation of the AST
+ * tree generated by this compiler instance.
+ * @return
+ */
+ public abstract String getLastPreFixExp();
+
+ /**
+ * Compiles a single Action. Returns the postfix string needed by the Rules Engine.
+ * @param action The String in "Formal" to be compiled.
+ * @return The postfix string representing the action.
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileAction(String action) throws Exception;
+
+ /**
+ * Compiles a Context Wrapper Returns the postfix string needed by the Rules Engine.
+ * @param context The String in "Formal" to be compiled.
+ * @return The postfix string representing the action.
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileContext(String context) throws Exception;
+
+ /**
+ * Compiles a single Condition. Returns the postfix string needed by the Rules Engine.
+ * @param condition The String in "Formal" to be compiled.
+ * @return The postfix string representing the condition
+ * @throws Exception Throws an exception if the compile fails for any reason.
+ */
+ public abstract String compileCondition(String condition) throws Exception;
+
+ /**
+ * Returns the types HashMap.
+ * @return
+ */
+ public abstract HashMap getTypes();
+
+ /**
+ * Prints all of the types known by the compiler.
+ * @throws RulesException
+ */
+ public void printTypes(PrintStream out) throws RulesException;
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.session;
+
+/**
+ * ICompilerError defines a linked list of errors generated when compiling
+ * a decision table. The error types are:
+ * <br><br>
+ * 1 -- Condition <br>
+ * 2 -- Action <br>
+ * 3 -- Table <br>
+ * 4 -- InitialAction <br>
+ * 5 -- Context <br>
+ * <br><br>
+ * @author paul snow
+ * Feb 20, 2007
+ *
+ */
+public interface ICompilerError {
+
+ enum Type { CONDITION, ACTION, TABLE, INITIALACTION, CONTEXT};
+
+ /**
+ * Returns the Error type, which will be a 1 if the error was in the
+ * compilation of a Condition, a 2 if the error was in the compliation
+ * of an Action, or a 3 if it was in building the Table.
+ * @return ErrorTypeNumber
+ */
+ Type getErrorType();
+ /**
+ * Returns the text provided the compiler which generated the error. If
+ * the error type is a 3, this function returns null.
+ * @return Source code of error
+ */
+ String getSource();
+ /**
+ * Returns an error message explaining the error.
+ * @return message explaining the error
+ */
+ String getMessage();
+ /**
+ * Returns the index (1 based) of the condition that triggered the error.
+ * Returns a value > 0 if compling a condition caused the error, and a
+ * zero otherwise. Error types 2 and 3 will always return zero.
+ * @return index of condition
+ */
+ int getConditionIndex();
+ /**
+ * Returns the index (1 based) of the action that triggered the error.
+ * Returns a value > 0 if compling an action caused the error, and a zero
+ * otherwise. Error types 1 and 3 will always return zero.
+ * @return index of action
+ */
+ int getActionIndex();
+ /**
+ * Really, we should toss the getConditionIndex and getActionIndex in
+ * favor of a getIndex which returns a 1 or greater for valid indexes,
+ * and a zero otherwise. Use the errorType to decide if this is an
+ * index into InitialActions, Conditions, or Actions.
+ */
+ int getIndex();
+ /**
+ * If the error was due to an unbalanced decision table, this funciton
+ * returns the row in the condition table where the error was detected.
+ * @return row index of error
+ */
+ int getRow();
+ /**
+ * If the error was due to an unbalanced decision table, this funciton
+ * returns the column in the condition table where the error was detected.
+ * @return column index of error
+ */
+ int getCol();
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.PrintStream;
+import java.rmi.RemoteException;
+
+import javax.rules.InvalidRuleSessionException;
+import javax.rules.RuleExecutionSetMetadata;
+
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.xmlparser.IXMLPrinter;
+
+public interface IRSession {
+
+ /**
+ * Returns the RulesDirectory used to create this session.
+ * @return RulesDirectory
+ */
+ public abstract RulesDirectory getRulesDirectory();
+ /**
+ * Returns the RuleSet associated with this Session.
+ * @return
+ */
+ public abstract RuleSet getRuleSet();
+
+ /**
+ * Creates a new uniqueID. This ID is unique within the RSession, but
+ * not across all RSessions. Unique IDs are used to relate references
+ * between objects when writing out trace files, or to reconstruct a RSession
+ * when reading in a trace file.
+ *
+ * @return A unique integer.
+ */
+ public abstract int getUniqueID();
+
+ public abstract RuleExecutionSetMetadata getRuleExecutionSetMetadata();
+
+ public abstract void release() throws RemoteException,
+ InvalidRuleSessionException;
+
+ public abstract int getType() throws RemoteException,
+ InvalidRuleSessionException;
+
+ public abstract void execute(String s) throws RulesException;
+
+ /**
+ * Returns the Rules Engine State for this Session.
+ * @return
+ */
+ public abstract DTState getState();
+
+ public abstract EntityFactory getEntityFactory() ;
+
+ /**
+ * Debugging aid that allows you to dump an Entity and its attributes.
+ * @param e
+ */
+ public void dump(REntity e) throws RulesException;
+
+ public void printEntity(IXMLPrinter rpt, String tag, IREntity e) throws Exception ;
+
+ public void printEntityReport(IXMLPrinter rpt, DTState state, String iRObjname );
+
+ public void printEntityReport(IXMLPrinter rpt, boolean verbose, DTState state, String iRObjname );
+
+ public void printBalancedTables(PrintStream out)throws RulesException;
+
+ /**
+ * Get the default mapping
+ * @return
+ */
+ public Mapping getMapping ();
+
+ /**
+ * Get a named mapping file
+ * @param filename
+ * @return
+ */
+ public Mapping getMapping (String filename);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+
+import java.io.PrintStream;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.rules.InvalidRuleSessionException;
+import javax.rules.RuleExecutionSetMetadata;
+import javax.rules.RuleSession;
+
+import com.dtrules.decisiontables.RDecisionTable;
+import com.dtrules.entity.IREntity;
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RArray;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RString;
+import com.dtrules.interpreter.operators.ROperator;
+import com.dtrules.xmlparser.IXMLPrinter;
+import com.dtrules.mapping.Mapping;
+
+@SuppressWarnings("unchecked")
+public class RSession implements RuleSession, IRSession {
+
+ final RuleSet rs;
+ final DTState dtstate;
+ final EntityFactory ef;
+ int uniqueID = 1;
+ HashMap<Object,IREntity> entityInstances = new HashMap<Object,IREntity>();
+ ICompiler compiler = null;
+
+ /**
+ * Get the default mapping
+ * @return
+ */
+ public Mapping getMapping () {
+ return rs.getMapping(this);
+ }
+
+ /**
+ * Get a named mapping file
+ * @param filename
+ * @return
+ */
+ public Mapping getMapping (String filename){
+ return rs.getMapping(filename, this);
+ }
+
+ /**
+ * Gets the Rules Directory used to create this session
+ * @return The Rules Directory used to create this session
+ */
+ public RulesDirectory getRulesDirectory() {
+ return rs.getRulesDirectory();
+ }
+ /**
+ * If the session is provided a compiler object, then it can compile
+ * the Formal syntax into posfix using this compiler. A Compiler is
+ * really specific to the RuleSet. However, in the future we may
+ * wish that a compiler be specific to the decision table.
+ *
+ * @param _compiler
+ */
+ public void setCompiler(ICompiler _compiler){
+ compiler = _compiler;
+ }
+
+ /**
+ * Each RSession is associated with a particular RuleSet
+ * @param _ef
+ * @throws RulesException
+ */
+ public RSession(RuleSet _rs) throws RulesException {
+ rs = _rs;
+ dtstate = new DTState(this);
+ ef = _rs.getEntityFactory(this);
+ if(ef.getUniqueID()<100000){
+ uniqueID = 100000;
+ }else{
+ uniqueID = ef.getUniqueID()+100000;
+ }
+ /**
+ * Add all the reference entities to the session list
+ * of entities.
+ */
+ Iterator<RName> ie = ef.referenceEntities.keySet().iterator();
+ while(ie.hasNext()){
+ IREntity e = ef.findRefEntity(ie.next());
+ String id = e.getID()+"";
+ if(entityInstances.containsKey(id)){
+ throw new RulesException("duplicate","new RSession()","Duplicate id "+id+" found between:\n"
+ +e.getName()+" and "+entityInstances.get(id).getName());
+ }
+ entityInstances.put(id,e);
+ }
+ try {
+ dtstate.entitypush(ROperator.getPrimitives());
+ dtstate.entitypush(ef.decisiontables);
+ } catch (RulesException e) {
+ throw new RulesException("Initialization Error",
+ "RSession",
+ "Failed to initialize dtstate in init()");
+ }
+ }
+
+ /**
+ * Does a recursive dump of the given entity to standard out.
+ * This is a debugging thing. If DEBUG isn't set in the State of the Session,
+ * calling this routine does nothing at all.
+ * @param e
+ */
+ public void dump(REntity e) throws RulesException {
+
+ if(!dtstate.testState(DTState.DEBUG))return; // Leave if nothing to do.
+ dtstate.traceTagBegin("entity", "name='"+e.getName().stringValue()+"' id='"+e.getID()+"'");
+ dump(e,1);
+ dtstate.traceTagEnd("entity", null);
+ }
+
+ private HashMap<REntity,ArrayList> boundries = new HashMap<REntity,ArrayList>(); // Track printing Entity from Entity boundries to stop recursive printing.
+
+ private String getType(REntity e, RName n) throws RulesException{
+ int type = e.getEntry(n).type;
+ return RSession.typeInt2Str(type);
+ }
+
+ /**
+ * Dumps the Entity and its attributes to the debug output source. However,
+ * if debug isn't enabled, the routine does absolutely nothing.
+ * @param e The Entity to be dumped.
+ * @param depth Dumping is a private, recursive thing. depth helps us track its recursive nature.
+ */
+ private void dump(REntity e,int depth){
+ Iterator<RName> anames = e.getAttributeIterator();
+ while(anames.hasNext()){
+ try {
+ RName aname = anames.next();
+ IRObject value = e.get(aname);
+
+ dtstate.traceTagBegin("attribute", "name='"+aname.stringValue()+"' type='"+getType(e,aname)+"'");
+ switch(e.getEntry(aname).type){
+ case IRObject.iEntity: {
+ if(value.type()==IRObject.iNull){
+ dtstate.traceInfo("value","type ='null' value='null'");
+ break;
+ }
+ dtstate.traceTagBegin("entity",
+ "name='"+((REntity)value).getName().stringValue()+
+ "' id='"+((REntity)value).getID()+"'");
+
+ if(!(boundries.get(e)!= null && boundries.get(e).contains(value))){
+ dtstate.debug(" recurse\n");
+ }else{
+ if(boundries.get(e)==null)boundries.put(e, new ArrayList());
+ boundries.get(e).add(value);
+ dump((REntity)value, depth+1);
+ }
+ dtstate.traceTagEnd("entity", null);
+ break;
+ }
+ case IRObject.iArray: {
+ ArrayList values = value.arrayValue();
+ Iterator iv = values.iterator();
+ while(iv.hasNext()){
+ IRObject v = (IRObject) iv.next();
+ if(v.type()==IRObject.iEntity){
+ dump((REntity)v,depth+2);
+ }else{
+ dtstate.traceInfo("value","v='"+v.stringValue()+"'");
+ }
+ }
+ break;
+ }
+ default : {
+ dtstate.traceInfo("value","v='"+value.stringValue()+"'");
+ }
+ }
+ dtstate.traceTagEnd("attribute",null);
+ } catch (RulesException e1) {
+ dtstate.debug("Rules Engine Exception\n");
+ e1.printStackTrace(dtstate.getErrorOut());
+ }
+ }
+ }
+
+
+ /**
+ * Return an ID that is unique for this session. The ID is generated using a simple
+ * counter. This ID will not be unique across all sessions, nor is it very likely to
+ * be unique when compared to IDs generated with by methods.
+ * <br><br>
+ * Unique IDs are used to distinguish various instances of entities apart during
+ * exectuion and/or during the generation or loading of a Trace file. They can be
+ * used for other purposes as well, under the assumption that the number of unique IDs
+ * are less than or equal to 0x7FFFFFFF hex or 2147483647 decimal.
+ *
+ * @return a Unique ID generated by a simple counter.
+ */
+ public int getUniqueID(){
+ return uniqueID++;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#getRuleExecutionSetMetadata()
+ */
+ public RuleExecutionSetMetadata getRuleExecutionSetMetadata(){
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#release()
+ */
+ public void release() throws RemoteException, InvalidRuleSessionException {
+ }
+
+ /* (non-Javadoc)
+ * @see com.dtrules.session.IRSession#getType()
+ */
+ public int getType() throws RemoteException, InvalidRuleSessionException {
+ return 1;
+ }
+
+ /**
+ * Compiles the given string into an executable array, per the Rules Engine's interpreter.
+ * Assuming this compile completes, the given array is executed. A RulesException can be
+ * thrown either by the compile of the string, or the execution of the resulting array.
+ * @param s String to be compiled.
+ * @exception RulesException thrown if any problem occurs compiling or executing the string.
+ * @see com.dtrules.session.IRSession#execute(java.lang.String)
+ */
+ public void execute(String s) throws RulesException {
+ RString.newRString(s,true).execute(dtstate);
+ return;
+ }
+ /**
+ * Converts the string representation of a type into an index.
+ * @param type
+ * @return
+ * @throws RulesException
+ */
+ static public int typeStr2Int(String type, String entity, String attribute)throws RulesException{
+ type = type.trim();
+ if(type.equalsIgnoreCase("list"))type = IRObject.rArray;
+ if(type.equalsIgnoreCase("date"))type = IRObject.rTime;
+ if(type.equalsIgnoreCase("double"))type = IRObject.rFloat;
+ for(int i=0;i<IRObject.types.length;i++){
+ if(IRObject.types[i].equalsIgnoreCase(type))return i;
+ }
+ throw new RulesException("Undefined","typeStr2Int on entity: '"+entity+"' attribute: '"+attribute+"'","Bad Type Encountered:"+type);
+ }
+ /**
+ * Converts the index representation of a type into a String.
+ * @param type
+ * @return
+ * @throws RulesException
+ */
+ static public String typeInt2Str(int type)throws RulesException {
+ if(type<0 || type > IRObject.types.length){
+ throw new RulesException("Undefined","typeInt2Str","Bad Type Index Encountered: "+type);
+ }
+ return IRObject.types[type];
+ }
+
+ /**
+ * Returns the state object for this Session. The state is used by the Rules Engine in
+ * the interpretation of the decision tables.
+ * @return DTState The object holds the Data Stack, Entity Stack, and other state of the Rules Engine.
+ */
+ public DTState getState(){return dtstate; }
+
+ /**
+ * @return the ef
+ */
+ public EntityFactory getEntityFactory() {
+ return ef;
+ }
+ /**
+ * Create an Instance of an Entity of the given name.
+ * @param name The name of the Entity to create
+ * @return The entity created.
+ * @throws RulesException Thrown if any problem occurs (such as an undefined Entity name)
+ */
+ public IREntity createEntity(Object id, String name) throws RulesException{
+ RName entity = RName.getRName(name);
+ return createEntity(id, entity);
+ }
+
+ /**
+ * Create an Instance of an Entity of the given name.
+ * @param name The name of the Entity to create
+ * @return The entity created.
+ * @throws RulesException Thrown if any problem occurs (such as an undefined Entity name)
+ */
+ public IREntity createEntity(Object id, RName name) throws RulesException{
+ if(id==null){
+ id = getUniqueID()+"";
+ }
+ REntity ref = ef.findRefEntity(name);
+ if(ref==null){
+ throw new RulesException("undefined","session.createEntity","An attempt ws made to create the entity "+name.stringValue()+"\n" +
+ "This entity isn't defined in the EDD");
+ }
+ if(!ref.isReadOnly()){
+ REntity e = (REntity) ref.clone(this);
+ entityInstances.put(e.getID(),e);
+ return e;
+ }
+ return ref;
+ }
+
+
+ /**
+ * @return the rs
+ */
+ public RuleSet getRuleSet() {
+ return rs;
+ }
+
+
+ public void printEntity(IXMLPrinter rpt, String tag, IREntity e) throws Exception {
+ if(tag==null)tag = e.getName().stringValue();
+ IRObject id = e.get(RName.getRName("mapping*key"));
+ String idString = id!=null?id.stringValue():"--none--";
+ rpt.opentag(tag,"DTRulesId",e.getID()+"","id",idString);
+ Iterator<RName> names = e.getAttributeIterator();
+ while(names.hasNext()){
+ RName name = names.next();
+ IRObject v = e.get(name);
+ if(v.type()==IRObject.iArray && v.rArrayValue().size()==0) continue;
+ String vstr = v==null?"":v.stringValue();
+ rpt.printdata("attribute","name",name.stringValue(), vstr);
+ }
+ }
+
+
+ public void printArray(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, String name, RArray rarray)throws RulesException{
+ if(name!=null && name.length()>0){
+ rpt.opentag("array","name",name, "id", rarray.getID());
+ }else{
+ rpt.opentag("array");
+ }
+ for(IRObject element : rarray){
+ printIRObject(rpt, entitypath, printed, state,"",element);
+ }
+ rpt.closetag();
+ }
+
+ public void printEntityReport(IXMLPrinter rpt, DTState state, String objname ) {
+ printEntityReport(rpt,false,state,objname);
+ }
+
+ public void printEntityReport(IXMLPrinter rpt, boolean verbose, DTState state, String name ) {
+ ArrayList<IRObject> entitypath = new ArrayList<IRObject>();
+ ArrayList<IRObject> printed = null;
+ if (!verbose) printed = new ArrayList<IRObject>();
+ try {
+ IRObject obj = state.find(name);
+ if(obj==null){
+ rpt.printdata("unknown", "object", name,null);
+ }else{
+ printIRObject(rpt,entitypath, printed,state,name,obj);
+ }
+ } catch (RulesException e) {
+ rpt.print_error(e.toString());
+ }
+ }
+
+ public void printIRObject(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, String name, IRObject v) throws RulesException {
+ switch(v.type()){
+ case IRObject.iEntity :
+ if(name.length()!=0)rpt.opentag(name);
+ printAllEntities(rpt, entitypath, printed, state, v.rEntityValue());
+ if(name.length()!=0)rpt.closetag();
+ break;
+ case IRObject.iArray :
+ if(name.length()!=0)rpt.opentag(name);
+ printArray(rpt, entitypath, printed, state, name, v.rArrayValue());
+ if(name.length()!=0)rpt.closetag();
+ break;
+ default:
+ String vstr = v==null?"":v.stringValue();
+ rpt.printdata("attribute","name",name, vstr);
+ }
+ }
+
+ public void printAllEntities(IXMLPrinter rpt, ArrayList<IRObject> entitypath, ArrayList<IRObject> printed, DTState state, IREntity e) throws RulesException {
+ String entityName = e.getName().stringValue();
+ if(entitypath.contains(e) && entitypath.get(entitypath.size()-1)==e){
+ rpt.printdata("entity","name",entityName, "self reference");
+ }else if (printed!= null && printed.contains(e)){
+ rpt.printdata("entity","name",entityName,"DTRulesId",e.getID(),"id",e.get("mapping*key").stringValue(),"multiple reference");
+ }else{
+ entitypath.add(e);
+ if(printed!=null) printed.add(e);
+ IRObject id = e.get(RName.getRName("mapping*key"));
+ String idString = id!=null?id.stringValue():"--none--";
+ rpt.opentag("entity","name",entityName,"DTRulesId",e.getID()+"","id",idString);
+ Iterator<RName> names = e.getAttributeIterator();
+ while(names.hasNext()){
+ RName name = names.next();
+ IRObject v = e.get(name);
+ printIRObject(rpt, entitypath, printed, state, name.stringValue(), v);
+ }
+ rpt.closetag();
+ entitypath.remove(entitypath.size()-1);
+ }
+ }
+ /**
+ * Prints all the balanced form of all the decision tables in this session to
+ * the given output stream
+ * @throws RulesException
+ */
+ public void printBalancedTables(PrintStream out)throws RulesException {
+ Iterator<RName> dts = this.getEntityFactory().getDecisionTableRNameIterator();
+ while(dts.hasNext()){
+ RName dtname = dts.next();
+ RDecisionTable dt = this.getEntityFactory().findDecisionTable(dtname);
+ String t = dt.getBalancedTable().getPrintableTable();
+
+ out.println();
+ out.println(dtname.stringValue());
+ out.println();
+ out.println(t);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.HashMap;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+/**
+ * Defines the set of artifacts which make up a logical set of
+ * rules. These include the schema for the rules (The Entity
+ * Description Dictionary or EDD) as well as the entityfactory
+ * created from the EDD. A Rule Set also includes the decision
+ * tables, and a set of mappings to map XML data into the
+ * Schema defined by the EDD.
+ * <br><br>
+ * This implementation is really just a place holder. We need
+ * to explore how to define sets of Rules, their schemas, their
+ * decision tables and the entry points into these tables, the
+ * connections between rules and databases, and rules and
+ * perhaps several UI implementations. This is a much more
+ * complex problem than it first appears.
+ *
+ * @author paul snow
+ * Jan 17, 2007
+ *
+ */
+public class RuleSet {
+ protected RName name;
+ protected boolean resource = false;
+ protected ArrayList<String> edd_names = new ArrayList<String>();
+ protected ArrayList<String> dt_names = new ArrayList<String>();
+ protected ArrayList<String> map_paths = new ArrayList<String>();
+ protected String excel_edd = null;
+ protected String excel_dtfolder = null;
+
+ protected HashMap<String,Mapping> mappings = new HashMap<String,Mapping>();
+ protected EntityFactory ef = null;
+ protected RulesDirectory rd;
+ protected String firstDecisionTableName;
+
+ protected String resourcepath =null;
+ protected String filepath =null;
+ protected String workingdirectory =null;
+
+ /**
+ * Get the default mapping (the first mapping file)
+ * @param session
+ * @return
+ */
+ public Mapping getMapping(IRSession session){
+ String filename = map_paths.get(0);
+ return getMapping(filename,session);
+ }
+
+ /**
+ * get Mapping.
+ * We create an instance that has a reference to this
+ * session, but is otherwise identical to the reference
+ * mapping.
+ */
+ public synchronized Mapping getMapping(String filename,IRSession session){
+ Mapping map = mappings.get(filename);
+ if(map != null)return map.clone(session);
+ if(map_paths.indexOf(filename)<0){
+ throw new RuntimeException("Bad Mapping File: "+filename+" For the rule set: "+name.stringValue());
+ }
+ map = Mapping.newMapping(rd, session, filename);
+ mappings.put(filename, map);
+ return map.clone(session);
+ }
+
+ /**
+ * Tries openning the filename as it is. Then attempts to open
+ * the file with the resource path. Then the file path. If everything
+ * fails, returns a null.
+ * @param filename
+ * @return InputStream
+ */
+ public InputStream openfile(String filename){
+ InputStream s = null;
+ s = RulesDirectory.openstream(this,filename);
+ if(s!=null)return s;
+ s = RulesDirectory.openstream(this,getFilepath()+"/"+filename);
+ if(s!=null)return s;
+ s = RulesDirectory.openstream(this,getResourcepath()+filename);
+ return s;
+ }
+
+ /**
+ * @return the excel_dtfolder
+ */
+ public String getExcel_dtfolder() {
+ return excel_dtfolder;
+ }
+
+ /**
+ * @param excel_dtfolder the excel_dtfolder to set
+ */
+ public void setExcel_dtfolder(String excel_dtfolder) {
+ if(excel_dtfolder.startsWith("/") || excel_dtfolder.startsWith("\\")){
+ excel_dtfolder = excel_dtfolder.substring(1);
+ }
+ this.excel_dtfolder = excel_dtfolder;
+ }
+
+ /**
+ * @return the excel_edd
+ */
+ public String getExcel_edd() {
+ return excel_edd;
+ }
+
+ /**
+ * @param excel_edd the excel_edd to set
+ */
+ public void setExcel_edd(String excel_edd) {
+ if(excel_edd.startsWith("/") || excel_edd.startsWith("\\")){
+ excel_edd = excel_edd.substring(1);
+ }
+ this.excel_edd = excel_edd;
+ }
+
+ /**
+ * Appends the directory specified in the RulesDirectory (if present) to the
+ * filepath for the Rule Set.
+ * @return the filepath
+ */
+ public String getFilepath() {
+ return rd.getFilepath()+"/"+filepath;
+ }
+
+ /**
+ * @param filepath the filepath to set
+ */
+ public void setFilepath(String filepath) {
+ filepath = filepath.trim();
+ if( !filepath.endsWith("/") && !filepath.endsWith("\\")){
+ filepath = filepath + "/";
+ }
+ //Remove any leading slash.
+ if(filepath.startsWith("/")||filepath.startsWith("\\")){
+ filepath = filepath.substring(1);
+ }
+ this.filepath = filepath;
+ }
+
+ /**
+ * @return the resourcepath
+ */
+ public String getResourcepath() {
+ return resourcepath;
+ }
+
+ /**
+ * @param resourcepath the resourcepath to set
+ */
+ public void setResourcepath(String resourcepath) {
+ this.resourcepath = resourcepath;
+ }
+
+ /**
+ * @return the workingdirectory
+ */
+ public String getWorkingdirectory() {
+ return rd.getFilepath()+"/"+workingdirectory;
+ }
+
+ /**
+ * @param workingdirectory the workingdirectory to set
+ */
+ public void setWorkingdirectory(String workingdirectory) {
+ workingdirectory = workingdirectory.trim();
+ if( !workingdirectory.endsWith("/") && !workingdirectory.endsWith("\\")){
+ workingdirectory = workingdirectory + "/";
+ }
+ //Remove any leading slash.
+ if(workingdirectory.startsWith("/")||workingdirectory.startsWith("\\")){
+ workingdirectory = workingdirectory.substring(1);
+ }
+
+ this.workingdirectory = workingdirectory;
+ }
+
+ /**
+ * Accessor for getting the Rules Directory used to create this Rule Set
+ * @return
+ */
+ RulesDirectory getRulesDirectory(){
+ return rd;
+ }
+
+ RuleSet(RulesDirectory _rd){
+ rd = _rd;
+ }
+ /**
+ * Returns an interator for the paths used to define the
+ * decision tables. These paths may point to XML files on
+ * the file system, or to resources within a jar.
+ * @return
+ */
+ public Iterator<String> DTPathIterator(){
+ return dt_names.iterator();
+ }
+
+ /**
+ * Returns an iterator for the paths used to define the
+ * EDD for this rule set. These paths may point to XML files
+ * on the file system, or to resources within a jar.
+ * @return
+ */
+ public Iterator<String> eDDPathIterator(){
+ return edd_names.iterator();
+ }
+
+ /**
+ * Creates a new Session set up to execute rules within this
+ * Rule Set. Note that a RuleSet is stateless, so a Session
+ * can point to a RuleSet, but a RuleSet can belong to many
+ * sessions.
+ * @return
+ * @throws RulesException
+ */
+ public IRSession newSession () throws RulesException{
+ return new RSession(this);
+ }
+
+ /**
+ * Get the EntityFactory associated with this ruleset.
+ * An EntityFactory is stateless, so many sessions can use
+ * the reference to a single EntityFactory.
+ * @return
+ * @throws RulesException
+ */
+ public EntityFactory getEntityFactory(IRSession session) throws RulesException{
+ if(ef==null){
+ ef = new EntityFactory(this);
+ Iterator<String> iedds = edd_names.iterator();
+ while(iedds.hasNext()){
+ String filename = iedds.next();
+ String filenameused = "";
+ InputStream s= openfile(filename);
+ if(s==null){
+ if(s==null){
+ System.out.println("No EDD XML found");
+ }
+ }
+ if(s!=null) ef.loadedd(filenameused,s);
+ }
+ Iterator<String> idts = dt_names.iterator();
+ while(idts.hasNext()){
+ String filename = idts.next();
+ InputStream s = openfile(filename);
+ if(s==null){
+ if(s==null){
+ System.out.println("No Decision Table XML found");
+ }
+ }
+ if(s!=null) ef.loaddt(session, s);
+ }
+
+ }
+ return ef;
+ }
+
+ /**
+ * Returns the path to load the mapping file. Ultimately, we
+ * should support multiple mappings into the same EDD.
+ * @return the map_path
+ */
+ public ArrayList<String> getMapPath() {
+ return map_paths;
+ }
+
+ /**
+ * Sets the path to the mapping file.
+ * @param map_path the map_path to set
+ */
+ public void setMapPath(ArrayList<String> map_path) {
+ this.map_paths = map_path;
+ }
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name.stringValue();
+ }
+
+ /**
+ * Get the name as a RName
+ */
+ public RName getRName(){
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = RName.getRName(name);
+ }
+ /**
+ * @return the dt_paths
+ */
+ public ArrayList<String> getDt_paths() {
+ return dt_names;
+ }
+ /**
+ * @param dt_paths the dt_paths to set
+ */
+ public void setDt_paths(ArrayList<String> dt_paths) {
+ this.dt_names = dt_paths;
+ }
+
+ /**
+ * Returns the single DecisionTable XML. If there are more, or none, an
+ * error is thrown.
+ * @return filename
+ * @throws RulesException
+ */
+ public String getDT_XMLName() throws RulesException{
+ if(dt_names.size()!=1){
+ throw new RulesException("UnsupportedConfiguration","RuleSet","We can only have one DecisionTable XML file");
+ }
+ return dt_names.get(0);
+ }
+ /**
+ * Returns the single EDD XML. If there are more, or none, an error is
+ * thrown.
+ * @return filename
+ * @throws RulesException
+ */
+ public String getEDD_XMLName() throws RulesException{
+ if(edd_names.size()!=1){
+ throw new RulesException("UnsupportedConfiguration","RuleSet","We can only have one EDD XML file");
+ }
+ return edd_names.get(0);
+ }
+ /**
+ * @return the edd_paths
+ */
+ public ArrayList<String> getEdd_paths() {
+ return edd_names;
+ }
+ /**
+ * @param edd_paths the edd_paths to set
+ */
+ public void setEdd_paths(ArrayList<String> edd_paths) {
+ this.edd_names = edd_paths;
+ }
+ /**
+ * @return the firstDecisionTableName
+ */
+ public String getFirstDecisionTableName() {
+ return firstDecisionTableName;
+ }
+ /**
+ * @param firstDecisionTableName the firstDecisionTableName to set
+ */
+ public void setFirstDecisionTableName(String firstDecisionTableName) {
+ this.firstDecisionTableName = firstDecisionTableName;
+ }
+
+ public String getSystemPath () {
+ return rd.getSystemPath();
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.session;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.xmlparser.GenericXMLParser;
+import com.dtrules.xmlparser.IGenericXMLParser;
+
+@SuppressWarnings({"unchecked"})
+public class RulesDirectory {
+
+ boolean loaded;
+ HashMap<RName,RuleSet> rulesets;
+ String systemPath=""; // Path to the directory on the File System
+ // where files can be read and written. If
+ // present, it is appended to paths used by
+ // rule sets.
+
+ public void addRuleSet(RuleSet ruleset) throws RulesException {
+
+ }
+
+ /**
+ * Returns the ruleset associated with the given name. The conversion
+ * of the String to an RName is done by this routine.
+ * All hash tables in DTRules should use RNames as keys.
+ *
+ * Returns true if the RulesDirectory has been successfully loaded.
+ * @return
+ */
+ public boolean isLoaded(){return loaded;}
+
+ public RuleSet getRuleSet(String setname){
+ return getRuleSet(RName.getRName(setname));
+ }
+
+ /**
+ * Returns the ruleset associated with the given name. Note that the
+ * key is an RName. All hash tables in DTRules should use RNames as keys.
+ *
+ * @param setname
+ * @return
+ */
+ public RuleSet getRuleSet(RName setname){
+ return (RuleSet) rulesets.get(setname);
+ }
+
+
+ /**
+ * We attempt to open the streamname as a resource in our jar.
+ * Then failing that, we attempt to open it as a URL.
+ * Then failing that, we attempt to open it as a file.
+ *
+ * @param streamname
+ * @return
+ */
+ public static InputStream openstream(Object object, String streamname){
+ // First try and open the stream as a resource
+ // InputStream s = System.class.getResourceAsStream(streamname);
+
+ InputStream s = object.getClass().getResourceAsStream(streamname);
+
+ if(s!=null)return s;
+
+ // If that fails, try and open it as a URL
+ try {
+ URL url = new URL(streamname);
+ URLConnection urlc = url.openConnection();
+ s = urlc.getInputStream();
+ if(s!=null)return s;
+ } catch (MalformedURLException e) {
+ } catch (Exception e){}
+
+ // If that fails, try and open it as a file.
+ try {
+ s = new FileInputStream(streamname);
+ return s;
+ } catch (FileNotFoundException e) {}
+
+ // If all these fail, return a null.
+ return null;
+
+ }
+
+
+ String propertyfile;
+
+ /**
+ * The RulesDirectory manages the various RuleSets and the versions of
+ * RuleSets. We need to do a good bit of work to make all of this
+ * managable. For right now, I am loading the property list from the
+ * path provided this class. It first attempts to use this path as a
+ * jar resource, then an URL, then a file.
+ *
+ * The systemPath is assumed to be the name of a directory, either with
+ * or without a ending '/' or '\'.
+ *
+ * @param propertyfile
+ */
+ public RulesDirectory(String systemPath, String propertyfile) {
+ if(systemPath.endsWith("/")||systemPath.endsWith("\\")){
+ // If it has an ending slash, chop it off.
+ systemPath = systemPath.substring(0,systemPath.length()-1);
+ }
+ if(propertyfile.startsWith("/")||propertyfile.startsWith("\\")){
+ // If the propertyfile has a leading slash, chop that off.
+ propertyfile = propertyfile.substring(1);
+ }
+ this.propertyfile = propertyfile;
+ this.systemPath = systemPath.trim();
+
+ InputStream s = openstream(this,systemPath +"/"+ propertyfile);
+ loadRulesDirectory(s);
+ }
+
+ public RulesDirectory(String systemPath, InputStream s) {
+ if(systemPath.endsWith("/")||systemPath.endsWith("\\")){
+ systemPath = systemPath+"/";
+ }
+ this.systemPath = systemPath.trim();
+ propertyfile = s.toString();
+
+ loadRulesDirectory(s);
+ }
+
+ public void loadRulesDirectory(InputStream s){
+ LoadDirectory parser = new LoadDirectory(this);
+
+ if(s==null){
+ throw new RuntimeException("Could not find the file/inputstream :"+propertyfile);
+ }
+ try {
+ GenericXMLParser.load(s,parser);
+ } catch (Exception e) {
+ throw new RuntimeException("Error parsing property file/inputstream: "+propertyfile+"\n"+e);
+ }
+ loaded = true;
+ }
+
+ static class LoadDirectory implements IGenericXMLParser {
+
+ final RulesDirectory rd;
+ LoadDirectory(RulesDirectory _rd){
+ rd=_rd;
+ rd.rulesets = new HashMap<RName,RuleSet>();
+ }
+ RuleSet currentset=null;
+
+ public void beginTag(String[] tagstk, int tagstkptr, String tag, HashMap attribs) throws IOException, Exception {
+ if (tag.equals("RuleSet")){
+ currentset = new RuleSet(rd);
+ currentset.setName((String) attribs.get("name"));
+ if(currentset.name==null){
+ throw new RuntimeException("Missing name in RuleSet");
+ }
+ rd.rulesets.put(currentset.name, currentset);
+ }
+ }
+
+ public void endTag(String[] tagstk, int tagstkptr, String tag, String body, HashMap attribs) throws Exception, IOException {
+ if(tag.equals("RuleSetResourcePath")){
+ currentset.setResourcepath(body.trim());
+ }else if (tag.equals("RuleSetFilePath")){
+ currentset.setFilepath(body.trim());
+ }else if (tag.equals("WorkingDirectory")){
+ currentset.setWorkingdirectory(body.trim());
+ }else if (tag.equals("Entities")){
+ currentset.edd_names.add((String) attribs.get("name"));
+ }else if (tag.equals("Decisiontables")){
+ currentset.dt_names.add((String) attribs.get("name"));
+ }else if (tag.equals("Map")){
+ currentset.map_paths.add((String) attribs.get("name"));
+ }else if (tag.equals("DTExcelFolder")){
+ currentset.setExcel_dtfolder(body.trim());
+ }else if (tag.equals("EDDExcelFile")){
+ currentset.setExcel_edd(body.trim());
+ }
+ }
+ public boolean error(String v) throws Exception {
+ return true;
+ }
+
+ }
+
+ /**
+ * @return the rulesets
+ */
+ public HashMap getRulesets() {
+ return rulesets;
+ }
+ /**
+ * @return the filepath
+ */
+ public String getFilepath() {
+ return systemPath;
+ }
+ /**
+ * @param filepath the filepath to set
+ */
+ public void setFilepath(String filepath) {
+ this.systemPath = filepath;
+ }
+ /**
+ * @return the systemPath
+ */
+ public String getSystemPath() {
+ return systemPath;
+ }
+ /**
+ * @param systemPath the systemPath to set
+ */
+ public void setSystemPath(String systemPath) {
+ this.systemPath = systemPath;
+ }
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/trace
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+TraceNode.java
+file
+
+
+
+
+2008-08-21T15:20:10.406250Z
+496efbdd4b3523fa06d88c03d94d1d6c
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
+DecisionTableNode.java
+file
+
+
+
+
+2008-08-21T15:19:59.578125Z
+a4e50791650a25a9983591a342424d97
+2008-08-21T15:23:51.307359Z
+11276
+psnow
+\f
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.trace;
+
+import java.util.ArrayList;
+
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+
+public class DecisionTableNode implements TraceNode {
+
+ ArrayList<TraceNode> children = new ArrayList<TraceNode>();
+ TraceNode parent;
+ TraceNode previous;
+
+ public RName getAttribute() {
+ return null;
+ }
+ /**
+ * Get first child, and return null if no children.
+ */
+ public TraceNode getFirstChild() {
+ if(children.size()==0)return null;
+ return children.get(0);
+ }
+
+ public RInteger getIndex() {
+ return null;
+ }
+
+ public TraceNode getNext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getNextChange() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getParent() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getPrevious() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getPreviousChange() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setNewValues() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setOldValues() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.trace;
+
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+
+/**
+ * A trace node allows two kinds of navigation acorss changes recorded in
+ * a DTRules Trace file. One mode is a tree, and one mode is linear. In
+ * fact, all changes occur serially within a decision table thread. Yet all
+ * changes occur with in a hierarchy of Decision Table execution.
+ *
+ * The parent of all nodes is a root node. The initialization node holds the
+ * initial values (includeing data inserted into a ruleset)
+ *
+ * The changes are kept as nodes
+ */
+public interface TraceNode {
+
+ /**
+ * These are the hierarchy operators.
+ */
+
+ /** getParent() -- return the parent node, usually a decisiontable. But it
+ * could be the root node, or the initialization node.
+ * @return
+ */
+ TraceNode getParent();
+ /**
+ * Get the firstChild()
+ * @return
+ */
+ TraceNode getFirstChild();
+ /**
+ * Get the next();
+ * Returns a null if no more children;
+ * @return
+ */
+ TraceNode getNext();
+ /**
+ * Get the perivious node,
+ * @return
+ */
+ TraceNode getPrevious();
+
+ /**
+ * These are the linear access methods. All the changes are organized
+ * in a linear list.
+ */
+ /**
+ * Get the next Change Node
+ * @return
+ */
+ TraceNode getNextChange();
+ /**
+ * Get the previous Change Node
+ * @return
+ */
+ TraceNode getPreviousChange();
+
+
+ /**
+ * Change Operators
+ */
+ void setOldValues();
+ void setNewValues();
+ /**
+ * Returns the Name for the Attribute that changed (or a null if
+ * this isn't a change to an Entity).
+ */
+ RName getAttribute();
+ /**
+ * Returns the index for the Attribute that changed (or a null if
+ * this isn't a change to an Element of an Array).
+ */
+ RInteger getIndex();
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.trace;
+
+import java.util.ArrayList;
+
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+
+public class DecisionTableNode implements TraceNode {
+
+ ArrayList<TraceNode> children = new ArrayList<TraceNode>();
+ TraceNode parent;
+ TraceNode previous;
+
+ public RName getAttribute() {
+ return null;
+ }
+ /**
+ * Get first child, and return null if no children.
+ */
+ public TraceNode getFirstChild() {
+ if(children.size()==0)return null;
+ return children.get(0);
+ }
+
+ public RInteger getIndex() {
+ return null;
+ }
+
+ public TraceNode getNext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getNextChange() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getParent() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getPrevious() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public TraceNode getPreviousChange() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setNewValues() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setOldValues() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.trace;
+
+import com.dtrules.interpreter.RInteger;
+import com.dtrules.interpreter.RName;
+
+/**
+ * A trace node allows two kinds of navigation acorss changes recorded in
+ * a DTRules Trace file. One mode is a tree, and one mode is linear. In
+ * fact, all changes occur serially within a decision table thread. Yet all
+ * changes occur with in a hierarchy of Decision Table execution.
+ *
+ * The parent of all nodes is a root node. The initialization node holds the
+ * initial values (includeing data inserted into a ruleset)
+ *
+ * The changes are kept as nodes
+ */
+public interface TraceNode {
+
+ /**
+ * These are the hierarchy operators.
+ */
+
+ /** getParent() -- return the parent node, usually a decisiontable. But it
+ * could be the root node, or the initialization node.
+ * @return
+ */
+ TraceNode getParent();
+ /**
+ * Get the firstChild()
+ * @return
+ */
+ TraceNode getFirstChild();
+ /**
+ * Get the next();
+ * Returns a null if no more children;
+ * @return
+ */
+ TraceNode getNext();
+ /**
+ * Get the perivious node,
+ * @return
+ */
+ TraceNode getPrevious();
+
+ /**
+ * These are the linear access methods. All the changes are organized
+ * in a linear list.
+ */
+ /**
+ * Get the next Change Node
+ * @return
+ */
+ TraceNode getNextChange();
+ /**
+ * Get the previous Change Node
+ * @return
+ */
+ TraceNode getPreviousChange();
+
+
+ /**
+ * Change Operators
+ */
+ void setOldValues();
+ void setNewValues();
+ /**
+ * Returns the Name for the Attribute that changed (or a null if
+ * this isn't a change to an Entity).
+ */
+ RName getAttribute();
+ /**
+ * Returns the index for the Attribute that changed (or a null if
+ * this isn't a change to an Element of an Array).
+ */
+ RInteger getIndex();
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/main/java/com/dtrules/xmlparser
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+IGenericXMLParser.java
+file
+
+
+
+
+2008-05-15T17:28:01.109375Z
+3a8c322a2afcc21fae61c491466c2bc6
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+XMLPrinter.java
+file
+
+
+
+
+2008-08-24T03:01:39.593750Z
+1d559375325e5c633d0507c06e1e7a9a
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
+GenericXMLParser.flex
+file
+
+
+
+
+2008-09-04T02:55:14.921875Z
+fc013df3653276dbc2347add882f59a7
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8469
+\f
+compileGenericXMLParser.bat
+file
+
+
+
+
+2008-08-22T21:18:01.578125Z
+c9ce16f6360a585b1ef450668b387e16
+2008-08-23T21:04:03.492379Z
+11338
+psnow
+\f
+GenericXMLParser.java
+file
+
+
+
+
+2008-09-04T02:55:19.937500Z
+dbaba9d6fdfb2134ae9107104c0c6434
+2008-09-09T03:11:32.756501Z
+11667
+psnow
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+26486
+\f
+IXMLPrinter.java
+file
+
+
+
+
+2008-08-24T03:02:27.093750Z
+4e97868741257866c2ff0ebdc1ecb5ec
+2008-08-25T15:23:35.073751Z
+11348
+psnow
+\f
--- /dev/null
+package com.dtrules.xmlparser;
+import java.util.*;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.regex.Pattern;
+@SuppressWarnings({"unchecked","unused"})
+%%
+%public
+%class GenericXMLParser
+%yylexthrow Exception
+%unicode
+%line
+%column
+%int
+
+%{
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ private String sourcename = "unknown name";
+ String tagstk [] = new String[1000];
+ int tagstkptr = 0;
+ int statestk [] = new int[1000];
+ int statestkptr = 0;
+ ArrayList attribstk = new ArrayList();
+ HashMap<String,String> attribs = new HashMap<String,String>();
+ boolean printflg = true;
+ IGenericXMLParser parser = null;
+
+ String body = "";
+ String currenttag = "";
+ String Source;
+
+ public GenericXMLParser(String filename) throws FileNotFoundException {
+ this(new FileInputStream(filename));
+ sourcename = filename;
+ }
+
+ void pushTag(String tag){
+ tagstk[tagstkptr++] = tag;
+ currenttag = tag;
+ attribstk.add(attribs); // We save and restore the attribs hashmap
+ attribs = new HashMap();
+ }
+
+ String popTag(String endtag) {
+ attribs = (HashMap) attribstk.remove(attribstk.size()-1);
+ if(endtag.indexOf("</")>=0){
+ endtag=endtag.substring(2,endtag.length()-1).trim();
+ }
+ if(tagstkptr<=0){
+ System.err.print("Stack Underflow\n");
+ }
+ String tag = tagstk[--tagstkptr];
+ if(!tag.equals(endtag)){
+ System.err.print("Begin and End tags do not match:\n"+
+ "Begin tag: "+tag+"\n"+
+ "End tag: "+endtag+"\n");
+ }
+
+ if(tagstkptr<=0){
+ currenttag = "";
+ }else{
+ currenttag = tagstk[tagstkptr-1];
+ }
+
+ return tag;
+ }
+
+ public void setSource(String source){
+ this.sourcename=source;
+ }
+
+ public void setParser (IGenericXMLParser p_parser){
+ parser = p_parser;
+ }
+
+ void pushstate(int state) {
+ statestk[statestkptr++]=yystate();
+ yybegin(state);
+ }
+
+ int popstate (){
+ int newstate = statestk[--statestkptr];
+ statestk[statestkptr]=0;
+ yybegin(newstate);
+ return newstate;
+ }
+
+ void error(String v)throws Exception{
+ if(!parser.error(v)){
+ throw new Exception("Unmatched characters, parsing cannot continue at" + where());
+ }
+ }
+
+ static private Pattern xamp = Pattern.compile("&");
+ static private Pattern xlt = Pattern.compile("<");
+ static private Pattern xgt = Pattern.compile(">");
+ static private Pattern xsqu = Pattern.compile("'");
+ static private Pattern xdqu = Pattern.compile(""");
+
+ static public String unencode (String s){
+ if(s.indexOf("&")>=0){
+ s= xlt.matcher(s).replaceAll("<");
+ s= xgt.matcher(s).replaceAll(">");
+ s= xsqu.matcher(s).replaceAll("'");
+ s= xdqu.matcher(s).replaceAll("\"");
+ s= xamp.matcher(s).replaceAll("&");
+ }
+ return s;
+ }
+ static private Pattern tst = Pattern.compile("[&<>'\"]+");
+ static private Pattern amp = Pattern.compile("&");
+ static private Pattern lt = Pattern.compile("<");
+ static private Pattern gt = Pattern.compile(">");
+ static private Pattern squ = Pattern.compile("'");
+ static private Pattern dqu = Pattern.compile("\"");
+
+ static public String encode (String s) {
+ if(tst.matcher(s).find()){
+ s= amp.matcher(s).replaceAll("&");
+ s= lt.matcher(s).replaceAll("<");
+ s= gt.matcher(s).replaceAll(">");
+ s= squ.matcher(s).replaceAll("'");
+ s= dqu.matcher(s).replaceAll(""");
+ }
+ return s;
+ }
+
+
+ static public StringBuffer encode (StringBuffer sb) {
+
+ return new StringBuffer(encode(sb.toString()));
+
+ }
+
+
+ public String where() {
+ return sourcename + ":" + (yyline+1) + "." + (yycolumn+1) ;
+ }
+
+ public int getYYLine() { return yyline+1;}
+ public int getYYColumn() { return yycolumn+1;}
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * <br><br>
+ * @param file An inputStream providing the XML
+ * @param gp A parser implementing the IGenericXMLParser interface.
+ */
+ static public void load(java.io.InputStream xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * @param xmlStream
+ * @param gp
+ * @throws Exception
+ */
+ static public void load(java.io.Reader xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+
+%}
+
+Char = [a-z]|[A-Z]|"_"
+Digit = [0-9]
+namestart = {Char}
+namechar = {namestart} | "-" | "." | {Digit}
+Identifier = {namestart}{namechar}*(":"{namestart}{namechar}*)?
+EOL = \r|\n|\r\n
+ws = {EOL}|[ \t\f]
+string1 = "'"[^']*"'"
+string2 = "\""[^\"]*"\""
+string = {string1}|{string2}
+body = ({ws}|[^<>])*
+any = Char|ws|Digit|">"|"<"|"&"|.
+comment = "<!--"~"-->"
+
+%xstate Attributes
+%xstate Tag
+%xstate EndTag
+%xstate NestedTag
+%%
+
+<YYINITIAL> {
+
+ "<" {pushstate(Tag); }
+ "<?"{body}"?>" {}
+ {ws} { }
+ {comment} {}
+ {any} { error(yytext()); }
+
+}
+
+<Attributes> {
+ {Identifier}{ws}*"="{ws}*{string} {
+ String text = yytext();
+ String key = text.substring (0,text.indexOf('=')).trim();
+ String value = text.substring (text.indexOf('=')+1).trim();
+ char delimiter = value.charAt(0);
+ value = value.substring(1,value.lastIndexOf(delimiter));
+
+ attribs.put(key,unencode(value));
+ }
+
+ "/"?">" {
+ yypushback(1);
+ if(yytext().indexOf("/")>=0) yypushback(1);
+ popstate();
+ }
+
+ {ws} { }
+ {any} { error(yytext()); }
+}
+
+<Tag> {
+ {Identifier} {
+ pushTag(yytext());
+ body="";
+ pushstate(Attributes);
+ }
+
+ ">" {
+ parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ popstate();
+ pushstate(EndTag);
+ }
+
+ "/>" {
+ parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(currenttag);
+ popstate();
+ return 1;
+ }
+
+ {comment} {}
+ {ws} { }
+ {any} { error(yytext()); }
+
+}
+
+<EndTag> {
+
+ {body} {
+ String text = yytext();
+ body += text;
+ }
+
+ "</"{Identifier}{ws}*">" {
+ String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,unencode(body),attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ }
+
+ "<" {
+ popstate();
+ pushstate(NestedTag);
+ pushstate(Tag);
+ }
+
+ {comment} {}
+ {any} { body += yytext(); error(yytext()); }
+}
+
+<NestedTag> {
+ "<" {pushstate(Tag); }
+
+ "</"{Identifier}{ws}*">" {
+ String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ return 1;
+ }
+
+ {ws} {}
+ {comment} {}
+ {any} { error(yytext()); }
+
+}
+
--- /dev/null
+/* The following code was generated by JFlex 1.4.1 on 9/3/08 9:55 PM */
+
+package com.dtrules.xmlparser;
+import java.util.*;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.regex.Pattern;
+@SuppressWarnings({"unchecked","unused"})
+
+/**
+ * This class is a scanner generated by
+ * <a href="http://www.jflex.de/">JFlex</a> 1.4.1
+ * on 9/3/08 9:55 PM from the specification file
+ * <tt>C:/eb/eb_dev2/RulesEngine/DTRules/src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex</tt>
+ */
+public class GenericXMLParser {
+
+ /** This character denotes the end of file */
+ public static final int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ public static final int EndTag = 3;
+ public static final int NestedTag = 4;
+ public static final int YYINITIAL = 0;
+ public static final int Tag = 2;
+ public static final int Attributes = 1;
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final String ZZ_CMAP_PACKED =
+ "\11\0\1\7\1\6\1\0\1\7\1\5\22\0\1\7\1\26\1\11"+
+ "\3\0\1\0\1\10\5\0\1\3\1\2\1\31\12\2\1\4\1\0"+
+ "\1\12\1\30\1\25\1\27\1\0\2\1\1\13\1\21\26\1\4\0"+
+ "\1\1\1\0\1\15\5\1\1\23\1\14\1\22\10\1\1\16\1\20"+
+ "\1\24\2\1\1\17\3\1\uff85\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int [] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 =
+ "\3\0\1\1\1\0\1\2\2\3\1\4\7\2\1\5"+
+ "\1\2\1\6\1\2\1\7\1\2\1\1\1\10\1\11"+
+ "\1\4\13\0\1\12\13\0\1\6\4\0\1\13\3\0"+
+ "\1\14\2\0\1\15\4\0";
+
+ private static int [] zzUnpackAction() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAction(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+ private static final String ZZ_ROWMAP_PACKED_0 =
+ "\0\0\0\32\0\64\0\116\0\150\0\202\0\234\0\202"+
+ "\0\266\0\320\0\352\0\u0104\0\u011e\0\u0138\0\u0152\0\u016c"+
+ "\0\202\0\u0186\0\u01a0\0\u01ba\0\202\0\u01d4\0\u01ee\0\u0208"+
+ "\0\202\0\u0222\0\u023c\0\u0256\0\u0270\0\u028a\0\u011e\0\u02a4"+
+ "\0\u02be\0\u02d8\0\u02f2\0\u030c\0\u0326\0\202\0\u0340\0\u035a"+
+ "\0\u0374\0\u038e\0\u03a8\0\u03c2\0\u03dc\0\u03f6\0\u0410\0\u042a"+
+ "\0\u0444\0\u045e\0\u0478\0\u0492\0\u04ac\0\u04c6\0\202\0\u04e0"+
+ "\0\u04fa\0\u0514\0\202\0\u052e\0\u0548\0\202\0\u0562\0\u057c"+
+ "\0\u0596\0\u05b0";
+
+ private static int [] zzUnpackRowMap() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int high = packed.charAt(i++) << 16;
+ result[j++] = high | packed.charAt(i++);
+ }
+ return j;
+ }
+
+ /**
+ * The transition table of the DFA
+ */
+ private static final int [] ZZ_TRANS = zzUnpackTrans();
+
+ private static final String ZZ_TRANS_PACKED_0 =
+ "\5\6\1\7\2\10\2\6\1\11\1\12\3\6\1\13"+
+ "\1\6\1\14\11\6\1\15\3\6\1\7\2\10\3\6"+
+ "\1\16\3\15\1\17\1\15\1\20\3\15\1\21\3\6"+
+ "\1\22\1\6\1\23\3\6\1\7\2\10\2\6\1\24"+
+ "\12\23\1\25\3\6\1\26\12\27\1\30\12\27\1\31"+
+ "\4\27\5\6\1\7\2\10\2\6\1\32\1\12\3\6"+
+ "\1\13\1\6\1\14\10\6\40\0\1\10\51\0\1\33"+
+ "\1\34\16\0\1\35\35\0\1\6\33\0\1\36\10\0"+
+ "\3\37\1\40\3\41\3\0\12\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\1\37\1\43\10\37\3\0"+
+ "\1\42\2\0\3\37\1\40\3\41\3\0\5\37\1\15"+
+ "\4\37\3\0\1\42\2\0\3\37\1\40\3\41\3\0"+
+ "\7\37\1\44\2\37\3\0\1\42\26\0\1\21\5\0"+
+ "\3\23\1\45\6\0\12\23\33\0\1\33\30\0\1\46"+
+ "\4\0\12\27\1\0\12\27\1\0\4\27\26\0\1\33"+
+ "\2\0\1\47\26\0\1\33\2\0\1\50\3\0\1\51"+
+ "\26\0\12\34\1\0\12\34\1\0\1\34\1\52\2\34"+
+ "\15\0\1\53\37\0\1\54\7\0\1\55\11\0\12\55"+
+ "\12\0\3\41\20\0\1\42\6\0\3\42\1\56\1\57"+
+ "\21\0\3\37\1\40\3\41\3\0\2\37\1\60\7\37"+
+ "\3\0\1\42\2\0\3\37\1\40\3\41\3\0\10\37"+
+ "\1\61\1\37\3\0\1\42\2\0\1\62\11\0\12\62"+
+ "\6\0\1\63\11\0\12\63\6\0\1\64\11\0\12\64"+
+ "\10\0\1\65\26\0\12\34\1\0\12\34\1\10\1\34"+
+ "\1\52\2\34\16\0\1\6\35\0\1\66\10\0\3\55"+
+ "\1\0\3\41\3\0\12\55\3\0\1\42\1\0\10\56"+
+ "\1\67\21\56\11\57\1\67\20\57\1\0\3\37\1\40"+
+ "\3\41\3\0\3\37\1\15\6\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\7\37\1\70\2\37\3\0"+
+ "\1\42\2\0\3\62\7\0\12\62\6\0\3\63\1\71"+
+ "\3\72\3\0\12\63\1\73\5\0\3\64\1\74\3\75"+
+ "\3\0\12\64\1\76\4\0\3\65\1\77\26\65\24\0"+
+ "\1\6\6\0\3\37\1\40\3\41\3\0\11\37\1\15"+
+ "\3\0\1\42\2\0\1\100\11\0\12\100\12\0\3\72"+
+ "\15\0\1\73\5\0\1\101\11\0\12\101\12\0\3\75"+
+ "\15\0\1\76\4\0\3\65\1\102\26\65\1\0\3\100"+
+ "\1\0\3\72\3\0\12\100\1\73\5\0\3\101\1\0"+
+ "\3\75\3\0\12\101\1\76\4\0\3\65\1\102\21\65"+
+ "\1\10\4\65";
+
+ private static int [] zzUnpackTrans() {
+ int [] result = new int[1482];
+ int offset = 0;
+ offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackTrans(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+
+ /* error messages for the codes above */
+ private static final String ZZ_ERROR_MSG[] = {
+ "Unkown internal scanner error",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
+ */
+ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 =
+ "\3\0\1\1\1\0\1\11\1\1\1\11\10\1\1\11"+
+ "\3\1\1\11\3\1\1\11\1\1\13\0\1\11\13\0"+
+ "\1\1\4\0\1\11\3\0\1\11\2\0\1\11\4\0";
+
+ private static int [] zzUnpackAttribute() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the input device */
+ private java.io.Reader zzReader;
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int zzPushbackPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int zzEndRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ private int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ private int yycolumn;
+
+ /**
+ * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=> the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /* user code: */
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ private String sourcename = "unknown name";
+ String tagstk [] = new String[1000];
+ int tagstkptr = 0;
+ int statestk [] = new int[1000];
+ int statestkptr = 0;
+ ArrayList attribstk = new ArrayList();
+ HashMap<String,String> attribs = new HashMap<String,String>();
+ boolean printflg = true;
+ IGenericXMLParser parser = null;
+
+ String body = "";
+ String currenttag = "";
+ String Source;
+
+ public GenericXMLParser(String filename) throws FileNotFoundException {
+ this(new FileInputStream(filename));
+ sourcename = filename;
+ }
+
+ void pushTag(String tag){
+ tagstk[tagstkptr++] = tag;
+ currenttag = tag;
+ attribstk.add(attribs); // We save and restore the attribs hashmap
+ attribs = new HashMap();
+ }
+
+ String popTag(String endtag) {
+ attribs = (HashMap) attribstk.remove(attribstk.size()-1);
+ if(endtag.indexOf("</")>=0){
+ endtag=endtag.substring(2,endtag.length()-1).trim();
+ }
+ if(tagstkptr<=0){
+ System.err.print("Stack Underflow\n");
+ }
+ String tag = tagstk[--tagstkptr];
+ if(!tag.equals(endtag)){
+ System.err.print("Begin and End tags do not match:\n"+
+ "Begin tag: "+tag+"\n"+
+ "End tag: "+endtag+"\n");
+ }
+
+ if(tagstkptr<=0){
+ currenttag = "";
+ }else{
+ currenttag = tagstk[tagstkptr-1];
+ }
+
+ return tag;
+ }
+
+ public void setSource(String source){
+ this.sourcename=source;
+ }
+
+ public void setParser (IGenericXMLParser p_parser){
+ parser = p_parser;
+ }
+
+ void pushstate(int state) {
+ statestk[statestkptr++]=yystate();
+ yybegin(state);
+ }
+
+ int popstate (){
+ int newstate = statestk[--statestkptr];
+ statestk[statestkptr]=0;
+ yybegin(newstate);
+ return newstate;
+ }
+
+ void error(String v)throws Exception{
+ if(!parser.error(v)){
+ throw new Exception("Unmatched characters, parsing cannot continue at" + where());
+ }
+ }
+
+ static private Pattern xamp = Pattern.compile("&");
+ static private Pattern xlt = Pattern.compile("<");
+ static private Pattern xgt = Pattern.compile(">");
+ static private Pattern xsqu = Pattern.compile("'");
+ static private Pattern xdqu = Pattern.compile(""");
+
+ static public String unencode (String s){
+ if(s.indexOf("&")>=0){
+ s= xlt.matcher(s).replaceAll("<");
+ s= xgt.matcher(s).replaceAll(">");
+ s= xsqu.matcher(s).replaceAll("'");
+ s= xdqu.matcher(s).replaceAll("\"");
+ s= xamp.matcher(s).replaceAll("&");
+ }
+ return s;
+ }
+ static private Pattern tst = Pattern.compile("[&<>'\"]+");
+ static private Pattern amp = Pattern.compile("&");
+ static private Pattern lt = Pattern.compile("<");
+ static private Pattern gt = Pattern.compile(">");
+ static private Pattern squ = Pattern.compile("'");
+ static private Pattern dqu = Pattern.compile("\"");
+
+ static public String encode (String s) {
+ if(tst.matcher(s).find()){
+ s= amp.matcher(s).replaceAll("&");
+ s= lt.matcher(s).replaceAll("<");
+ s= gt.matcher(s).replaceAll(">");
+ s= squ.matcher(s).replaceAll("'");
+ s= dqu.matcher(s).replaceAll(""");
+ }
+ return s;
+ }
+
+
+ static public StringBuffer encode (StringBuffer sb) {
+
+ return new StringBuffer(encode(sb.toString()));
+
+ }
+
+
+ public String where() {
+ return sourcename + ":" + (yyline+1) + "." + (yycolumn+1) ;
+ }
+
+ public int getYYLine() { return yyline+1;}
+ public int getYYColumn() { return yycolumn+1;}
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * <br><br>
+ * @param file An inputStream providing the XML
+ * @param gp A parser implementing the IGenericXMLParser interface.
+ */
+ static public void load(java.io.InputStream xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * @param xmlStream
+ * @param gp
+ * @throws Exception
+ */
+ static public void load(java.io.Reader xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+
+
+
+ /**
+ * Creates a new scanner
+ * There is also a java.io.InputStream version of this constructor.
+ *
+ * @param in the java.io.Reader to read input from.
+ */
+ public GenericXMLParser(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+ /**
+ * Creates a new scanner.
+ * There is also java.io.Reader version of this constructor.
+ *
+ * @param in the java.io.Inputstream to read input from.
+ */
+ public GenericXMLParser(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char [] zzUnpackCMap(String packed) {
+ char [] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 90) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do map[j++] = value; while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return <code>false</code>, iff there was new input.
+ *
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ private boolean zzRefill() throws java.io.IOException {
+
+ /* first: make room (if you can) */
+ if (zzStartRead > 0) {
+ System.arraycopy(zzBuffer, zzStartRead,
+ zzBuffer, 0,
+ zzEndRead-zzStartRead);
+
+ /* translate stored positions */
+ zzEndRead-= zzStartRead;
+ zzCurrentPos-= zzStartRead;
+ zzMarkedPos-= zzStartRead;
+ zzPushbackPos-= zzStartRead;
+ zzStartRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (zzCurrentPos >= zzBuffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[zzCurrentPos*2];
+ System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
+ zzBuffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = zzReader.read(zzBuffer, zzEndRead,
+ zzBuffer.length-zzEndRead);
+
+ if (numRead < 0) {
+ return true;
+ }
+ else {
+ zzEndRead+= numRead;
+ return false;
+ }
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ public final void yyclose() throws java.io.IOException {
+ zzAtEOF = true; /* indicate end of file */
+ zzEndRead = zzStartRead; /* invalidate buffer */
+
+ if (zzReader != null)
+ zzReader.close();
+ }
+
+
+ /**
+ * Resets the scanner to read from a new input stream.
+ * Does not close the old reader.
+ *
+ * All internal variables are reset, the old input stream
+ * <b>cannot</b> be reused (internal buffer is discarded and lost).
+ * Lexical state is set to <tt>ZZ_INITIAL</tt>.
+ *
+ * @param reader the new input stream
+ */
+ public final void yyreset(java.io.Reader reader) {
+ zzReader = reader;
+ zzAtBOL = true;
+ zzAtEOF = false;
+ zzEndRead = zzStartRead = 0;
+ zzCurrentPos = zzMarkedPos = zzPushbackPos = 0;
+ yyline = yychar = yycolumn = 0;
+ zzLexicalState = YYINITIAL;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ public final int yystate() {
+ return zzLexicalState;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState the new lexical state
+ */
+ public final void yybegin(int newState) {
+ zzLexicalState = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ public final String yytext() {
+ return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
+ }
+
+
+ /**
+ * Returns the character at position <tt>pos</tt> from the
+ * matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos the position of the character to fetch.
+ * A value from 0 to yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ public final char yycharat(int pos) {
+ return zzBuffer[zzStartRead+pos];
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ public final int yylength() {
+ return zzMarkedPos-zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ public void yypushback(int number) {
+ if ( number > yylength() )
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched,
+ * the end of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ public int yylex() throws java.io.IOException, Exception {
+ int zzInput;
+ int zzAction;
+
+ // cached fields:
+ int zzCurrentPosL;
+ int zzMarkedPosL;
+ int zzEndReadL = zzEndRead;
+ char [] zzBufferL = zzBuffer;
+ char [] zzCMapL = ZZ_CMAP;
+
+ int [] zzTransL = ZZ_TRANS;
+ int [] zzRowMapL = ZZ_ROWMAP;
+ int [] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ boolean zzR = false;
+ for (zzCurrentPosL = zzStartRead; zzCurrentPosL < zzMarkedPosL;
+ zzCurrentPosL++) {
+ switch (zzBufferL[zzCurrentPosL]) {
+ case '\u000B':
+ case '\u000C':
+ case '\u0085':
+ case '\u2028':
+ case '\u2029':
+ yyline++;
+ yycolumn = 0;
+ zzR = false;
+ break;
+ case '\r':
+ yyline++;
+ yycolumn = 0;
+ zzR = true;
+ break;
+ case '\n':
+ if (zzR)
+ zzR = false;
+ else {
+ yyline++;
+ yycolumn = 0;
+ }
+ break;
+ default:
+ zzR = false;
+ yycolumn++;
+ }
+ }
+
+ if (zzR) {
+ // peek one character ahead if it is \n (if we have counted one line too much)
+ boolean zzPeek;
+ if (zzMarkedPosL < zzEndReadL)
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ else if (zzAtEOF)
+ zzPeek = false;
+ else {
+ boolean eof = zzRefill();
+ zzEndReadL = zzEndRead;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ if (eof)
+ zzPeek = false;
+ else
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ }
+ if (zzPeek) yyline--;
+ }
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = zzLexicalState;
+
+
+ zzForAction: {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL)
+ zzInput = zzBufferL[zzCurrentPosL++];
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ zzInput = zzBufferL[zzCurrentPosL++];
+ }
+ }
+ int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
+ if (zzNext == -1) break zzForAction;
+ zzState = zzNext;
+
+ int zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ( (zzAttributes & 8) == 8 ) break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 11:
+ { String text = yytext();
+ String key = text.substring (0,text.indexOf('=')).trim();
+ String value = text.substring (text.indexOf('=')+1).trim();
+ char delimiter = value.charAt(0);
+ value = value.substring(1,value.lastIndexOf(delimiter));
+
+ attribs.put(key,unencode(value));
+ }
+ case 14: break;
+ case 9:
+ { body += yytext(); error(yytext());
+ }
+ case 15: break;
+ case 6:
+ { pushTag(yytext());
+ body="";
+ pushstate(Attributes);
+ }
+ case 16: break;
+ case 5:
+ { yypushback(1);
+ if(yytext().indexOf("/")>=0) yypushback(1);
+ popstate();
+ }
+ case 17: break;
+ case 12:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,unencode(body),attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ }
+ case 18: break;
+ case 8:
+ { popstate();
+ pushstate(NestedTag);
+ pushstate(Tag);
+ }
+ case 19: break;
+ case 7:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ popstate();
+ pushstate(EndTag);
+ }
+ case 20: break;
+ case 13:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ return 1;
+ }
+ case 21: break;
+ case 10:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(currenttag);
+ popstate();
+ return 1;
+ }
+ case 22: break;
+ case 1:
+ { String text = yytext();
+ body += text;
+ }
+ case 23: break;
+ case 2:
+ { error(yytext());
+ }
+ case 24: break;
+ case 4:
+ { pushstate(Tag);
+ }
+ case 25: break;
+ case 3:
+ {
+ }
+ case 26: break;
+ default:
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ return YYEOF;
+ }
+ else {
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.xmlparser;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * This is a simple interface for handling parsing events
+ * from the generic parser. At this time, only two events
+ * are generated, the beginTag and the endTag events. The
+ * endTag() provides the body, if present.
+ * Creation date: (9/15/2003 8:35:17 AM)
+ * @author: Paul Snow, MTBJ, Inc.
+ */
+public interface IGenericXMLParser {
+
+ /**
+ * The beginTag method is called when the parser detects the
+ * each begin tag in the XML file being parsed. When one uses
+ * a SAX parser, the class implementing the interface is responsible
+ * for keeping up with the context of the tags as they are
+ * encountered and closed. The GenericXMLParser provides a
+ * stack of all the tags currently open when the begin tag
+ * is encountered. This is the actual stack maintained by the
+ * GenericXMLParser, which is maintained as an array of tags.
+ * The tagstkptr provides an index into this array. <br><br>
+ * The attributes associated with the tag are provided as a
+ * hashmap of key/Value pairs. <br><br>
+ *
+ * @param tagstk A stack of tags active at the time the tag was encountered.
+ * @param tagstkptr A pointer into the tag stack to the top of stack.
+ * @param tag The tag encountered.
+ * @param attribs A hash map of attributes as a set of key/Value pairs.
+ * @throws IOException If an error occurs while parsing the XML, this exception will be thrown.
+ * @throws Exception If the tags are not matched, or an unexpected character is encountered, an
+ * exception will be thrown.
+ */
+ public void beginTag(
+ String tagstk[],
+ int tagstkptr,
+ String tag,
+ HashMap<String, String> attribs)
+ throws IOException, Exception;
+
+ /**
+ * The endTag method is called when the parser detects the
+ * each end tag in the XML file being parsed. When one uses
+ * a SAX parser, the class implementing the interface is responsible
+ * for keeping up with the context of the tags as they are
+ * encountered and closed. The GenericXMLParser provides a
+ * stack of all the tags currently open when the end tag
+ * is encountered. The GenericXMLParser also provides the
+ * attributes of the begin tag to the end tag as well.
+ * <br><br>
+ *
+ * @param tagstk A stack of tags active at the time the tag was encountered.
+ * @param tagstkptr A pointer into the tag stack to the top of stack.
+ * @param tag The tag encountered.
+ * @param body the body (if any) of the data between the begin and end tags.
+ * @param attribs A hash map of attributes as a set of key/Value pairs.
+ * @throws IOException If an error occurs while parsing the XML, this exception will be thrown.
+ * @throws Exception If the tags are not matched, or an unexpected character is encountered, an
+ * exception will be thrown.
+ **/
+ public void endTag(
+ java.lang.String[] tagstk,
+ int tagstkptr,
+ String tag,
+ String body,
+ HashMap<String,String> attribs)
+ throws Exception, IOException;
+
+ /**
+ * When an error is encountered by the parser, the error method
+ * is called on the class implementing the IGenericXMLParser
+ * interface. This method returns true if parsing should continue.
+ * @param v This is the error string from the GenericXMLParser
+ */
+ public boolean error(String v)
+ throws Exception; // Returns true if parsing should continue.
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.xmlparser;
+
+public interface IXMLPrinter {
+
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth();
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i);
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ public abstract void opentag(String tag);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ */
+ public abstract void opentag(String tag, String name1, Object value1);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8, String name9, Object value9);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8, String name9, Object value9, String name10,Object value10);
+ /**
+ * Closes the currently open tag. Assumes no body text. Throws a
+ * runtime exception if no open tag exists.
+ */
+ public abstract void closetag();
+
+ /**
+ * Print data within a data tag. The text is encoded.
+ * @param text
+ */
+ public abstract void printdata(Object bodyvalue);
+
+ /**
+ * Print data within a given tag.
+ */
+ public abstract void printdata(String tag, Object bodyvalue);
+
+ /**
+ * Print the tag, one attribute, and the body.
+ * @param tag
+ * @param name1
+ * @param value
+ * @param body
+ */
+ public abstract void printdata(String tag, String name1, Object value, Object body);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ Object bodyvalue);
+ /**
+ * Closes all open tags, close the file.
+ *
+ */
+ public abstract void close();
+
+ /**
+ * Just a helper to print an error during the generation of an XML file
+ * @param errorMsg The error message to be printed. Put into an <error> tag in the XML.
+ */
+ public abstract void print_error(String errorMsg);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.xmlparser;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.interpreter.RTime;
+
+/**
+ * A simple class for the support of printing XML files. Start and end tags
+ * are tracked and printed. An enclosing tag is printed. Strings are encoded
+ * automatically. Tags are specified by their name, i.e. "Document" and not
+ * using any XML syntax, i.e. "<Document>".
+ *
+ * @author paul snow
+ * Jul 9, 2007
+ *
+ */
+public class XMLPrinter implements IXMLPrinter {
+ ArrayList<String> tagStack = new ArrayList<String>();
+ final PrintStream out;
+ boolean newline = true;
+ boolean intextbody = false;
+ boolean intagbody = false;
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth() {
+ return tagStack.size();
+ }
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i){
+ if(i<0 || i>=tagStack.size())return null;
+ return tagStack.get(i);
+ }
+
+ /**
+ * This function puts the output on a newline, but not if we
+ * are already on a newline.
+ */
+ private void newline(){
+ if(!newline)out.println();
+ newline = true;
+ }
+ /**
+ * A helper function just to print text, and sets the state of the
+ * newline function. Note that we are never going to print a newline
+ * on a non-XML syntax boundry.
+ * @param text
+ */
+ private void print(String text){
+ out.print(text);
+ newline = false;
+ }
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ private void halfopentag(String tag){
+ if(intextbody)throw new RuntimeException("Can't open a tag within a data body");
+ newline();
+ int indent = tagStack.size();
+ for(int i=0;i<indent;i++)print(" ");
+ print("<");
+ print(tag);
+ tagStack.add(tag);
+ intagbody = false; // Just don't know at this point how this tag will be used.
+ intextbody = false;
+ }
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ public void opentag(String tag){
+ halfopentag(tag);
+ print(">");
+ }
+ /**
+ * Prints an attribute. The value is encoded.
+ */
+ private void printAttribute(String name, Object value){
+ name = name.replaceAll(" ", "_");
+ print(" ");
+ print(name);
+ print("='");
+ print(GenericXMLParser.encode(value.toString()));
+ print("'");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ */
+ public void opentag(String tag, String name1, Object value1){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ print(">");
+ }
+ /**
+ * Open a tag with a given set of attributes
+ */
+ public void opentag(String tag, HashMap<String,Object> attribs){
+ halfopentag(tag);
+ for(String key : attribs.keySet()){
+ Object o = attribs.get(key);
+ if(o!=null){
+ printAttribute(key, o);
+ }else{
+ printAttribute(key,"");
+ }
+ }
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ print(">");
+ }
+
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ printAttribute(name9, value9);
+ print(">");
+ }
+
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9,
+ String name10,Object value10
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ printAttribute(name9, value9);
+ printAttribute(name10,value10);
+ print(">");
+ }
+
+
+ /**
+ * Closes the currently open tag. Assumes no body text. Throws a
+ * runtime exception if no open tag exists.
+ */
+ public void closetag(){
+ int lastIndex = tagStack.size()-1;
+ if(!intextbody){
+ newline();
+ for(int i=0;i<lastIndex;i++)print(" ");
+ }
+ if(tagStack.size()<=0){
+ throw new RuntimeException("No Enclosing Tag to close");
+ }
+ print("</");
+ print(tagStack.get(lastIndex));
+ print(">");
+ newline();
+ tagStack.remove(lastIndex);
+ intextbody = false;
+ intagbody = true;
+ }
+ /**
+ * Print data within a data tag. The text is encoded.
+ * @param text
+ */
+ public void printdata(Object bodyvalue){
+ if(intagbody){
+ throw new RuntimeException("You can't mix data and tags");
+ }
+ if(bodyvalue != null){
+ if(bodyvalue instanceof Date) {
+ bodyvalue = RTime.getRTime((Date)bodyvalue);
+ }
+ String v = GenericXMLParser.encode(bodyvalue.toString());
+ out.print(v);
+ }
+ intextbody = true;
+ }
+
+ /**
+ * Print data within a given tag.
+ */
+ public void printdata(String tag, Object bodyvalue){
+ opentag(tag);
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Open a tag with a given set of attributes
+ */
+ public void printdata(String tag, HashMap<String,Object> attribs, Object bodyvalue){
+ halfopentag(tag);
+ for(String key : attribs.keySet()){
+ String v = GenericXMLParser.encode(attribs.get(key).toString());
+ printAttribute(key, v);
+ }
+ print(">");
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param body
+ */
+ public void printdata(String tag, String name1, Object value1,String name2, Object value2, Object bodyvalue){
+ opentag(tag,name1,value1,name2,value2);
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ Object bodyvalue){
+ opentag(tag,name1,value1,name2,value2,name3,value3);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ Object bodyvalue){
+ opentag(tag,
+ name1,value1,
+ name2,value2,
+ name3,value3,
+ name4,value4
+ );
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ * @param name5
+ * @param value5
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ Object bodyvalue){
+ opentag(tag,
+ name1,value1,
+ name2,value2,
+ name3,value3,
+ name4,value4,
+ name5,value5
+ );
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, no
+ * @param tag
+ * @param name1
+ * @param value
+ * @param body
+ */
+ public void printdata(String tag, String name1, Object value, Object bodyvalue){
+ opentag(tag,name1,value);
+ printdata(bodyvalue);
+ closetag();
+ }
+ public XMLPrinter(OutputStream stream ){
+ out = new PrintStream(stream);
+ }
+ /**
+ * Opens an output stream, and puts out the surrounding root tag.
+ * @param tag The surrounding tag. No XML syntax should be specified.
+ * @param stream
+ */
+ public XMLPrinter(String tag, OutputStream stream){
+ out = new PrintStream(stream);
+ opentag(tag);
+ }
+
+ /**
+ * Closes all open tags, close the file.
+ *
+ */
+ public void close(){
+ for(int i = tagStack.size()-1; i>=0;i--){
+ closetag();
+ }
+ out.close();
+ }
+
+ /**
+ * Just a helper to print an error during the generation of an XML file
+ * @param errorMsg The error message to be printed. Put into an <error> tag in the XML.
+ */
+ public void print_error(String errorMsg){
+ if(intextbody)closetag();
+ opentag("error");
+ print(GenericXMLParser.encode(errorMsg));
+ closetag();
+ }
+
+}
--- /dev/null
+dir
+set pdir=C:\eb\eb_dev2\RulesEngine\DTRules\src\main\java\com\dtrules
+set pdir2=C:\jflex-1.4.1
+set xmldir=%pdir%\xmlparser
+java -classpath %pdir2%\lib\JFlex.jar JFlex.Main -d %xmldir% %xmldir%\GenericXMLParser.flex
+pause
\ No newline at end of file
--- /dev/null
+package com.dtrules.xmlparser;
+import java.util.*;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.regex.Pattern;
+@SuppressWarnings({"unchecked","unused"})
+%%
+%public
+%class GenericXMLParser
+%yylexthrow Exception
+%unicode
+%line
+%column
+%int
+
+%{
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ private String sourcename = "unknown name";
+ String tagstk [] = new String[1000];
+ int tagstkptr = 0;
+ int statestk [] = new int[1000];
+ int statestkptr = 0;
+ ArrayList attribstk = new ArrayList();
+ HashMap<String,String> attribs = new HashMap<String,String>();
+ boolean printflg = true;
+ IGenericXMLParser parser = null;
+
+ String body = "";
+ String currenttag = "";
+ String Source;
+
+ public GenericXMLParser(String filename) throws FileNotFoundException {
+ this(new FileInputStream(filename));
+ sourcename = filename;
+ }
+
+ void pushTag(String tag){
+ tagstk[tagstkptr++] = tag;
+ currenttag = tag;
+ attribstk.add(attribs); // We save and restore the attribs hashmap
+ attribs = new HashMap();
+ }
+
+ String popTag(String endtag) {
+ attribs = (HashMap) attribstk.remove(attribstk.size()-1);
+ if(endtag.indexOf("</")>=0){
+ endtag=endtag.substring(2,endtag.length()-1).trim();
+ }
+ if(tagstkptr<=0){
+ System.err.print("Stack Underflow\n");
+ }
+ String tag = tagstk[--tagstkptr];
+ if(!tag.equals(endtag)){
+ System.err.print("Begin and End tags do not match:\n"+
+ "Begin tag: "+tag+"\n"+
+ "End tag: "+endtag+"\n");
+ }
+
+ if(tagstkptr<=0){
+ currenttag = "";
+ }else{
+ currenttag = tagstk[tagstkptr-1];
+ }
+
+ return tag;
+ }
+
+ public void setSource(String source){
+ this.sourcename=source;
+ }
+
+ public void setParser (IGenericXMLParser p_parser){
+ parser = p_parser;
+ }
+
+ void pushstate(int state) {
+ statestk[statestkptr++]=yystate();
+ yybegin(state);
+ }
+
+ int popstate (){
+ int newstate = statestk[--statestkptr];
+ statestk[statestkptr]=0;
+ yybegin(newstate);
+ return newstate;
+ }
+
+ void error(String v)throws Exception{
+ if(!parser.error(v)){
+ throw new Exception("Unmatched characters, parsing cannot continue at" + where());
+ }
+ }
+
+ static private Pattern xamp = Pattern.compile("&");
+ static private Pattern xlt = Pattern.compile("<");
+ static private Pattern xgt = Pattern.compile(">");
+ static private Pattern xsqu = Pattern.compile("'");
+ static private Pattern xdqu = Pattern.compile(""");
+
+ static public String unencode (String s){
+ if(s.indexOf("&")>=0){
+ s= xlt.matcher(s).replaceAll("<");
+ s= xgt.matcher(s).replaceAll(">");
+ s= xsqu.matcher(s).replaceAll("'");
+ s= xdqu.matcher(s).replaceAll("\"");
+ s= xamp.matcher(s).replaceAll("&");
+ }
+ return s;
+ }
+ static private Pattern tst = Pattern.compile("[&<>'\"]+");
+ static private Pattern amp = Pattern.compile("&");
+ static private Pattern lt = Pattern.compile("<");
+ static private Pattern gt = Pattern.compile(">");
+ static private Pattern squ = Pattern.compile("'");
+ static private Pattern dqu = Pattern.compile("\"");
+
+ static public String encode (String s) {
+ if(tst.matcher(s).find()){
+ s= amp.matcher(s).replaceAll("&");
+ s= lt.matcher(s).replaceAll("<");
+ s= gt.matcher(s).replaceAll(">");
+ s= squ.matcher(s).replaceAll("'");
+ s= dqu.matcher(s).replaceAll(""");
+ }
+ return s;
+ }
+
+
+ static public StringBuffer encode (StringBuffer sb) {
+
+ return new StringBuffer(encode(sb.toString()));
+
+ }
+
+
+ public String where() {
+ return sourcename + ":" + (yyline+1) + "." + (yycolumn+1) ;
+ }
+
+ public int getYYLine() { return yyline+1;}
+ public int getYYColumn() { return yycolumn+1;}
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * <br><br>
+ * @param file An inputStream providing the XML
+ * @param gp A parser implementing the IGenericXMLParser interface.
+ */
+ static public void load(java.io.InputStream xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * @param xmlStream
+ * @param gp
+ * @throws Exception
+ */
+ static public void load(java.io.Reader xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+
+%}
+
+Char = [a-z]|[A-Z]|"_"
+Digit = [0-9]
+namestart = {Char}
+namechar = {namestart} | "-" | "." | {Digit}
+Identifier = {namestart}{namechar}*(":"{namestart}{namechar}*)?
+EOL = \r|\n|\r\n
+ws = {EOL}|[ \t\f]
+string1 = "'"[^']*"'"
+string2 = "\""[^\"]*"\""
+string = {string1}|{string2}
+body = ({ws}|[^<>])*
+any = Char|ws|Digit|">"|"<"|"&"|.
+comment = "<!--"~"-->"
+
+%xstate Attributes
+%xstate Tag
+%xstate EndTag
+%xstate NestedTag
+%%
+
+<YYINITIAL> {
+
+ "<" {pushstate(Tag); }
+ "<?"{body}"?>" {}
+ {ws} { }
+ {comment} {}
+ {any} { error(yytext()); }
+
+}
+
+<Attributes> {
+ {Identifier}{ws}*"="{ws}*{string} {
+ String text = yytext();
+ String key = text.substring (0,text.indexOf('=')).trim();
+ String value = text.substring (text.indexOf('=')+1).trim();
+ char delimiter = value.charAt(0);
+ value = value.substring(1,value.lastIndexOf(delimiter));
+
+ attribs.put(key,unencode(value));
+ }
+
+ "/"?">" {
+ yypushback(1);
+ if(yytext().indexOf("/")>=0) yypushback(1);
+ popstate();
+ }
+
+ {ws} { }
+ {any} { error(yytext()); }
+}
+
+<Tag> {
+ {Identifier} {
+ pushTag(yytext());
+ body="";
+ pushstate(Attributes);
+ }
+
+ ">" {
+ parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ popstate();
+ pushstate(EndTag);
+ }
+
+ "/>" {
+ parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(currenttag);
+ popstate();
+ return 1;
+ }
+
+ {comment} {}
+ {ws} { }
+ {any} { error(yytext()); }
+
+}
+
+<EndTag> {
+
+ {body} {
+ String text = yytext();
+ body += text;
+ }
+
+ "</"{Identifier}{ws}*">" {
+ String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,unencode(body),attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ }
+
+ "<" {
+ popstate();
+ pushstate(NestedTag);
+ pushstate(Tag);
+ }
+
+ {comment} {}
+ {any} { body += yytext(); error(yytext()); }
+}
+
+<NestedTag> {
+ "<" {pushstate(Tag); }
+
+ "</"{Identifier}{ws}*">" {
+ String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ return 1;
+ }
+
+ {ws} {}
+ {comment} {}
+ {any} { error(yytext()); }
+
+}
+
--- /dev/null
+/* The following code was generated by JFlex 1.4.1 on 9/3/08 9:55 PM */
+
+package com.dtrules.xmlparser;
+import java.util.*;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.regex.Pattern;
+@SuppressWarnings({"unchecked","unused"})
+
+/**
+ * This class is a scanner generated by
+ * <a href="http://www.jflex.de/">JFlex</a> 1.4.1
+ * on 9/3/08 9:55 PM from the specification file
+ * <tt>C:/eb/eb_dev2/RulesEngine/DTRules/src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex</tt>
+ */
+public class GenericXMLParser {
+
+ /** This character denotes the end of file */
+ public static final int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ public static final int EndTag = 3;
+ public static final int NestedTag = 4;
+ public static final int YYINITIAL = 0;
+ public static final int Tag = 2;
+ public static final int Attributes = 1;
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final String ZZ_CMAP_PACKED =
+ "\11\0\1\7\1\6\1\0\1\7\1\5\22\0\1\7\1\26\1\11"+
+ "\3\0\1\0\1\10\5\0\1\3\1\2\1\31\12\2\1\4\1\0"+
+ "\1\12\1\30\1\25\1\27\1\0\2\1\1\13\1\21\26\1\4\0"+
+ "\1\1\1\0\1\15\5\1\1\23\1\14\1\22\10\1\1\16\1\20"+
+ "\1\24\2\1\1\17\3\1\uff85\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int [] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 =
+ "\3\0\1\1\1\0\1\2\2\3\1\4\7\2\1\5"+
+ "\1\2\1\6\1\2\1\7\1\2\1\1\1\10\1\11"+
+ "\1\4\13\0\1\12\13\0\1\6\4\0\1\13\3\0"+
+ "\1\14\2\0\1\15\4\0";
+
+ private static int [] zzUnpackAction() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAction(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+ private static final String ZZ_ROWMAP_PACKED_0 =
+ "\0\0\0\32\0\64\0\116\0\150\0\202\0\234\0\202"+
+ "\0\266\0\320\0\352\0\u0104\0\u011e\0\u0138\0\u0152\0\u016c"+
+ "\0\202\0\u0186\0\u01a0\0\u01ba\0\202\0\u01d4\0\u01ee\0\u0208"+
+ "\0\202\0\u0222\0\u023c\0\u0256\0\u0270\0\u028a\0\u011e\0\u02a4"+
+ "\0\u02be\0\u02d8\0\u02f2\0\u030c\0\u0326\0\202\0\u0340\0\u035a"+
+ "\0\u0374\0\u038e\0\u03a8\0\u03c2\0\u03dc\0\u03f6\0\u0410\0\u042a"+
+ "\0\u0444\0\u045e\0\u0478\0\u0492\0\u04ac\0\u04c6\0\202\0\u04e0"+
+ "\0\u04fa\0\u0514\0\202\0\u052e\0\u0548\0\202\0\u0562\0\u057c"+
+ "\0\u0596\0\u05b0";
+
+ private static int [] zzUnpackRowMap() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int high = packed.charAt(i++) << 16;
+ result[j++] = high | packed.charAt(i++);
+ }
+ return j;
+ }
+
+ /**
+ * The transition table of the DFA
+ */
+ private static final int [] ZZ_TRANS = zzUnpackTrans();
+
+ private static final String ZZ_TRANS_PACKED_0 =
+ "\5\6\1\7\2\10\2\6\1\11\1\12\3\6\1\13"+
+ "\1\6\1\14\11\6\1\15\3\6\1\7\2\10\3\6"+
+ "\1\16\3\15\1\17\1\15\1\20\3\15\1\21\3\6"+
+ "\1\22\1\6\1\23\3\6\1\7\2\10\2\6\1\24"+
+ "\12\23\1\25\3\6\1\26\12\27\1\30\12\27\1\31"+
+ "\4\27\5\6\1\7\2\10\2\6\1\32\1\12\3\6"+
+ "\1\13\1\6\1\14\10\6\40\0\1\10\51\0\1\33"+
+ "\1\34\16\0\1\35\35\0\1\6\33\0\1\36\10\0"+
+ "\3\37\1\40\3\41\3\0\12\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\1\37\1\43\10\37\3\0"+
+ "\1\42\2\0\3\37\1\40\3\41\3\0\5\37\1\15"+
+ "\4\37\3\0\1\42\2\0\3\37\1\40\3\41\3\0"+
+ "\7\37\1\44\2\37\3\0\1\42\26\0\1\21\5\0"+
+ "\3\23\1\45\6\0\12\23\33\0\1\33\30\0\1\46"+
+ "\4\0\12\27\1\0\12\27\1\0\4\27\26\0\1\33"+
+ "\2\0\1\47\26\0\1\33\2\0\1\50\3\0\1\51"+
+ "\26\0\12\34\1\0\12\34\1\0\1\34\1\52\2\34"+
+ "\15\0\1\53\37\0\1\54\7\0\1\55\11\0\12\55"+
+ "\12\0\3\41\20\0\1\42\6\0\3\42\1\56\1\57"+
+ "\21\0\3\37\1\40\3\41\3\0\2\37\1\60\7\37"+
+ "\3\0\1\42\2\0\3\37\1\40\3\41\3\0\10\37"+
+ "\1\61\1\37\3\0\1\42\2\0\1\62\11\0\12\62"+
+ "\6\0\1\63\11\0\12\63\6\0\1\64\11\0\12\64"+
+ "\10\0\1\65\26\0\12\34\1\0\12\34\1\10\1\34"+
+ "\1\52\2\34\16\0\1\6\35\0\1\66\10\0\3\55"+
+ "\1\0\3\41\3\0\12\55\3\0\1\42\1\0\10\56"+
+ "\1\67\21\56\11\57\1\67\20\57\1\0\3\37\1\40"+
+ "\3\41\3\0\3\37\1\15\6\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\7\37\1\70\2\37\3\0"+
+ "\1\42\2\0\3\62\7\0\12\62\6\0\3\63\1\71"+
+ "\3\72\3\0\12\63\1\73\5\0\3\64\1\74\3\75"+
+ "\3\0\12\64\1\76\4\0\3\65\1\77\26\65\24\0"+
+ "\1\6\6\0\3\37\1\40\3\41\3\0\11\37\1\15"+
+ "\3\0\1\42\2\0\1\100\11\0\12\100\12\0\3\72"+
+ "\15\0\1\73\5\0\1\101\11\0\12\101\12\0\3\75"+
+ "\15\0\1\76\4\0\3\65\1\102\26\65\1\0\3\100"+
+ "\1\0\3\72\3\0\12\100\1\73\5\0\3\101\1\0"+
+ "\3\75\3\0\12\101\1\76\4\0\3\65\1\102\21\65"+
+ "\1\10\4\65";
+
+ private static int [] zzUnpackTrans() {
+ int [] result = new int[1482];
+ int offset = 0;
+ offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackTrans(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+
+ /* error messages for the codes above */
+ private static final String ZZ_ERROR_MSG[] = {
+ "Unkown internal scanner error",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
+ */
+ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 =
+ "\3\0\1\1\1\0\1\11\1\1\1\11\10\1\1\11"+
+ "\3\1\1\11\3\1\1\11\1\1\13\0\1\11\13\0"+
+ "\1\1\4\0\1\11\3\0\1\11\2\0\1\11\4\0";
+
+ private static int [] zzUnpackAttribute() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the input device */
+ private java.io.Reader zzReader;
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int zzPushbackPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int zzEndRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ private int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ private int yycolumn;
+
+ /**
+ * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=> the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /* user code: */
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ private String sourcename = "unknown name";
+ String tagstk [] = new String[1000];
+ int tagstkptr = 0;
+ int statestk [] = new int[1000];
+ int statestkptr = 0;
+ ArrayList attribstk = new ArrayList();
+ HashMap<String,String> attribs = new HashMap<String,String>();
+ boolean printflg = true;
+ IGenericXMLParser parser = null;
+
+ String body = "";
+ String currenttag = "";
+ String Source;
+
+ public GenericXMLParser(String filename) throws FileNotFoundException {
+ this(new FileInputStream(filename));
+ sourcename = filename;
+ }
+
+ void pushTag(String tag){
+ tagstk[tagstkptr++] = tag;
+ currenttag = tag;
+ attribstk.add(attribs); // We save and restore the attribs hashmap
+ attribs = new HashMap();
+ }
+
+ String popTag(String endtag) {
+ attribs = (HashMap) attribstk.remove(attribstk.size()-1);
+ if(endtag.indexOf("</")>=0){
+ endtag=endtag.substring(2,endtag.length()-1).trim();
+ }
+ if(tagstkptr<=0){
+ System.err.print("Stack Underflow\n");
+ }
+ String tag = tagstk[--tagstkptr];
+ if(!tag.equals(endtag)){
+ System.err.print("Begin and End tags do not match:\n"+
+ "Begin tag: "+tag+"\n"+
+ "End tag: "+endtag+"\n");
+ }
+
+ if(tagstkptr<=0){
+ currenttag = "";
+ }else{
+ currenttag = tagstk[tagstkptr-1];
+ }
+
+ return tag;
+ }
+
+ public void setSource(String source){
+ this.sourcename=source;
+ }
+
+ public void setParser (IGenericXMLParser p_parser){
+ parser = p_parser;
+ }
+
+ void pushstate(int state) {
+ statestk[statestkptr++]=yystate();
+ yybegin(state);
+ }
+
+ int popstate (){
+ int newstate = statestk[--statestkptr];
+ statestk[statestkptr]=0;
+ yybegin(newstate);
+ return newstate;
+ }
+
+ void error(String v)throws Exception{
+ if(!parser.error(v)){
+ throw new Exception("Unmatched characters, parsing cannot continue at" + where());
+ }
+ }
+
+ static private Pattern xamp = Pattern.compile("&");
+ static private Pattern xlt = Pattern.compile("<");
+ static private Pattern xgt = Pattern.compile(">");
+ static private Pattern xsqu = Pattern.compile("'");
+ static private Pattern xdqu = Pattern.compile(""");
+
+ static public String unencode (String s){
+ if(s.indexOf("&")>=0){
+ s= xlt.matcher(s).replaceAll("<");
+ s= xgt.matcher(s).replaceAll(">");
+ s= xsqu.matcher(s).replaceAll("'");
+ s= xdqu.matcher(s).replaceAll("\"");
+ s= xamp.matcher(s).replaceAll("&");
+ }
+ return s;
+ }
+ static private Pattern tst = Pattern.compile("[&<>'\"]+");
+ static private Pattern amp = Pattern.compile("&");
+ static private Pattern lt = Pattern.compile("<");
+ static private Pattern gt = Pattern.compile(">");
+ static private Pattern squ = Pattern.compile("'");
+ static private Pattern dqu = Pattern.compile("\"");
+
+ static public String encode (String s) {
+ if(tst.matcher(s).find()){
+ s= amp.matcher(s).replaceAll("&");
+ s= lt.matcher(s).replaceAll("<");
+ s= gt.matcher(s).replaceAll(">");
+ s= squ.matcher(s).replaceAll("'");
+ s= dqu.matcher(s).replaceAll(""");
+ }
+ return s;
+ }
+
+
+ static public StringBuffer encode (StringBuffer sb) {
+
+ return new StringBuffer(encode(sb.toString()));
+
+ }
+
+
+ public String where() {
+ return sourcename + ":" + (yyline+1) + "." + (yycolumn+1) ;
+ }
+
+ public int getYYLine() { return yyline+1;}
+ public int getYYColumn() { return yycolumn+1;}
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * <br><br>
+ * @param file An inputStream providing the XML
+ * @param gp A parser implementing the IGenericXMLParser interface.
+ */
+ static public void load(java.io.InputStream xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * @param xmlStream
+ * @param gp
+ * @throws Exception
+ */
+ static public void load(java.io.Reader xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+
+
+
+ /**
+ * Creates a new scanner
+ * There is also a java.io.InputStream version of this constructor.
+ *
+ * @param in the java.io.Reader to read input from.
+ */
+ public GenericXMLParser(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+ /**
+ * Creates a new scanner.
+ * There is also java.io.Reader version of this constructor.
+ *
+ * @param in the java.io.Inputstream to read input from.
+ */
+ public GenericXMLParser(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char [] zzUnpackCMap(String packed) {
+ char [] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 90) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do map[j++] = value; while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return <code>false</code>, iff there was new input.
+ *
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ private boolean zzRefill() throws java.io.IOException {
+
+ /* first: make room (if you can) */
+ if (zzStartRead > 0) {
+ System.arraycopy(zzBuffer, zzStartRead,
+ zzBuffer, 0,
+ zzEndRead-zzStartRead);
+
+ /* translate stored positions */
+ zzEndRead-= zzStartRead;
+ zzCurrentPos-= zzStartRead;
+ zzMarkedPos-= zzStartRead;
+ zzPushbackPos-= zzStartRead;
+ zzStartRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (zzCurrentPos >= zzBuffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[zzCurrentPos*2];
+ System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
+ zzBuffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = zzReader.read(zzBuffer, zzEndRead,
+ zzBuffer.length-zzEndRead);
+
+ if (numRead < 0) {
+ return true;
+ }
+ else {
+ zzEndRead+= numRead;
+ return false;
+ }
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ public final void yyclose() throws java.io.IOException {
+ zzAtEOF = true; /* indicate end of file */
+ zzEndRead = zzStartRead; /* invalidate buffer */
+
+ if (zzReader != null)
+ zzReader.close();
+ }
+
+
+ /**
+ * Resets the scanner to read from a new input stream.
+ * Does not close the old reader.
+ *
+ * All internal variables are reset, the old input stream
+ * <b>cannot</b> be reused (internal buffer is discarded and lost).
+ * Lexical state is set to <tt>ZZ_INITIAL</tt>.
+ *
+ * @param reader the new input stream
+ */
+ public final void yyreset(java.io.Reader reader) {
+ zzReader = reader;
+ zzAtBOL = true;
+ zzAtEOF = false;
+ zzEndRead = zzStartRead = 0;
+ zzCurrentPos = zzMarkedPos = zzPushbackPos = 0;
+ yyline = yychar = yycolumn = 0;
+ zzLexicalState = YYINITIAL;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ public final int yystate() {
+ return zzLexicalState;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState the new lexical state
+ */
+ public final void yybegin(int newState) {
+ zzLexicalState = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ public final String yytext() {
+ return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
+ }
+
+
+ /**
+ * Returns the character at position <tt>pos</tt> from the
+ * matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos the position of the character to fetch.
+ * A value from 0 to yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ public final char yycharat(int pos) {
+ return zzBuffer[zzStartRead+pos];
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ public final int yylength() {
+ return zzMarkedPos-zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ public void yypushback(int number) {
+ if ( number > yylength() )
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched,
+ * the end of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ public int yylex() throws java.io.IOException, Exception {
+ int zzInput;
+ int zzAction;
+
+ // cached fields:
+ int zzCurrentPosL;
+ int zzMarkedPosL;
+ int zzEndReadL = zzEndRead;
+ char [] zzBufferL = zzBuffer;
+ char [] zzCMapL = ZZ_CMAP;
+
+ int [] zzTransL = ZZ_TRANS;
+ int [] zzRowMapL = ZZ_ROWMAP;
+ int [] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ boolean zzR = false;
+ for (zzCurrentPosL = zzStartRead; zzCurrentPosL < zzMarkedPosL;
+ zzCurrentPosL++) {
+ switch (zzBufferL[zzCurrentPosL]) {
+ case '\u000B':
+ case '\u000C':
+ case '\u0085':
+ case '\u2028':
+ case '\u2029':
+ yyline++;
+ yycolumn = 0;
+ zzR = false;
+ break;
+ case '\r':
+ yyline++;
+ yycolumn = 0;
+ zzR = true;
+ break;
+ case '\n':
+ if (zzR)
+ zzR = false;
+ else {
+ yyline++;
+ yycolumn = 0;
+ }
+ break;
+ default:
+ zzR = false;
+ yycolumn++;
+ }
+ }
+
+ if (zzR) {
+ // peek one character ahead if it is \n (if we have counted one line too much)
+ boolean zzPeek;
+ if (zzMarkedPosL < zzEndReadL)
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ else if (zzAtEOF)
+ zzPeek = false;
+ else {
+ boolean eof = zzRefill();
+ zzEndReadL = zzEndRead;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ if (eof)
+ zzPeek = false;
+ else
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ }
+ if (zzPeek) yyline--;
+ }
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = zzLexicalState;
+
+
+ zzForAction: {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL)
+ zzInput = zzBufferL[zzCurrentPosL++];
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ zzInput = zzBufferL[zzCurrentPosL++];
+ }
+ }
+ int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
+ if (zzNext == -1) break zzForAction;
+ zzState = zzNext;
+
+ int zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ( (zzAttributes & 8) == 8 ) break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 11:
+ { String text = yytext();
+ String key = text.substring (0,text.indexOf('=')).trim();
+ String value = text.substring (text.indexOf('=')+1).trim();
+ char delimiter = value.charAt(0);
+ value = value.substring(1,value.lastIndexOf(delimiter));
+
+ attribs.put(key,unencode(value));
+ }
+ case 14: break;
+ case 9:
+ { body += yytext(); error(yytext());
+ }
+ case 15: break;
+ case 6:
+ { pushTag(yytext());
+ body="";
+ pushstate(Attributes);
+ }
+ case 16: break;
+ case 5:
+ { yypushback(1);
+ if(yytext().indexOf("/")>=0) yypushback(1);
+ popstate();
+ }
+ case 17: break;
+ case 12:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,unencode(body),attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ }
+ case 18: break;
+ case 8:
+ { popstate();
+ pushstate(NestedTag);
+ pushstate(Tag);
+ }
+ case 19: break;
+ case 7:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ popstate();
+ pushstate(EndTag);
+ }
+ case 20: break;
+ case 13:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ return 1;
+ }
+ case 21: break;
+ case 10:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(currenttag);
+ popstate();
+ return 1;
+ }
+ case 22: break;
+ case 1:
+ { String text = yytext();
+ body += text;
+ }
+ case 23: break;
+ case 2:
+ { error(yytext());
+ }
+ case 24: break;
+ case 4:
+ { pushstate(Tag);
+ }
+ case 25: break;
+ case 3:
+ {
+ }
+ case 26: break;
+ default:
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ return YYEOF;
+ }
+ else {
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
--- /dev/null
+/* The following code was generated by JFlex 1.4.1 on 9/3/08 9:40 PM */
+
+package com.dtrules.xmlparser;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+@SuppressWarnings({"unchecked","unused"})
+
+/**
+ * This class is a scanner generated by
+ * <a href="http://www.jflex.de/">JFlex</a> 1.4.1
+ * on 9/3/08 9:40 PM from the specification file
+ * <tt>C:/eb/eb_dev2/RulesEngine/DTRules/src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex</tt>
+ */
+public class GenericXMLParser {
+
+ /** This character denotes the end of file */
+ public static final int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ public static final int EndTag = 3;
+ public static final int NestedTag = 4;
+ public static final int YYINITIAL = 0;
+ public static final int Tag = 2;
+ public static final int Attributes = 1;
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final String ZZ_CMAP_PACKED =
+ "\11\0\1\7\1\6\1\0\1\7\1\5\22\0\1\7\1\26\1\11"+
+ "\3\0\1\0\1\10\5\0\1\3\1\2\1\31\12\2\1\4\1\0"+
+ "\1\12\1\30\1\25\1\27\1\0\2\1\1\13\1\21\26\1\4\0"+
+ "\1\1\1\0\1\15\5\1\1\23\1\14\1\22\10\1\1\16\1\20"+
+ "\1\24\2\1\1\17\3\1\uff85\0";
+
+ /**
+ * Translates characters to character classes
+ */
+ private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int [] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 =
+ "\3\0\1\1\1\0\1\2\2\3\1\4\7\2\1\5"+
+ "\1\2\1\6\1\2\1\7\1\2\1\1\1\10\1\11"+
+ "\1\4\13\0\1\12\13\0\1\6\4\0\1\13\3\0"+
+ "\1\14\2\0\1\15\4\0";
+
+ private static int [] zzUnpackAction() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAction(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+ private static final String ZZ_ROWMAP_PACKED_0 =
+ "\0\0\0\32\0\64\0\116\0\150\0\202\0\234\0\202"+
+ "\0\266\0\320\0\352\0\u0104\0\u011e\0\u0138\0\u0152\0\u016c"+
+ "\0\202\0\u0186\0\u01a0\0\u01ba\0\202\0\u01d4\0\u01ee\0\u0208"+
+ "\0\202\0\u0222\0\u023c\0\u0256\0\u0270\0\u028a\0\u011e\0\u02a4"+
+ "\0\u02be\0\u02d8\0\u02f2\0\u030c\0\u0326\0\202\0\u0340\0\u035a"+
+ "\0\u0374\0\u038e\0\u03a8\0\u03c2\0\u03dc\0\u03f6\0\u0410\0\u042a"+
+ "\0\u0444\0\u045e\0\u0478\0\u0492\0\u04ac\0\u04c6\0\202\0\u04e0"+
+ "\0\u04fa\0\u0514\0\202\0\u052e\0\u0548\0\202\0\u0562\0\u057c"+
+ "\0\u0596\0\u05b0";
+
+ private static int [] zzUnpackRowMap() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int high = packed.charAt(i++) << 16;
+ result[j++] = high | packed.charAt(i++);
+ }
+ return j;
+ }
+
+ /**
+ * The transition table of the DFA
+ */
+ private static final int [] ZZ_TRANS = zzUnpackTrans();
+
+ private static final String ZZ_TRANS_PACKED_0 =
+ "\5\6\1\7\2\10\2\6\1\11\1\12\3\6\1\13"+
+ "\1\6\1\14\11\6\1\15\3\6\1\7\2\10\3\6"+
+ "\1\16\3\15\1\17\1\15\1\20\3\15\1\21\3\6"+
+ "\1\22\1\6\1\23\3\6\1\7\2\10\2\6\1\24"+
+ "\12\23\1\25\3\6\1\26\12\27\1\30\12\27\1\31"+
+ "\4\27\5\6\1\7\2\10\2\6\1\32\1\12\3\6"+
+ "\1\13\1\6\1\14\10\6\40\0\1\10\51\0\1\33"+
+ "\1\34\16\0\1\35\35\0\1\6\33\0\1\36\10\0"+
+ "\3\37\1\40\3\41\3\0\12\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\1\37\1\43\10\37\3\0"+
+ "\1\42\2\0\3\37\1\40\3\41\3\0\5\37\1\15"+
+ "\4\37\3\0\1\42\2\0\3\37\1\40\3\41\3\0"+
+ "\7\37\1\44\2\37\3\0\1\42\26\0\1\21\5\0"+
+ "\3\23\1\45\6\0\12\23\33\0\1\33\30\0\1\46"+
+ "\4\0\12\27\1\0\12\27\1\0\4\27\26\0\1\33"+
+ "\2\0\1\47\26\0\1\33\2\0\1\50\3\0\1\51"+
+ "\26\0\12\34\1\0\12\34\1\0\1\34\1\52\2\34"+
+ "\15\0\1\53\37\0\1\54\7\0\1\55\11\0\12\55"+
+ "\12\0\3\41\20\0\1\42\6\0\3\42\1\56\1\57"+
+ "\21\0\3\37\1\40\3\41\3\0\2\37\1\60\7\37"+
+ "\3\0\1\42\2\0\3\37\1\40\3\41\3\0\10\37"+
+ "\1\61\1\37\3\0\1\42\2\0\1\62\11\0\12\62"+
+ "\6\0\1\63\11\0\12\63\6\0\1\64\11\0\12\64"+
+ "\10\0\1\65\26\0\12\34\1\0\12\34\1\10\1\34"+
+ "\1\52\2\34\16\0\1\6\35\0\1\66\10\0\3\55"+
+ "\1\0\3\41\3\0\12\55\3\0\1\42\1\0\10\56"+
+ "\1\67\21\56\11\57\1\67\20\57\1\0\3\37\1\40"+
+ "\3\41\3\0\3\37\1\15\6\37\3\0\1\42\2\0"+
+ "\3\37\1\40\3\41\3\0\7\37\1\70\2\37\3\0"+
+ "\1\42\2\0\3\62\7\0\12\62\6\0\3\63\1\71"+
+ "\3\72\3\0\12\63\1\73\5\0\3\64\1\74\3\75"+
+ "\3\0\12\64\1\76\4\0\3\65\1\77\26\65\24\0"+
+ "\1\6\6\0\3\37\1\40\3\41\3\0\11\37\1\15"+
+ "\3\0\1\42\2\0\1\100\11\0\12\100\12\0\3\72"+
+ "\15\0\1\73\5\0\1\101\11\0\12\101\12\0\3\75"+
+ "\15\0\1\76\4\0\3\65\1\102\26\65\1\0\3\100"+
+ "\1\0\3\72\3\0\12\100\1\73\5\0\3\101\1\0"+
+ "\3\75\3\0\12\101\1\76\4\0\3\65\1\102\21\65"+
+ "\1\10\4\65";
+
+ private static int [] zzUnpackTrans() {
+ int [] result = new int[1482];
+ int offset = 0;
+ offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackTrans(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+
+ /* error messages for the codes above */
+ private static final String ZZ_ERROR_MSG[] = {
+ "Unkown internal scanner error",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
+ */
+ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 =
+ "\3\0\1\1\1\0\1\11\1\1\1\11\10\1\1\11"+
+ "\3\1\1\11\3\1\1\11\1\1\13\0\1\11\13\0"+
+ "\1\1\4\0\1\11\3\0\1\11\2\0\1\11\4\0";
+
+ private static int [] zzUnpackAttribute() {
+ int [] result = new int[66];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the input device */
+ private java.io.Reader zzReader;
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the textposition at the last state to be included in yytext */
+ private int zzPushbackPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int zzEndRead;
+
+ /** number of newlines encountered up to the start of the matched text */
+ private int yyline;
+
+ /** the number of characters up to the start of the matched text */
+ private int yychar;
+
+ /**
+ * the number of characters from the last newline up to the start of the
+ * matched text
+ */
+ private int yycolumn;
+
+ /**
+ * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=> the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /* user code: */
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ private String sourcename = "unknown name";
+ String tagstk [] = new String[1000];
+ int tagstkptr = 0;
+ int statestk [] = new int[1000];
+ int statestkptr = 0;
+ ArrayList attribstk = new ArrayList();
+ HashMap<String,String> attribs = new HashMap<String,String>();
+ boolean printflg = true;
+ IGenericXMLParser parser = null;
+
+ String body = "";
+ String currenttag = "";
+ String Source;
+
+ public GenericXMLParser(String filename) throws FileNotFoundException {
+ this(new FileInputStream(filename));
+ sourcename = filename;
+ }
+
+ void pushTag(String tag){
+ tagstk[tagstkptr++] = tag;
+ currenttag = tag;
+ attribstk.add(attribs); // We save and restore the attribs hashmap
+ attribs = new HashMap();
+ }
+
+ String popTag(String endtag) {
+ attribs = (HashMap) attribstk.remove(attribstk.size()-1);
+ if(endtag.indexOf("</")>=0){
+ endtag=endtag.substring(2,endtag.length()-1).trim();
+ }
+ if(tagstkptr<=0){
+ System.err.print("Stack Underflow\n");
+ }
+ String tag = tagstk[--tagstkptr];
+ if(!tag.equals(endtag)){
+ System.err.print("Begin and End tags do not match:\n"+
+ "Begin tag: "+tag+"\n"+
+ "End tag: "+endtag+"\n");
+ }
+
+ if(tagstkptr<=0){
+ currenttag = "";
+ }else{
+ currenttag = tagstk[tagstkptr-1];
+ }
+
+ return tag;
+ }
+
+ public void setSource(String source){
+ this.sourcename=source;
+ }
+
+ public void setParser (IGenericXMLParser p_parser){
+ parser = p_parser;
+ }
+
+ void pushstate(int state) {
+ statestk[statestkptr++]=yystate();
+ yybegin(state);
+ }
+
+ int popstate (){
+ int newstate = statestk[--statestkptr];
+ statestk[statestkptr]=0;
+ yybegin(newstate);
+ return newstate;
+ }
+
+ void error(String v)throws Exception{
+ if(!parser.error(v)){
+ throw new Exception("Unmatched characters, parsing cannot continue at" + where());
+ }
+ }
+
+ static private Pattern xamp = Pattern.compile("&");
+ static private Pattern xlt = Pattern.compile("<");
+ static private Pattern xgt = Pattern.compile(">");
+ static private Pattern xsqu = Pattern.compile("'");
+ static private Pattern xdqu = Pattern.compile(""");
+
+ static public String unencode (String s){
+ if(s.indexOf("&")>=0){
+ s= xlt.matcher(s).replaceAll("<");
+ s= xgt.matcher(s).replaceAll(">");
+ s= xsqu.matcher(s).replaceAll("'");
+ s= xdqu.matcher(s).replaceAll("\"");
+ s= xamp.matcher(s).replaceAll("&");
+ }
+ return s;
+ }
+ static private Pattern tst = Pattern.compile("[&<>'\"]+");
+ static private Pattern amp = Pattern.compile("&");
+ static private Pattern lt = Pattern.compile("<");
+ static private Pattern gt = Pattern.compile(">");
+ static private Pattern squ = Pattern.compile("'");
+ static private Pattern dqu = Pattern.compile("\"");
+
+ static public String encode (String s) {
+ if(tst.matcher(s).find()){
+ s= amp.matcher(s).replaceAll("&");
+ s= lt.matcher(s).replaceAll("<");
+ s= gt.matcher(s).replaceAll(">");
+ s= squ.matcher(s).replaceAll("'");
+ s= dqu.matcher(s).replaceAll(""");
+ }
+ return s;
+ }
+
+ static public StringBuffer encode (StringBuffer sb) {
+
+ return new StringBuffer(encode(sb.toString()));
+
+ }
+
+
+ public String where() {
+ return sourcename + ":" + (yyline+1) + "." + (yycolumn+1) ;
+ }
+
+ public int getYYLine() { return yyline+1;}
+ public int getYYColumn() { return yycolumn+1;}
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * <br><br>
+ * @param file An inputStream providing the XML
+ * @param gp A parser implementing the IGenericXMLParser interface.
+ */
+ static public void load(java.io.InputStream xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+ /**
+ * Loads an XML file with the given Generic Parser.
+ * @param xmlStream
+ * @param gp
+ * @throws Exception
+ */
+ static public void load(java.io.Reader xmlStream, IGenericXMLParser gp) throws Exception{
+ GenericXMLParser parser = new GenericXMLParser(xmlStream);
+ parser.setParser(gp);
+ while(true){
+ if(GenericXMLParser.YYEOF == parser.yylex()) break;
+ }
+ }
+
+
+
+
+ /**
+ * Creates a new scanner
+ * There is also a java.io.InputStream version of this constructor.
+ *
+ * @param in the java.io.Reader to read input from.
+ */
+ public GenericXMLParser(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+ /**
+ * Creates a new scanner.
+ * There is also java.io.Reader version of this constructor.
+ *
+ * @param in the java.io.Inputstream to read input from.
+ */
+ public GenericXMLParser(java.io.InputStream in) {
+ this(new java.io.InputStreamReader(in));
+ }
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char [] zzUnpackCMap(String packed) {
+ char [] map = new char[0x10000];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < 90) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do map[j++] = value; while (--count > 0);
+ }
+ return map;
+ }
+
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return <code>false</code>, iff there was new input.
+ *
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ private boolean zzRefill() throws java.io.IOException {
+
+ /* first: make room (if you can) */
+ if (zzStartRead > 0) {
+ System.arraycopy(zzBuffer, zzStartRead,
+ zzBuffer, 0,
+ zzEndRead-zzStartRead);
+
+ /* translate stored positions */
+ zzEndRead-= zzStartRead;
+ zzCurrentPos-= zzStartRead;
+ zzMarkedPos-= zzStartRead;
+ zzPushbackPos-= zzStartRead;
+ zzStartRead = 0;
+ }
+
+ /* is the buffer big enough? */
+ if (zzCurrentPos >= zzBuffer.length) {
+ /* if not: blow it up */
+ char newBuffer[] = new char[zzCurrentPos*2];
+ System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
+ zzBuffer = newBuffer;
+ }
+
+ /* finally: fill the buffer with new input */
+ int numRead = zzReader.read(zzBuffer, zzEndRead,
+ zzBuffer.length-zzEndRead);
+
+ if (numRead < 0) {
+ return true;
+ }
+ else {
+ zzEndRead+= numRead;
+ return false;
+ }
+ }
+
+
+ /**
+ * Closes the input stream.
+ */
+ public final void yyclose() throws java.io.IOException {
+ zzAtEOF = true; /* indicate end of file */
+ zzEndRead = zzStartRead; /* invalidate buffer */
+
+ if (zzReader != null)
+ zzReader.close();
+ }
+
+
+ /**
+ * Resets the scanner to read from a new input stream.
+ * Does not close the old reader.
+ *
+ * All internal variables are reset, the old input stream
+ * <b>cannot</b> be reused (internal buffer is discarded and lost).
+ * Lexical state is set to <tt>ZZ_INITIAL</tt>.
+ *
+ * @param reader the new input stream
+ */
+ public final void yyreset(java.io.Reader reader) {
+ zzReader = reader;
+ zzAtBOL = true;
+ zzAtEOF = false;
+ zzEndRead = zzStartRead = 0;
+ zzCurrentPos = zzMarkedPos = zzPushbackPos = 0;
+ yyline = yychar = yycolumn = 0;
+ zzLexicalState = YYINITIAL;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ public final int yystate() {
+ return zzLexicalState;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState the new lexical state
+ */
+ public final void yybegin(int newState) {
+ zzLexicalState = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ public final String yytext() {
+ return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
+ }
+
+
+ /**
+ * Returns the character at position <tt>pos</tt> from the
+ * matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos the position of the character to fetch.
+ * A value from 0 to yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ public final char yycharat(int pos) {
+ return zzBuffer[zzStartRead+pos];
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ public final int yylength() {
+ return zzMarkedPos-zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ public void yypushback(int number) {
+ if ( number > yylength() )
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched,
+ * the end of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ public int yylex() throws java.io.IOException, Exception {
+ int zzInput;
+ int zzAction;
+
+ // cached fields:
+ int zzCurrentPosL;
+ int zzMarkedPosL;
+ int zzEndReadL = zzEndRead;
+ char [] zzBufferL = zzBuffer;
+ char [] zzCMapL = ZZ_CMAP;
+
+ int [] zzTransL = ZZ_TRANS;
+ int [] zzRowMapL = ZZ_ROWMAP;
+ int [] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ boolean zzR = false;
+ for (zzCurrentPosL = zzStartRead; zzCurrentPosL < zzMarkedPosL;
+ zzCurrentPosL++) {
+ switch (zzBufferL[zzCurrentPosL]) {
+ case '\u000B':
+ case '\u000C':
+ case '\u0085':
+ case '\u2028':
+ case '\u2029':
+ yyline++;
+ yycolumn = 0;
+ zzR = false;
+ break;
+ case '\r':
+ yyline++;
+ yycolumn = 0;
+ zzR = true;
+ break;
+ case '\n':
+ if (zzR)
+ zzR = false;
+ else {
+ yyline++;
+ yycolumn = 0;
+ }
+ break;
+ default:
+ zzR = false;
+ yycolumn++;
+ }
+ }
+
+ if (zzR) {
+ // peek one character ahead if it is \n (if we have counted one line too much)
+ boolean zzPeek;
+ if (zzMarkedPosL < zzEndReadL)
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ else if (zzAtEOF)
+ zzPeek = false;
+ else {
+ boolean eof = zzRefill();
+ zzEndReadL = zzEndRead;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ if (eof)
+ zzPeek = false;
+ else
+ zzPeek = zzBufferL[zzMarkedPosL] == '\n';
+ }
+ if (zzPeek) yyline--;
+ }
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = zzLexicalState;
+
+
+ zzForAction: {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL)
+ zzInput = zzBufferL[zzCurrentPosL++];
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ zzInput = zzBufferL[zzCurrentPosL++];
+ }
+ }
+ int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ];
+ if (zzNext == -1) break zzForAction;
+ zzState = zzNext;
+
+ int zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ( (zzAttributes & 8) == 8 ) break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 11:
+ { String text = yytext();
+ String key = text.substring (0,text.indexOf('=')).trim();
+ String value = text.substring (text.indexOf('=')+1).trim();
+ char delimiter = value.charAt(0);
+ value = value.substring(1,value.lastIndexOf(delimiter));
+
+ attribs.put(key,unencode(value));
+ }
+ case 14: break;
+ case 9:
+ { body += yytext(); error(yytext());
+ }
+ case 15: break;
+ case 6:
+ { pushTag(yytext());
+ body="";
+ pushstate(Attributes);
+ }
+ case 16: break;
+ case 5:
+ { yypushback(1);
+ if(yytext().indexOf("/")>=0) yypushback(1);
+ popstate();
+ }
+ case 17: break;
+ case 12:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,unencode(body),attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ }
+ case 18: break;
+ case 8:
+ { popstate();
+ pushstate(NestedTag);
+ pushstate(Tag);
+ }
+ case 19: break;
+ case 7:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ popstate();
+ pushstate(EndTag);
+ }
+ case 20: break;
+ case 13:
+ { String endTag = yytext();
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(endTag);
+ popstate();
+ return 1;
+ }
+ case 21: break;
+ case 10:
+ { parser.beginTag(tagstk,tagstkptr,currenttag,attribs);
+ parser.endTag(tagstk,tagstkptr,currenttag,"",attribs);
+ attribs.clear();
+ popTag(currenttag);
+ popstate();
+ return 1;
+ }
+ case 22: break;
+ case 1:
+ { String text = yytext();
+ body += text;
+ }
+ case 23: break;
+ case 2:
+ { error(yytext());
+ }
+ case 24: break;
+ case 4:
+ { pushstate(Tag);
+ }
+ case 25: break;
+ case 3:
+ {
+ }
+ case 26: break;
+ default:
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ return YYEOF;
+ }
+ else {
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.xmlparser;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * This is a simple interface for handling parsing events
+ * from the generic parser. At this time, only two events
+ * are generated, the beginTag and the endTag events. The
+ * endTag() provides the body, if present.
+ * Creation date: (9/15/2003 8:35:17 AM)
+ * @author: Paul Snow, MTBJ, Inc.
+ */
+public interface IGenericXMLParser {
+
+ /**
+ * The beginTag method is called when the parser detects the
+ * each begin tag in the XML file being parsed. When one uses
+ * a SAX parser, the class implementing the interface is responsible
+ * for keeping up with the context of the tags as they are
+ * encountered and closed. The GenericXMLParser provides a
+ * stack of all the tags currently open when the begin tag
+ * is encountered. This is the actual stack maintained by the
+ * GenericXMLParser, which is maintained as an array of tags.
+ * The tagstkptr provides an index into this array. <br><br>
+ * The attributes associated with the tag are provided as a
+ * hashmap of key/Value pairs. <br><br>
+ *
+ * @param tagstk A stack of tags active at the time the tag was encountered.
+ * @param tagstkptr A pointer into the tag stack to the top of stack.
+ * @param tag The tag encountered.
+ * @param attribs A hash map of attributes as a set of key/Value pairs.
+ * @throws IOException If an error occurs while parsing the XML, this exception will be thrown.
+ * @throws Exception If the tags are not matched, or an unexpected character is encountered, an
+ * exception will be thrown.
+ */
+ public void beginTag(
+ String tagstk[],
+ int tagstkptr,
+ String tag,
+ HashMap<String, String> attribs)
+ throws IOException, Exception;
+
+ /**
+ * The endTag method is called when the parser detects the
+ * each end tag in the XML file being parsed. When one uses
+ * a SAX parser, the class implementing the interface is responsible
+ * for keeping up with the context of the tags as they are
+ * encountered and closed. The GenericXMLParser provides a
+ * stack of all the tags currently open when the end tag
+ * is encountered. The GenericXMLParser also provides the
+ * attributes of the begin tag to the end tag as well.
+ * <br><br>
+ *
+ * @param tagstk A stack of tags active at the time the tag was encountered.
+ * @param tagstkptr A pointer into the tag stack to the top of stack.
+ * @param tag The tag encountered.
+ * @param body the body (if any) of the data between the begin and end tags.
+ * @param attribs A hash map of attributes as a set of key/Value pairs.
+ * @throws IOException If an error occurs while parsing the XML, this exception will be thrown.
+ * @throws Exception If the tags are not matched, or an unexpected character is encountered, an
+ * exception will be thrown.
+ **/
+ public void endTag(
+ java.lang.String[] tagstk,
+ int tagstkptr,
+ String tag,
+ String body,
+ HashMap<String,String> attribs)
+ throws Exception, IOException;
+
+ /**
+ * When an error is encountered by the parser, the error method
+ * is called on the class implementing the IGenericXMLParser
+ * interface. This method returns true if parsing should continue.
+ * @param v This is the error string from the GenericXMLParser
+ */
+ public boolean error(String v)
+ throws Exception; // Returns true if parsing should continue.
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.xmlparser;
+
+public interface IXMLPrinter {
+
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth();
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i);
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ public abstract void opentag(String tag);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ */
+ public abstract void opentag(String tag, String name1, Object value1);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3);
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ */
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8, String name9, Object value9);
+
+ public abstract void opentag(String tag, String name1, Object value1, String name2,
+ Object value2, String name3, Object value3, String name4, Object value4, String name5,
+ Object value5, String name6, Object value6, String name7, Object value7, String name8,
+ Object value8, String name9, Object value9, String name10,Object value10);
+ /**
+ * Closes the currently open tag. Assumes no body text. Throws a
+ * runtime exception if no open tag exists.
+ */
+ public abstract void closetag();
+
+ /**
+ * Print data within a data tag. The text is encoded.
+ * @param text
+ */
+ public abstract void printdata(Object bodyvalue);
+
+ /**
+ * Print data within a given tag.
+ */
+ public abstract void printdata(String tag, Object bodyvalue);
+
+ /**
+ * Print the tag, one attribute, and the body.
+ * @param tag
+ * @param name1
+ * @param value
+ * @param body
+ */
+ public abstract void printdata(String tag, String name1, Object value, Object body);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ Object bodyvalue);
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ Object bodyvalue);
+ /**
+ * Closes all open tags, close the file.
+ *
+ */
+ public abstract void close();
+
+ /**
+ * Just a helper to print an error during the generation of an XML file
+ * @param errorMsg The error message to be printed. Put into an <error> tag in the XML.
+ */
+ public abstract void print_error(String errorMsg);
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.xmlparser;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+
+import com.dtrules.interpreter.RTime;
+
+/**
+ * A simple class for the support of printing XML files. Start and end tags
+ * are tracked and printed. An enclosing tag is printed. Strings are encoded
+ * automatically. Tags are specified by their name, i.e. "Document" and not
+ * using any XML syntax, i.e. "<Document>".
+ *
+ * @author paul snow
+ * Jul 9, 2007
+ *
+ */
+public class XMLPrinter implements IXMLPrinter {
+ ArrayList<String> tagStack = new ArrayList<String>();
+ final PrintStream out;
+ boolean newline = true;
+ boolean intextbody = false;
+ boolean intagbody = false;
+ /**
+ * Returns the number of tags on the tag stack.
+ */
+ public int depth() {
+ return tagStack.size();
+ }
+
+ /**
+ * Returns the tag with the given index. Returns null if out
+ * of range.
+ */
+ public String getTag(int i){
+ if(i<0 || i>=tagStack.size())return null;
+ return tagStack.get(i);
+ }
+
+ /**
+ * This function puts the output on a newline, but not if we
+ * are already on a newline.
+ */
+ private void newline(){
+ if(!newline)out.println();
+ newline = true;
+ }
+ /**
+ * A helper function just to print text, and sets the state of the
+ * newline function. Note that we are never going to print a newline
+ * on a non-XML syntax boundry.
+ * @param text
+ */
+ private void print(String text){
+ out.print(text);
+ newline = false;
+ }
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ private void halfopentag(String tag){
+ if(intextbody)throw new RuntimeException("Can't open a tag within a data body");
+ newline();
+ int indent = tagStack.size();
+ for(int i=0;i<indent;i++)print(" ");
+ print("<");
+ print(tag);
+ tagStack.add(tag);
+ intagbody = false; // Just don't know at this point how this tag will be used.
+ intextbody = false;
+ }
+
+ /**
+ * Prints a simple open tag with no attributes.
+ * @param tag
+ */
+ public void opentag(String tag){
+ halfopentag(tag);
+ print(">");
+ }
+ /**
+ * Prints an attribute. The value is encoded.
+ */
+ private void printAttribute(String name, Object value){
+ name = name.replaceAll(" ", "_");
+ print(" ");
+ print(name);
+ print("='");
+ print(GenericXMLParser.encode(value.toString()));
+ print("'");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ */
+ public void opentag(String tag, String name1, Object value1){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ print(">");
+ }
+ /**
+ * Open a tag with a given set of attributes
+ */
+ public void opentag(String tag, HashMap<String,Object> attribs){
+ halfopentag(tag);
+ for(String key : attribs.keySet()){
+ Object o = attribs.get(key);
+ if(o!=null){
+ printAttribute(key, o);
+ }else{
+ printAttribute(key,"");
+ }
+ }
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ print(">");
+ }
+
+ /**
+ * Open a tag with one named attribute
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ */
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ print(">");
+ }
+
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ print(">");
+ }
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ printAttribute(name9, value9);
+ print(">");
+ }
+
+ public void opentag(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ String name6, Object value6,
+ String name7, Object value7,
+ String name8, Object value8,
+ String name9, Object value9,
+ String name10,Object value10
+ ){
+ halfopentag(tag);
+ printAttribute(name1, value1);
+ printAttribute(name2, value2);
+ printAttribute(name3, value3);
+ printAttribute(name4, value4);
+ printAttribute(name5, value5);
+ printAttribute(name6, value6);
+ printAttribute(name7, value7);
+ printAttribute(name8, value8);
+ printAttribute(name9, value9);
+ printAttribute(name10,value10);
+ print(">");
+ }
+
+
+ /**
+ * Closes the currently open tag. Assumes no body text. Throws a
+ * runtime exception if no open tag exists.
+ */
+ public void closetag(){
+ int lastIndex = tagStack.size()-1;
+ if(!intextbody){
+ newline();
+ for(int i=0;i<lastIndex;i++)print(" ");
+ }
+ if(tagStack.size()<=0){
+ throw new RuntimeException("No Enclosing Tag to close");
+ }
+ print("</");
+ print(tagStack.get(lastIndex));
+ print(">");
+ newline();
+ tagStack.remove(lastIndex);
+ intextbody = false;
+ intagbody = true;
+ }
+ /**
+ * Print data within a data tag. The text is encoded.
+ * @param text
+ */
+ public void printdata(Object bodyvalue){
+ if(intagbody){
+ throw new RuntimeException("You can't mix data and tags");
+ }
+ if(bodyvalue != null){
+ if(bodyvalue instanceof Date) {
+ bodyvalue = RTime.getRTime((Date)bodyvalue);
+ }
+ String v = GenericXMLParser.encode(bodyvalue.toString());
+ out.print(v);
+ }
+ intextbody = true;
+ }
+
+ /**
+ * Print data within a given tag.
+ */
+ public void printdata(String tag, Object bodyvalue){
+ opentag(tag);
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Open a tag with a given set of attributes
+ */
+ public void printdata(String tag, HashMap<String,Object> attribs, Object bodyvalue){
+ halfopentag(tag);
+ for(String key : attribs.keySet()){
+ String v = GenericXMLParser.encode(attribs.get(key).toString());
+ printAttribute(key, v);
+ }
+ print(">");
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param body
+ */
+ public void printdata(String tag, String name1, Object value1,String name2, Object value2, Object bodyvalue){
+ opentag(tag,name1,value1,name2,value2);
+ printdata(bodyvalue);
+ closetag();
+ }
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ Object bodyvalue){
+ opentag(tag,name1,value1,name2,value2,name3,value3);
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ Object bodyvalue){
+ opentag(tag,
+ name1,value1,
+ name2,value2,
+ name3,value3,
+ name4,value4
+ );
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, and the body.
+ * @param tag
+ * @param name1
+ * @param value1
+ * @param name2
+ * @param value2
+ * @param name3
+ * @param value3
+ * @param name4
+ * @param value4
+ * @param name5
+ * @param value5
+ * @param body
+ */
+ public void printdata(String tag,
+ String name1, Object value1,
+ String name2, Object value2,
+ String name3, Object value3,
+ String name4, Object value4,
+ String name5, Object value5,
+ Object bodyvalue){
+ opentag(tag,
+ name1,value1,
+ name2,value2,
+ name3,value3,
+ name4,value4,
+ name5,value5
+ );
+ printdata(bodyvalue);
+ closetag();
+ }
+
+ /**
+ * Print the tag, attributes, no
+ * @param tag
+ * @param name1
+ * @param value
+ * @param body
+ */
+ public void printdata(String tag, String name1, Object value, Object bodyvalue){
+ opentag(tag,name1,value);
+ printdata(bodyvalue);
+ closetag();
+ }
+ public XMLPrinter(OutputStream stream ){
+ out = new PrintStream(stream);
+ }
+ /**
+ * Opens an output stream, and puts out the surrounding root tag.
+ * @param tag The surrounding tag. No XML syntax should be specified.
+ * @param stream
+ */
+ public XMLPrinter(String tag, OutputStream stream){
+ out = new PrintStream(stream);
+ opentag(tag);
+ }
+
+ /**
+ * Closes all open tags, close the file.
+ *
+ */
+ public void close(){
+ for(int i = tagStack.size()-1; i>=0;i--){
+ closetag();
+ }
+ out.close();
+ }
+
+ /**
+ * Just a helper to print an error during the generation of an XML file
+ * @param errorMsg The error message to be printed. Put into an <error> tag in the XML.
+ */
+ public void print_error(String errorMsg){
+ if(intextbody)closetag();
+ opentag("error");
+ print(GenericXMLParser.encode(errorMsg));
+ closetag();
+ }
+
+}
--- /dev/null
+dir
+set pdir=C:\eb\eb_dev2\RulesEngine\DTRules\src\main\java\com\dtrules
+set pdir2=C:\jflex-1.4.1
+set xmldir=%pdir%\xmlparser
+java -classpath %pdir2%\lib\JFlex.jar JFlex.Main -d %xmldir% %xmldir%\GenericXMLParser.flex
+pause
\ No newline at end of file
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+com
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+dtrules
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+test
+dir
+\f
+interpreter
+dir
+\f
+admin
+dir
+\f
+decisiontables
+dir
+\f
+mapping
+dir
+\f
+entity
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/admin
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+RulesAdminServiceTest.java
+file
+
+
+
+
+2008-05-15T17:27:56.953125Z
+3d126096ada88422cb828962d2f67434
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RulesAdminServiceTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public final void testGetRulesets() {
+ RulesAdminService ras = new RulesAdminService(null,null);
+ ras.initialize(null);
+ assertNotNull("Ruleset null", ras.getRulesets());
+ assertNotNull("Ruleset null", ras.getRulesets().get(0));
+ assertEquals("Ruleset name is the same","ebdemo", ras.getRulesets().get(0));
+ // fail("Not yet implemented"); // TODO
+ }
+
+ @Test
+ public final void testGetRuleset() {
+ RulesAdminService ras = new RulesAdminService(null,null);
+ ras.initialize(null);
+ assertNotNull("Ruleset name null", ras.getRuleset("ebdemo"));
+ assertNull("Ruleset null", ras.getRuleset("/ebdemo"));
+ // fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.admin;
+
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class RulesAdminServiceTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public final void testGetRulesets() {
+ RulesAdminService ras = new RulesAdminService(null,null);
+ ras.initialize(null);
+ assertNotNull("Ruleset null", ras.getRulesets());
+ assertNotNull("Ruleset null", ras.getRulesets().get(0));
+ assertEquals("Ruleset name is the same","ebdemo", ras.getRulesets().get(0));
+ // fail("Not yet implemented"); // TODO
+ }
+
+ @Test
+ public final void testGetRuleset() {
+ RulesAdminService ras = new RulesAdminService(null,null);
+ ras.initialize(null);
+ assertNotNull("Ruleset name null", ras.getRuleset("ebdemo"));
+ assertNull("Ruleset null", ras.getRuleset("/ebdemo"));
+ // fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/decisiontables
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+ANodeTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.156250Z
+2c471d4b9aec4b99f6d46535efc8a2d7
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+DecisionTableTypeTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.156250Z
+20d6320eff60e2199ae11924019af61f
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+RDecisionTableTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.171875Z
+467eae8d2c11bd7db4aabd07868ef990
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+CNodeTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.187500Z
+9b0cae9c37c14cc0899d397f8bc235d6
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+DTLoaderTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.187500Z
+0cc4dcb81b17f628b9eddf463ec476f7
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class ANodeTest extends BaseTest {
+
+ public ANodeTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import junit.framework.TestCase;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class CNodeTest extends TestCase {
+
+ /**
+ *
+ */
+ public CNodeTest() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param arg0
+ */
+ public CNodeTest(String arg0) {
+ super(arg0);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class DTLoaderTest extends BaseTest {
+
+ /**
+ * @param arg
+ */
+ public DTLoaderTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_decision_tables()}.
+ */
+ public final void testEnd_decision_tables() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_table_name()}.
+ */
+ public final void testEnd_table_name() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_decision_table()}.
+ */
+ public final void testEnd_decision_table() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_table_number()}.
+ */
+ public final void testEnd_table_number() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_ipad_id()}.
+ */
+ public final void testEnd_ipad_id() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_purpose()}.
+ */
+ public final void testEnd_purpose() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_comments()}.
+ */
+ public final void testEnd_comments() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_policy_reference()}.
+ */
+ public final void testEnd_policy_reference() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_condition_details()}.
+ */
+ public final void testBegin_condition_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_description()}.
+ */
+ public final void testEnd_condition_description() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_postfix()}.
+ */
+ public final void testEnd_condition_postfix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_comment()}.
+ */
+ public final void testEnd_condition_comment() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_condition_column()}.
+ */
+ public final void testBegin_condition_column() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_details()}.
+ */
+ public final void testEnd_condition_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_action_details()}.
+ */
+ public final void testBegin_action_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_description()}.
+ */
+ public final void testEnd_action_description() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_postfix()}.
+ */
+ public final void testEnd_action_postfix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_comment()}.
+ */
+ public final void testEnd_action_comment() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_action_column()}.
+ */
+ public final void testBegin_action_column() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_details()}.
+ */
+ public final void testEnd_action_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#beginTag(java.lang.String[], int, java.lang.String, java.util.HashMap)}.
+ */
+ public final void testBeginTag() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#endTag(java.lang.String[], int, java.lang.String, java.lang.String, java.util.HashMap)}.
+ */
+ public final void testEndTag() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#error(java.lang.String)}.
+ */
+ public final void testError() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.mapping.LoadMapping;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.session.DTState;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+public class DecisionTableTypeTest {
+
+ int maxRow=0,maxCol=0;
+ String ctable [][] = new String[128][128];
+ String atable [][] = new String[128][128];
+ RDecisionTable dt;
+
+ public DecisionTableTypeTest(IRSession session, RuleSet rs) throws RulesException{
+
+ dt = new RDecisionTable(session, rs, "test");
+
+ String ctable[][] = {
+ { "y", "n", "n", "y", "d", "a" },
+ { "n", "n", "y", " ", " ", " " },
+ { "y", "y", "y", "n", " ", " " },
+ { "y", "y", " ", " ", " ", " " },
+ { " ", " ", "y", " ", " ", " " },
+ { "y", " ", " ", " ", " ", " " },
+
+ };
+ dt.conditiontable = ctable;
+
+ String atable[][] = {
+ { "x", " ", " ", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", " ", " ", "x", "x", " " },
+ { " ", " ", " ", " ", "x", " " },
+ { " ", " ", " ", "x", " ", "x" },
+ };
+ dt.maxcol = ctable[0].length;
+ dt.actiontable = atable;
+ dt.rconditions = new IRObject[ctable.length];
+ dt.ractions = new IRObject[atable.length];
+
+ String cps[] = new String[ctable.length];
+ for (int i = 0; i < cps.length; i++)
+ cps[i] = "{ 'Condition " + i + "' }";
+
+ String aps[] = new String[atable.length];
+ for (int i = 0; i < aps.length; i++)
+ aps[i] = "{ 'Action " + i + "' }";
+
+ dt.conditions = cps;
+ dt.conditionsPostfix = cps;
+ dt.actions = aps;
+ dt.actionsPostfix = aps;
+ dt.setType(RDecisionTable.Type.FIRST);
+ }
+
+ public static void main(String[] args) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = "DTRules.xml";
+ if(args.length>0){
+ file = args[0];
+ }
+
+ try {
+ RulesDirectory rd = new RulesDirectory(path,file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ IRSession session = rs.newSession();
+ DTState state = session.getState();
+ DecisionTableTypeTest test;
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.FIRST);
+ test.dt.build();
+ test.printtable ();
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.ALL);
+ test.dt.build();
+ test.printtable ();
+
+
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
+
+ }
+
+ void printtable(){
+ maxRow = maxCol = 0;
+ filltable(0,0,dt.decisiontree);
+
+ System.out.print(" ");
+ for(int i=0;i<maxCol;i++){
+ System.out.print(i+((i<10)?" ":" "));
+ }
+ System.out.println();
+ for(int i=0;i<maxRow;i++){
+ System.out.print(dt.conditions[i]+" ");
+ for(int j=0; j<maxCol;j++){
+ System.out.print(ctable[i][j]==null?"- ":ctable[i][j]+" ");
+ }
+ System.out.println();
+ }
+ System.out.println("--------------------------------------");
+ for(int i=0;i<dt.actions.length;i++){
+ System.out.print(dt.actions[i]+" ");
+ for(int j=0;j<maxCol;j++){
+ System.out.print(atable[i][j]==null?" ":"X ");
+ }
+ System.out.println();
+ }
+ Iterator<ICompilerError> errors = dt.getErrorList().iterator();
+ while(errors.hasNext()){
+ ICompilerError error = errors.next();
+ System.out.println(error.getMessage()+
+ " on "+"Row " + error.getRow()+" Column "+error.getCol());
+
+
+ }
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+
+/**
+ * @author paul snow
+ * Jan 23, 2007
+ *
+ */
+public class RDecisionTableTest extends BaseTest {
+
+ /**
+ * @param arg
+ */
+ public RDecisionTableTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#isExecutable()}.
+ */
+ public final void testIsExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#compile()}.
+ */
+ public final void testCompile() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#newANode(int)}.
+ */
+ public final void testNewANode() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#build()}.
+ */
+ public final void testBuild() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#stringValue()}.
+ */
+ public final void testStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#type()}.
+ */
+ public final void testType() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class ANodeTest extends BaseTest {
+
+ public ANodeTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.ANode#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import junit.framework.TestCase;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class CNodeTest extends TestCase {
+
+ /**
+ *
+ */
+ public CNodeTest() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param arg0
+ */
+ public CNodeTest(String arg0) {
+ super(arg0);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.CNode#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class DTLoaderTest extends BaseTest {
+
+ /**
+ * @param arg
+ */
+ public DTLoaderTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_decision_tables()}.
+ */
+ public final void testEnd_decision_tables() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_table_name()}.
+ */
+ public final void testEnd_table_name() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_decision_table()}.
+ */
+ public final void testEnd_decision_table() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_table_number()}.
+ */
+ public final void testEnd_table_number() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_ipad_id()}.
+ */
+ public final void testEnd_ipad_id() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_purpose()}.
+ */
+ public final void testEnd_purpose() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_comments()}.
+ */
+ public final void testEnd_comments() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_policy_reference()}.
+ */
+ public final void testEnd_policy_reference() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_condition_details()}.
+ */
+ public final void testBegin_condition_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_description()}.
+ */
+ public final void testEnd_condition_description() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_postfix()}.
+ */
+ public final void testEnd_condition_postfix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_comment()}.
+ */
+ public final void testEnd_condition_comment() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_condition_column()}.
+ */
+ public final void testBegin_condition_column() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_condition_details()}.
+ */
+ public final void testEnd_condition_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_action_details()}.
+ */
+ public final void testBegin_action_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_description()}.
+ */
+ public final void testEnd_action_description() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_postfix()}.
+ */
+ public final void testEnd_action_postfix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_comment()}.
+ */
+ public final void testEnd_action_comment() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#begin_action_column()}.
+ */
+ public final void testBegin_action_column() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#end_action_details()}.
+ */
+ public final void testEnd_action_details() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#beginTag(java.lang.String[], int, java.lang.String, java.util.HashMap)}.
+ */
+ public final void testBeginTag() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#endTag(java.lang.String[], int, java.lang.String, java.lang.String, java.util.HashMap)}.
+ */
+ public final void testEndTag() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.DTLoader#error(java.lang.String)}.
+ */
+ public final void testError() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import com.dtrules.entity.REntity;
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.IRObject;
+import com.dtrules.interpreter.RName;
+import com.dtrules.interpreter.RNull;
+import com.dtrules.mapping.LoadMapping;
+import com.dtrules.mapping.Mapping;
+import com.dtrules.session.DTState;
+import com.dtrules.session.ICompilerError;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+import com.dtrules.xmlparser.GenericXMLParser;
+
+public class DecisionTableTypeTest {
+
+ int maxRow=0,maxCol=0;
+ String ctable [][] = new String[128][128];
+ String atable [][] = new String[128][128];
+ RDecisionTable dt;
+
+ public DecisionTableTypeTest(IRSession session, RuleSet rs) throws RulesException{
+
+ dt = new RDecisionTable(session, rs, "test");
+
+ String ctable[][] = {
+ { "y", "n", "n", "y", "d", "a" },
+ { "n", "n", "y", " ", " ", " " },
+ { "y", "y", "y", "n", " ", " " },
+ { "y", "y", " ", " ", " ", " " },
+ { " ", " ", "y", " ", " ", " " },
+ { "y", " ", " ", " ", " ", " " },
+
+ };
+ dt.conditiontable = ctable;
+
+ String atable[][] = {
+ { "x", " ", " ", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", "x", "x", " ", " ", " " },
+ { " ", " ", " ", "x", "x", " " },
+ { " ", " ", " ", " ", "x", " " },
+ { " ", " ", " ", "x", " ", "x" },
+ };
+ dt.maxcol = ctable[0].length;
+ dt.actiontable = atable;
+ dt.rconditions = new IRObject[ctable.length];
+ dt.ractions = new IRObject[atable.length];
+
+ String cps[] = new String[ctable.length];
+ for (int i = 0; i < cps.length; i++)
+ cps[i] = "{ 'Condition " + i + "' }";
+
+ String aps[] = new String[atable.length];
+ for (int i = 0; i < aps.length; i++)
+ aps[i] = "{ 'Action " + i + "' }";
+
+ dt.conditions = cps;
+ dt.conditionsPostfix = cps;
+ dt.actions = aps;
+ dt.actionsPostfix = aps;
+ dt.setType(RDecisionTable.Type.FIRST);
+ }
+
+ public static void main(String[] args) {
+ String path = "C:\\eclipse\\workspace\\EB_POC\\CA HCO Plan\\xml\\";
+ String file = "DTRules.xml";
+ if(args.length>0){
+ file = args[0];
+ }
+
+ try {
+ RulesDirectory rd = new RulesDirectory(path,file);
+ RuleSet rs = rd.getRuleSet(RName.getRName("ebdemo"));
+ IRSession session = rs.newSession();
+ DTState state = session.getState();
+ DecisionTableTypeTest test;
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.FIRST);
+ test.dt.build();
+ test.printtable ();
+
+ test = new DecisionTableTypeTest(session,rs);
+ test.dt.setType(RDecisionTable.Type.ALL);
+ test.dt.build();
+ test.printtable ();
+
+
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ }
+
+ }
+
+ void printtable(){
+ maxRow = maxCol = 0;
+ filltable(0,0,dt.decisiontree);
+
+ System.out.print(" ");
+ for(int i=0;i<maxCol;i++){
+ System.out.print(i+((i<10)?" ":" "));
+ }
+ System.out.println();
+ for(int i=0;i<maxRow;i++){
+ System.out.print(dt.conditions[i]+" ");
+ for(int j=0; j<maxCol;j++){
+ System.out.print(ctable[i][j]==null?"- ":ctable[i][j]+" ");
+ }
+ System.out.println();
+ }
+ System.out.println("--------------------------------------");
+ for(int i=0;i<dt.actions.length;i++){
+ System.out.print(dt.actions[i]+" ");
+ for(int j=0;j<maxCol;j++){
+ System.out.print(atable[i][j]==null?" ":"X ");
+ }
+ System.out.println();
+ }
+ Iterator<ICompilerError> errors = dt.getErrorList().iterator();
+ while(errors.hasNext()){
+ ICompilerError error = errors.next();
+ System.out.println(error.getMessage()+
+ " on "+"Row " + error.getRow()+" Column "+error.getCol());
+
+
+ }
+ }
+
+
+ private int filltable(int row, int col, DTNode node){
+ if(node.getClass()==CNode.class){
+ int ncol;
+ CNode cnode = (CNode) node;
+
+ if(cnode.conditionNumber!=row){
+ ncol = filltable(row+1,col, node);
+ for(int i=col;i<ncol;i++)ctable[row][i]="-";
+ return ncol;
+ }
+
+ ncol = filltable(row+1,col,cnode.iftrue);
+ for(int i=col;i<ncol;i++)ctable[row][i]="y";
+ col = ncol;
+ ncol = filltable(row+1,col,cnode.iffalse);
+ for(int i=col;i<ncol;i++)ctable[row][i]="n";
+ col = ncol;
+ }else{
+ ctable[row][col]="-";
+ ANode anode = (ANode)node;
+ for(int i=0;i<anode.anumbers.size();i++){
+ int index = anode.anumbers.get(i).intValue();
+ atable[index][col]="x";
+ }
+ col++;
+ }
+ maxRow = maxRow<row?row:maxRow;
+ maxCol = maxCol<col?col:maxCol;
+ return col;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.decisiontables;
+
+import com.dtrules.test.BaseTest;
+
+
+/**
+ * @author paul snow
+ * Jan 23, 2007
+ *
+ */
+public class RDecisionTableTest extends BaseTest {
+
+ /**
+ * @param arg
+ */
+ public RDecisionTableTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#isExecutable()}.
+ */
+ public final void testIsExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#compile()}.
+ */
+ public final void testCompile() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#validate()}.
+ */
+ public final void testValidate() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#newANode(int)}.
+ */
+ public final void testNewANode() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#build()}.
+ */
+ public final void testBuild() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#stringValue()}.
+ */
+ public final void testStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.decisiontables.RDecisionTable#type()}.
+ */
+ public final void testType() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/entity
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+REntityEntryTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.421875Z
+8456c01c6fa771bb353b8883a07be908
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+REntityTest.java
+file
+
+
+
+
+2008-05-15T17:27:57.421875Z
+eae049fddda68aec8a2295e1ba1e0b96
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.entity;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class REntityEntryTest extends BaseTest {
+
+ /**
+ * @param arg0
+ */
+ public REntityEntryTest(String arg0) {
+ super(arg0);
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntityEntry#REntityEntry(com.dtrules.entity.REntity, com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject, boolean, int, int)}.
+ */
+ public final void testREntityEntry() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntityEntry#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.entity;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class REntityTest extends BaseTest {
+
+ public REntityTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#postFix()}.
+ */
+ public final void testPostFix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#rEntityValue()}.
+ */
+ public final void testREntityValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#clone(com.dtrules.session.IRSession)}.
+ */
+ public final void testCloneIRSession() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#isReadOnly()}.
+ */
+ public final void testIsReadOnly() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getID()}.
+ */
+ public final void testGetID() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getAttributeIterator()}.
+ */
+ public final void testGetAttributeIterator() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#containsAttribute(com.dtrules.interpreter.RName)}.
+ */
+ public final void testContainsAttribute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#REntity(boolean, com.dtrules.entity.REntity, com.dtrules.session.IRSession)}.
+ */
+ public final void testREntityBooleanREntityIRSession() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#REntity(boolean, com.dtrules.interpreter.RName)}.
+ */
+ public final void testREntityBooleanRName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getName()}.
+ */
+ public final void testGetName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#addAttribute(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject, boolean, int)}.
+ */
+ public final void testAddAttribute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#put(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testPut() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#get(com.dtrules.interpreter.RName)}.
+ */
+ public final void testGetRName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#get(int)}.
+ */
+ public final void testGetInt() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#set(int, com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testSet() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getEntry(com.dtrules.interpreter.RName)}.
+ */
+ public final void testGetEntry() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getValue(int)}.
+ */
+ public final void testGetValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#stringValue()}.
+ */
+ public final void testStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#type()}.
+ */
+ public final void testType() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rArrayValue()}.
+ */
+ public final void testRArrayValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rBooleanValue()}.
+ */
+ public final void testRBooleanValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rDoubleValue()}.
+ */
+ public final void testRDoubleValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rTimeValue()}.
+ */
+ public final void testRTimeValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#timeValue()}.
+ */
+ public final void testTimeValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#throwRulesException(int, java.lang.String, java.lang.String)}.
+ */
+ public final void testThrowRulesException() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#getExecutable()}.
+ */
+ public final void testGetExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#getNonExecutable()}.
+ */
+ public final void testGetNonExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#equals(com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testEqualsIRObject() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#isExecutable()}.
+ */
+ public final void testIsExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rStringValue()}.
+ */
+ public final void testRStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rclone()}.
+ */
+ public final void testRclone() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#intValue()}.
+ */
+ public final void testIntValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#arrayValue()}.
+ */
+ public final void testArrayValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#booleanValue()}.
+ */
+ public final void testBooleanValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#doubleValue()}.
+ */
+ public final void testDoubleValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#hashMapValue()}.
+ */
+ public final void testHashMapValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#longValue()}.
+ */
+ public final void testLongValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rNameValue()}.
+ */
+ public final void testRNameValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rIntegerValue()}.
+ */
+ public final void testRIntegerValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#compare(com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testCompare() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.entity;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class REntityEntryTest extends BaseTest {
+
+ /**
+ * @param arg0
+ */
+ public REntityEntryTest(String arg0) {
+ super(arg0);
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntityEntry#REntityEntry(com.dtrules.entity.REntity, com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject, boolean, int, int)}.
+ */
+ public final void testREntityEntry() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntityEntry#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.entity;
+
+import com.dtrules.test.BaseTest;
+
+/**
+ * @author prasath ramachandran
+ * Jan 23, 2007
+ *
+ */
+public class REntityTest extends BaseTest {
+
+ public REntityTest(String arg) {
+ super(arg);
+ // TODO Auto-generated constructor stub
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /* (non-Javadoc)
+ * @see junit.framework.TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#postFix()}.
+ */
+ public final void testPostFix() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#rEntityValue()}.
+ */
+ public final void testREntityValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#clone(com.dtrules.session.IRSession)}.
+ */
+ public final void testCloneIRSession() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#isReadOnly()}.
+ */
+ public final void testIsReadOnly() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getID()}.
+ */
+ public final void testGetID() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getAttributeIterator()}.
+ */
+ public final void testGetAttributeIterator() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#containsAttribute(com.dtrules.interpreter.RName)}.
+ */
+ public final void testContainsAttribute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#REntity(boolean, com.dtrules.entity.REntity, com.dtrules.session.IRSession)}.
+ */
+ public final void testREntityBooleanREntityIRSession() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#REntity(boolean, com.dtrules.interpreter.RName)}.
+ */
+ public final void testREntityBooleanRName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getName()}.
+ */
+ public final void testGetName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#addAttribute(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject, boolean, int)}.
+ */
+ public final void testAddAttribute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#put(com.dtrules.interpreter.RName, com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testPut() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#get(com.dtrules.interpreter.RName)}.
+ */
+ public final void testGetRName() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#get(int)}.
+ */
+ public final void testGetInt() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#set(int, com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testSet() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getEntry(com.dtrules.interpreter.RName)}.
+ */
+ public final void testGetEntry() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#getValue(int)}.
+ */
+ public final void testGetValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#stringValue()}.
+ */
+ public final void testStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#type()}.
+ */
+ public final void testType() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.entity.REntity#toString()}.
+ */
+ public final void testToString() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rArrayValue()}.
+ */
+ public final void testRArrayValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rBooleanValue()}.
+ */
+ public final void testRBooleanValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rDoubleValue()}.
+ */
+ public final void testRDoubleValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rTimeValue()}.
+ */
+ public final void testRTimeValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#timeValue()}.
+ */
+ public final void testTimeValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#throwRulesException(int, java.lang.String, java.lang.String)}.
+ */
+ public final void testThrowRulesException() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#execute(com.dtrules.session.DTState)}.
+ */
+ public final void testExecute() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#getExecutable()}.
+ */
+ public final void testGetExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#getNonExecutable()}.
+ */
+ public final void testGetNonExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#equals(com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testEqualsIRObject() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#isExecutable()}.
+ */
+ public final void testIsExecutable() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rStringValue()}.
+ */
+ public final void testRStringValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rclone()}.
+ */
+ public final void testRclone() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#intValue()}.
+ */
+ public final void testIntValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#arrayValue()}.
+ */
+ public final void testArrayValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#booleanValue()}.
+ */
+ public final void testBooleanValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#doubleValue()}.
+ */
+ public final void testDoubleValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#hashMapValue()}.
+ */
+ public final void testHashMapValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#longValue()}.
+ */
+ public final void testLongValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rNameValue()}.
+ */
+ public final void testRNameValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#rIntegerValue()}.
+ */
+ public final void testRIntegerValue() {
+ fail("Not yet implemented"); // TODO
+ }
+
+ /**
+ * Test method for {@link com.dtrules.interpreter.ARObject#compare(com.dtrules.interpreter.IRObject)}.
+ */
+ public final void testCompare() {
+ fail("Not yet implemented"); // TODO
+ }
+
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/interpreter
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+operators
+dir
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/interpreter/operators
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+OperatorTest.java
+file
+
+
+
+
+2008-05-15T17:27:56.828125Z
+32fb5ad7f459f88a2fbb9f66f0c261a1
+2008-05-13T15:47:44.343120Z
+8649
+mgoshorn
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+public class OperatorTest {
+
+ static String tests[] = {
+
+ " 1.2 2.3 f+ ", "3.5",
+
+ " 1.2 2.3 + ", "3",
+ " 2.5 6 f* ", "15.0",
+ " 2.5 6 * ", "12",
+ " mark 1 2 3 4 arraytomark ", "[ 1 2 3 4 ]",
+ " 1 2 drop ", "1",
+ " 1 2 pop ", "1",
+ " true ", "true",
+ " false ", "false",
+ " 1 2 3 pstack print pop ", "1",
+ " 'TypeCheck' 'error test' error", "",
+ " 'TypeCheck' ", "TypeCheck",
+ " \"TypeCheck\" ", "TypeCheck",
+ " newarray ", "[ ]",
+ " newarray dup 2 addto ", "[ 2 ]",
+ " [ 2 ] dup 1 3 addat ", "[ 2 3 ]",
+ " [ 2 3 4 3 ] dup 3 remove ", "[ 2 4 ]",
+ " [ 1 2 3 4 ] dup 3 removeat ", "[ 1 2 3 ]",
+ " [ 3 4 5 6 ] dup 0 getat ", "3",
+ " [ 3 2 6 6 ] dup length ", "4",
+ " [ 5 7 8 1 ] dup 8 memberof ", "true",
+ " [ 5 7 8 1 ] dup 9 memberof ", "false",
+ " [ 1 2 3 4 ] copyelements ", "[ 1 2 3 4 ]",
+ " [ 5 7 8 1 ] dup 9 add_no_dups ", "[ 5 7 8 1 9 ]",
+ " [ 5 7 8 1 ] dup 8 add_no_dups ", "[ 5 7 8 1 ]",
+ " [ 5 7 8 1 ] dup clear ", "[ ]",
+ " [ 1 2 ] [ 3 4 ] merge ", "[ 1 2 3 4 ]",
+
+ " false not ", "true",
+ " false false && ", "false",
+ " false true || ", "true",
+ " 5 3 > ", "true",
+ " 5 3 < ", "false",
+ " 3 3 >= ", "true",
+ " 3 8 <= ", "true",
+ " 1 1 == ", "true",
+ " 5.1 3.2 > ", "true",
+ " 5.5 3.4 < ", "false",
+ " 3.1 3.0 >= ", "true",
+ " 3.9 4.0 <= ", "true",
+ " 1.5 1.5 == ", "true",
+ " true true b= ", "true",
+ " true true b!= ", "false",
+ " 'austin' 'austin' s== ", "true",
+ " 'madison' 'austin' s> ", "true",
+ " 'dallas' 'austin' s< ", "false",
+ " 3 3 >= ", "true",
+ " 3 8 <= ", "true",
+ " 1 1 == ", "true",
+ " 'austin ' 'downtown' s+ ", "austin downtown",
+ " 'austin downtown ' 'downtown' strremove ", "austin",
+ " 'abc' 'abc' req ", "true",
+ " 5 5 req ", "true",
+
+ " '2007-12-12' newdate ", "2007-12-12",
+ " '2007-12-12' newdate yearof ", "2007",
+ " '2007-12-12' newdate getdaysinyear ", "365",
+ " '2008-12-12' newdate getdaysinyear ", "366",
+ " '2008-12-12' newdate '2007-12-12' newdate d< ", "false",
+ " '2008-12-12' newdate '2007-12-12' newdate d> ", "true",
+ " '2008-12-12' newdate '2008-12-11' newdate d== ", "false",
+ " '2008-12-12' newdate '2008-12-12' newdate d== ", "true",
+ " '2008-12-12' newdate gettimestamp", "2008-12-12 00:00:00.0",
+
+ };
+
+ static int testcnt = 0;
+ static int testcntfailed = 0;
+
+ public static void main(String args[]){
+
+ String file = "c:\\eclipse\\workspace\\DTRules\\com.dtrules.testfiles\\DTRules.xml";
+ IRSession session;
+ DTState state;
+ RulesDirectory rd;
+ RuleSet rs;
+
+ try {
+ rd = new RulesDirectory("",file);
+ rs = rd.getRuleSet(RName.getRName("test",true));
+ session = rs.newSession();
+ state = session.getState();
+ } catch (RulesException e1) {
+ System.out.println("Failed to initialize the Rules Engine");
+ return;
+ }
+
+ for(int i=0;i<tests.length;i+=2){
+ try{
+ session.execute(tests[i]);
+ String result = state.datapop().stringValue();
+ if(tests[i+1].equals(result.trim())){
+ state.debug("test: << "+tests[i]+" >> expected: "+tests[i+1]+" --passed\n");
+ }else{
+ state.debug("test: << "+tests[i]+" >> expected: "+tests[i+1]+" result:"+result+" --FAILED\n");
+ }
+ state.debug("\n");
+ }catch(Exception e){
+ state.error(" Exception Thrown:\n");
+ state.error("test: "+tests[i]+"expected: "+tests[i+1]+" result: Exception thrown --FAILED\n");
+ state.error(e+"\n");
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.dtrules.interpreter.operators;
+
+import java.util.Iterator;
+
+import com.dtrules.infrastructure.RulesException;
+import com.dtrules.interpreter.RName;
+import com.dtrules.session.DTState;
+import com.dtrules.session.IRSession;
+import com.dtrules.session.RuleSet;
+import com.dtrules.session.RulesDirectory;
+
+public class OperatorTest {
+
+ static String tests[] = {
+
+ " 1.2 2.3 f+ ", "3.5",
+
+ " 1.2 2.3 + ", "3",
+ " 2.5 6 f* ", "15.0",
+ " 2.5 6 * ", "12",
+ " mark 1 2 3 4 arraytomark ", "[ 1 2 3 4 ]",
+ " 1 2 drop ", "1",
+ " 1 2 pop ", "1",
+ " true ", "true",
+ " false ", "false",
+ " 1 2 3 pstack print pop ", "1",
+ " 'TypeCheck' 'error test' error", "",
+ " 'TypeCheck' ", "TypeCheck",
+ " \"TypeCheck\" ", "TypeCheck",
+ " newarray ", "[ ]",
+ " newarray dup 2 addto ", "[ 2 ]",
+ " [ 2 ] dup 1 3 addat ", "[ 2 3 ]",
+ " [ 2 3 4 3 ] dup 3 remove ", "[ 2 4 ]",
+ " [ 1 2 3 4 ] dup 3 removeat ", "[ 1 2 3 ]",
+ " [ 3 4 5 6 ] dup 0 getat ", "3",
+ " [ 3 2 6 6 ] dup length ", "4",
+ " [ 5 7 8 1 ] dup 8 memberof ", "true",
+ " [ 5 7 8 1 ] dup 9 memberof ", "false",
+ " [ 1 2 3 4 ] copyelements ", "[ 1 2 3 4 ]",
+ " [ 5 7 8 1 ] dup 9 add_no_dups ", "[ 5 7 8 1 9 ]",
+ " [ 5 7 8 1 ] dup 8 add_no_dups ", "[ 5 7 8 1 ]",
+ " [ 5 7 8 1 ] dup clear ", "[ ]",
+ " [ 1 2 ] [ 3 4 ] merge ", "[ 1 2 3 4 ]",
+
+ " false not ", "true",
+ " false false && ", "false",
+ " false true || ", "true",
+ " 5 3 > ", "true",
+ " 5 3 < ", "false",
+ " 3 3 >= ", "true",
+ " 3 8 <= ", "true",
+ " 1 1 == ", "true",
+ " 5.1 3.2 > ", "true",
+ " 5.5 3.4 < ", "false",
+ " 3.1 3.0 >= ", "true",
+ " 3.9 4.0 <= ", "true",
+ " 1.5 1.5 == ", "true",
+ " true true b= ", "true",
+ " true true b!= ", "false",
+ " 'austin' 'austin' s== ", "true",
+ " 'madison' 'austin' s> ", "true",
+ " 'dallas' 'austin' s< ", "false",
+ " 3 3 >= ", "true",
+ " 3 8 <= ", "true",
+ " 1 1 == ", "true",
+ " 'austin ' 'downtown' s+ ", "austin downtown",
+ " 'austin downtown ' 'downtown' strremove ", "austin",
+ " 'abc' 'abc' req ", "true",
+ " 5 5 req ", "true",
+
+ " '2007-12-12' newdate ", "2007-12-12",
+ " '2007-12-12' newdate yearof ", "2007",
+ " '2007-12-12' newdate getdaysinyear ", "365",
+ " '2008-12-12' newdate getdaysinyear ", "366",
+ " '2008-12-12' newdate '2007-12-12' newdate d< ", "false",
+ " '2008-12-12' newdate '2007-12-12' newdate d> ", "true",
+ " '2008-12-12' newdate '2008-12-11' newdate d== ", "false",
+ " '2008-12-12' newdate '2008-12-12' newdate d== ", "true",
+ " '2008-12-12' newdate gettimestamp", "2008-12-12 00:00:00.0",
+
+ };
+
+ static int testcnt = 0;
+ static int testcntfailed = 0;
+
+ public static void main(String args[]){
+
+ String file = "c:\\eclipse\\workspace\\DTRules\\com.dtrules.testfiles\\DTRules.xml";
+ IRSession session;
+ DTState state;
+ RulesDirectory rd;
+ RuleSet rs;
+
+ try {
+ rd = new RulesDirectory("",file);
+ rs = rd.getRuleSet(RName.getRName("test",true));
+ session = rs.newSession();
+ state = session.getState();
+ } catch (RulesException e1) {
+ System.out.println("Failed to initialize the Rules Engine");
+ return;
+ }
+
+ for(int i=0;i<tests.length;i+=2){
+ try{
+ session.execute(tests[i]);
+ String result = state.datapop().stringValue();
+ if(tests[i+1].equals(result.trim())){
+ state.debug("test: << "+tests[i]+" >> expected: "+tests[i+1]+" --passed\n");
+ }else{
+ state.debug("test: << "+tests[i]+" >> expected: "+tests[i+1]+" result:"+result+" --FAILED\n");
+ }
+ state.debug("\n");
+ }catch(Exception e){
+ state.error(" Exception Thrown:\n");
+ state.error("test: "+tests[i]+"expected: "+tests[i+1]+" result: Exception thrown --FAILED\n");
+ state.error(e+"\n");
+ }
+ }
+ }
+}
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/mapping
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
--- /dev/null
+9
+
+dir
+11816
+svn://10.23.1.217/eb_dev2/trunk/RulesEngine/DTRules/src/test/com/dtrules/test
+svn://10.23.1.217/eb_dev2
+
+
+
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+ea930d4c-cb26-0410-8bd7-e59082844d7d
+\f
+AllUnitTest.java
+file
+
+
+
+
+2008-05-15T17:27:56.671875Z
+aecd495ffc64e57d07d73c69a4ec048d
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
+BaseTest.java
+file
+
+
+
+
+2008-05-15T17:27:56.687500Z
+8ce131b20b64c11b8937f2b107790269
+2008-04-30T18:30:56.493859Z
+8373
+mgoshorn
+\f
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Title : DTRules</p>
+ * <p>Description : The Rules Engine</p>
+ * <p>Date : Jan 26, 2005 , 4:41:14 PM</p>
+ *
+ * @author Prasath Ramachandran
+ * @version $Revision: 1.0 $
+ */
+
+public class AllUnitTest {
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ return suite;
+ }
+}
--- /dev/null
+/*
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.test;
+
+import junit.framework.TestCase;
+
+/**
+ * <p>Title : DTRules</p>
+ * <p>Description : The Rules Engine</p>
+ * <p>Date : Jan 26, 2005 , 4:41:14 PM</p>
+ *
+ * @author Prasath Ramachandran
+ * @version $Revision: 1.0 $
+ */
+
+public class BaseTest extends TestCase {
+
+ public BaseTest(String arg) {
+ super(arg);
+ }
+
+ public void assertNotEqual(String message, Object expected, Object actual) {
+ if (expected == null) {
+ if (actual == null) {
+ fail("They are equal");
+ }
+ } else {
+ if (actual != null) {
+ if (actual.equals(expected)) {
+ fail("They are equal");
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.test;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * <p>Title : DTRules</p>
+ * <p>Description : The Rules Engine</p>
+ * <p>Date : Jan 26, 2005 , 4:41:14 PM</p>
+ *
+ * @author Prasath Ramachandran
+ * @version $Revision: 1.0 $
+ */
+
+public class AllUnitTest {
+ public static Test suite() {
+ TestSuite suite = new TestSuite();
+ return suite;
+ }
+}
--- /dev/null
+/*
+ *
+ * Copyright 2004-2007 MTBJ, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.dtrules.test;
+
+import junit.framework.TestCase;
+
+/**
+ * <p>Title : DTRules</p>
+ * <p>Description : The Rules Engine</p>
+ * <p>Date : Jan 26, 2005 , 4:41:14 PM</p>
+ *
+ * @author Prasath Ramachandran
+ * @version $Revision: 1.0 $
+ */
+
+public class BaseTest extends TestCase {
+
+ public BaseTest(String arg) {
+ super(arg);
+ }
+
+ public void assertNotEqual(String message, Object expected, Object actual) {
+ if (expected == null) {
+ if (actual == null) {
+ fail("They are equal");
+ }
+ } else {
+ if (actual != null) {
+ if (actual.equals(expected)) {
+ fail("They are equal");
+ }
+ }
+ }
+ }
+}
--- /dev/null
+#Generated by Maven
+#Mon Sep 08 16:23:26 CDT 2008
+version=1.19-SNAPSHOT
+groupId=com.dtrules
+artifactId=DTRules