Initial Load of filesmaster
authorPaul Snow <[email protected]>
Fri, 12 Sep 2008 23:16:51 +0000 (12 18:16 -0500)
committerPaul Snow <[email protected]>
Fri, 12 Sep 2008 23:16:51 +0000 (12 18:16 -0500)
449 files changed:
.classpath [new file with mode: 0644]
.project [new file with mode: 0644]
.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
.svn/dir-prop-base [new file with mode: 0644]
.svn/entries [new file with mode: 0644]
.svn/format [new file with mode: 0644]
.svn/text-base/pom.xml.svn-base [new file with mode: 0644]
docs/.svn/entries [new file with mode: 0644]
docs/.svn/format [new file with mode: 0644]
docs/.svn/prop-base/DTRules.doc.svn-base [new file with mode: 0644]
docs/.svn/prop-base/OperatorList.doc.svn-base [new file with mode: 0644]
docs/.svn/text-base/DTRules.doc.svn-base [new file with mode: 0644]
docs/.svn/text-base/OperatorList.doc.svn-base [new file with mode: 0644]
docs/DTRules.doc [new file with mode: 0644]
docs/OperatorList.doc [new file with mode: 0644]
pom.xml [new file with mode: 0644]
src/.svn/entries [new file with mode: 0644]
src/.svn/format [new file with mode: 0644]
src/main/.svn/entries [new file with mode: 0644]
src/main/.svn/format [new file with mode: 0644]
src/main/java/.svn/entries [new file with mode: 0644]
src/main/java/.svn/format [new file with mode: 0644]
src/main/java/com/.svn/entries [new file with mode: 0644]
src/main/java/com/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/.svn/text-base/App.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/App.java [new file with mode: 0644]
src/main/java/com/dtrules/admin/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/admin/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/admin/.svn/text-base/IRulesAdminService.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/admin/.svn/text-base/RulesAdminService.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/admin/IRulesAdminService.java [new file with mode: 0644]
src/main/java/com/dtrules/admin/RulesAdminService.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/ANode.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/BalanceTable.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/CNode.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/CompilerError.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/DTLoader.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/DTNode.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/.svn/text-base/RDecisionTable.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/ANode.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/BalanceTable.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/CNode.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/CompilerError.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/DTLoader.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/DTNode.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/DecisionTableTypeTest.java [new file with mode: 0644]
src/main/java/com/dtrules/decisiontables/RDecisionTable.java [new file with mode: 0644]
src/main/java/com/dtrules/entity/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/entity/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/entity/.svn/text-base/IREntity.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/entity/.svn/text-base/REntity.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/entity/.svn/text-base/REntityEntry.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/entity/IREntity.java [new file with mode: 0644]
src/main/java/com/dtrules/entity/REntity.java [new file with mode: 0644]
src/main/java/com/dtrules/entity/REntityEntry.java [new file with mode: 0644]
src/main/java/com/dtrules/infrastructure/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/infrastructure/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/infrastructure/.svn/text-base/RulesException.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/infrastructure/RulesException.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/ARObject.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/IRObject.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RArray.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RBoolean.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RDouble.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RInteger.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RMark.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RName.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RNull.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RString.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RTable.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RTime.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/RXmlValue.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/SimpleTokenizer.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/.svn/text-base/Token.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/ARObject.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/IRObject.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RArray.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RBoolean.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RDouble.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RInteger.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RMark.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RName.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RNull.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RString.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RTable.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RTime.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/RXmlValue.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/SimpleTokenizer.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/Token.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RArrayOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RBooleanOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RControl.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RDateTimeOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMath.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMiscOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/ROperator.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RTableOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RXmlValueOps.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RArrayOps.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RBooleanOps.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RControl.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RDateTimeOps.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RMath.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RMiscOps.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/ROperator.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RTableOps.java [new file with mode: 0644]
src/main/java/com/dtrules/interpreter/operators/RXmlValueOps.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/AttributeInfo.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/DataMap.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/DataObjectMap.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/EntityInfo.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/LoadDatamapData.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/LoadMap.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/LoadMapping.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/LoadXMLData.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/MapGenerator.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/Mapping.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/.svn/text-base/XMLTag.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/mapping/AttributeInfo.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/DataMap.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/DataObjectMap.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/EntityInfo.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/LoadDatamapData.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/LoadMap.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/LoadMapping.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/LoadXMLData.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/MapGenerator.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/Mapping.java [new file with mode: 0644]
src/main/java/com/dtrules/mapping/XMLTag.java [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/DTState.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/EDDLoader.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/EntityFactory.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/ICompiler.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/ICompilerError.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/IRSession.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/RSession.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/RuleSet.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/.svn/text-base/RulesDirectory.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/session/DTState.java [new file with mode: 0644]
src/main/java/com/dtrules/session/EDDLoader.java [new file with mode: 0644]
src/main/java/com/dtrules/session/EntityFactory.java [new file with mode: 0644]
src/main/java/com/dtrules/session/ICompiler.java [new file with mode: 0644]
src/main/java/com/dtrules/session/ICompilerError.java [new file with mode: 0644]
src/main/java/com/dtrules/session/IRSession.java [new file with mode: 0644]
src/main/java/com/dtrules/session/RSession.java [new file with mode: 0644]
src/main/java/com/dtrules/session/RuleSet.java [new file with mode: 0644]
src/main/java/com/dtrules/session/RulesDirectory.java [new file with mode: 0644]
src/main/java/com/dtrules/trace/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/trace/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/trace/.svn/text-base/DecisionTableNode.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/trace/.svn/text-base/TraceNode.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/trace/DecisionTableNode.java [new file with mode: 0644]
src/main/java/com/dtrules/trace/TraceNode.java [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/entries [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/format [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.flex.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/IGenericXMLParser.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/IXMLPrinter.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/XMLPrinter.java.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/.svn/text-base/compileGenericXMLParser.bat.svn-base [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/GenericXMLParser.java [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/GenericXMLParser.java~ [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/IGenericXMLParser.java [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/IXMLPrinter.java [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/XMLPrinter.java [new file with mode: 0644]
src/main/java/com/dtrules/xmlparser/compileGenericXMLParser.bat [new file with mode: 0644]
src/test/.svn/entries [new file with mode: 0644]
src/test/.svn/format [new file with mode: 0644]
src/test/com/.svn/entries [new file with mode: 0644]
src/test/com/.svn/format [new file with mode: 0644]
src/test/com/dtrules/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/.svn/format [new file with mode: 0644]
src/test/com/dtrules/admin/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/admin/.svn/format [new file with mode: 0644]
src/test/com/dtrules/admin/.svn/text-base/RulesAdminServiceTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/admin/RulesAdminServiceTest.java [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/format [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/text-base/ANodeTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/text-base/CNodeTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/text-base/DTLoaderTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/decisiontables/.svn/text-base/RDecisionTableTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/decisiontables/ANodeTest.java [new file with mode: 0644]
src/test/com/dtrules/decisiontables/CNodeTest.java [new file with mode: 0644]
src/test/com/dtrules/decisiontables/DTLoaderTest.java [new file with mode: 0644]
src/test/com/dtrules/decisiontables/DecisionTableTypeTest.java [new file with mode: 0644]
src/test/com/dtrules/decisiontables/RDecisionTableTest.java [new file with mode: 0644]
src/test/com/dtrules/entity/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/entity/.svn/format [new file with mode: 0644]
src/test/com/dtrules/entity/.svn/text-base/REntityEntryTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/entity/.svn/text-base/REntityTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/entity/REntityEntryTest.java [new file with mode: 0644]
src/test/com/dtrules/entity/REntityTest.java [new file with mode: 0644]
src/test/com/dtrules/interpreter/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/interpreter/.svn/format [new file with mode: 0644]
src/test/com/dtrules/interpreter/operators/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/interpreter/operators/.svn/format [new file with mode: 0644]
src/test/com/dtrules/interpreter/operators/.svn/text-base/OperatorTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/interpreter/operators/OperatorTest.java [new file with mode: 0644]
src/test/com/dtrules/mapping/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/mapping/.svn/format [new file with mode: 0644]
src/test/com/dtrules/test/.svn/entries [new file with mode: 0644]
src/test/com/dtrules/test/.svn/format [new file with mode: 0644]
src/test/com/dtrules/test/.svn/text-base/AllUnitTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/test/.svn/text-base/BaseTest.java.svn-base [new file with mode: 0644]
src/test/com/dtrules/test/AllUnitTest.java [new file with mode: 0644]
src/test/com/dtrules/test/BaseTest.java [new file with mode: 0644]
target/DTRules-1.19-SNAPSHOT-sources.jar [new file with mode: 0644]
target/DTRules-1.19-SNAPSHOT.jar [new file with mode: 0644]
target/classes/com/dtrules/App.class [new file with mode: 0644]
target/classes/com/dtrules/admin/IRulesAdminService.class [new file with mode: 0644]
target/classes/com/dtrules/admin/RulesAdminService.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/ANode.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/BalanceTable.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/CNode.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/CompilerError.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/DTLoader.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/DTNode$Coordinate.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/DTNode.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/DecisionTableTypeTest.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$1.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$Type$1.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$Type$2.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$Type$3.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$Type.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable$UnbalancedType.class [new file with mode: 0644]
target/classes/com/dtrules/decisiontables/RDecisionTable.class [new file with mode: 0644]
target/classes/com/dtrules/entity/IREntity.class [new file with mode: 0644]
target/classes/com/dtrules/entity/REntity.class [new file with mode: 0644]
target/classes/com/dtrules/entity/REntityEntry.class [new file with mode: 0644]
target/classes/com/dtrules/infrastructure/RulesException.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/ARObject.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/IRObject.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RArray.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RBoolean.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RDouble.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RInteger.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RMark.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RName.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RNull.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RString.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RTable.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RTime.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/RXmlValue.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/SimpleTokenizer.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/Token$Type.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/Token.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$AddArray.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Add_no_dups.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Addat.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Addto.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Arraytomark.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Clear.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Copyelements.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Getat.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Length.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Mark.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Memberof.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Merge.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Newarray.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Randomize.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Remove.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Removeat.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortarray.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortentities.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps$Tokenize.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RArrayOps.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$And.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleannotequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Equal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$FEqual.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Isnull.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Not.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Or.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Req.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SConcat.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqual.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqualIgnoreCase.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthan.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthanequal.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps$Strremove.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RBooleanOps.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Allocate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Deallocate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Doloop.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Entityforall.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Execute.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$ExecuteTable.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$For.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$ForFirstElse.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Forall.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Forallr.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Forfirst.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Forr.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$If.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Ifelse.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Localfetch.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$Localstore.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl$While.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RControl.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddDays.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddMonths.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddYears.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DateMinus.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DatePlus.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dateeq.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dategt.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Datelt.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Days.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DaysBetween.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$EndOfMonth.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfMonth.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfYear.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdayofmonth.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinmonth.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinyear.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Gettimestamp.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$MonthsBetween.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Newdate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$SetCalendar.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Yearof.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps$YearsBetween.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RDateTimeOps.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Abs.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Add.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Div.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FAbs.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FAdd.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FDiv.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FMul.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FNegate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$FSub.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Mul.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Negate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Roundto.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath$Sub.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMath.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$ActionString.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Clone.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Createentity.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvb.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvd.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cve.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvi.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvn.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvr.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvs.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Debug.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Def.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Dup.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$EntityName.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Entityfetch.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypop.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypush.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Find.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$FromR.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$GetDescription.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$I.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Ignore.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$J.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$K.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Null.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Over.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$PStack.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Pop.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Print.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$RError.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$RegexMatch.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$SetDebug.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Stringlength.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Swap.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$ToR.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Tolowercase.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Touppercase.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceoff.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceon.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Trim.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$Xdef.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps$substring.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RMiscOps.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/ROperator.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$GetKeys.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$Lookup.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$NewTable.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$Set.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$SetDescription.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps$Translate.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RTableOps.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RXmlValueOps$GetXmlAttribute.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RXmlValueOps$SetXmlAttribute.class [new file with mode: 0644]
target/classes/com/dtrules/interpreter/operators/RXmlValueOps.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/AttributeInfo$Attrib.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/AttributeInfo.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/DataMap$XmlLoader.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/DataMap.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/DataObjectMap.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/EntityInfo.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/LoadDatamapData.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/LoadMap.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/LoadMapping.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/LoadXMLData.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/MapGenerator.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/Mapping.class [new file with mode: 0644]
target/classes/com/dtrules/mapping/XMLTag.class [new file with mode: 0644]
target/classes/com/dtrules/session/DTState.class [new file with mode: 0644]
target/classes/com/dtrules/session/EDDLoader.class [new file with mode: 0644]
target/classes/com/dtrules/session/EntityFactory.class [new file with mode: 0644]
target/classes/com/dtrules/session/ICompiler.class [new file with mode: 0644]
target/classes/com/dtrules/session/ICompilerError$Type.class [new file with mode: 0644]
target/classes/com/dtrules/session/ICompilerError.class [new file with mode: 0644]
target/classes/com/dtrules/session/IRSession.class [new file with mode: 0644]
target/classes/com/dtrules/session/RSession.class [new file with mode: 0644]
target/classes/com/dtrules/session/RuleSet.class [new file with mode: 0644]
target/classes/com/dtrules/session/RulesDirectory$LoadDirectory.class [new file with mode: 0644]
target/classes/com/dtrules/session/RulesDirectory.class [new file with mode: 0644]
target/classes/com/dtrules/trace/DecisionTableNode.class [new file with mode: 0644]
target/classes/com/dtrules/trace/TraceNode.class [new file with mode: 0644]
target/classes/com/dtrules/xmlparser/GenericXMLParser.class [new file with mode: 0644]
target/classes/com/dtrules/xmlparser/IGenericXMLParser.class [new file with mode: 0644]
target/classes/com/dtrules/xmlparser/IXMLPrinter.class [new file with mode: 0644]
target/classes/com/dtrules/xmlparser/XMLPrinter.class [new file with mode: 0644]
target/maven-archiver/pom.properties [new file with mode: 0644]

diff --git a/.classpath b/.classpath
new file mode 100644 (file)
index 0000000..f82b51e
--- /dev/null
@@ -0,0 +1,6 @@
+<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
diff --git a/.project b/.project
new file mode 100644 (file)
index 0000000..8ab58a1
--- /dev/null
+++ b/.project
@@ -0,0 +1,13 @@
+<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
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..31e06fb
--- /dev/null
@@ -0,0 +1,5 @@
+#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
diff --git a/.svn/dir-prop-base b/.svn/dir-prop-base
new file mode 100644 (file)
index 0000000..6786af4
--- /dev/null
@@ -0,0 +1,10 @@
+K 10
+svn:ignore
+V 47
+.settings
+target
+.classpath
+.project
+.git
+
+END
diff --git a/.svn/entries b/.svn/entries
new file mode 100644 (file)
index 0000000..45f4ece
--- /dev/null
@@ -0,0 +1,68 @@
+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
diff --git a/.svn/format b/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/.svn/text-base/pom.xml.svn-base b/.svn/text-base/pom.xml.svn-base
new file mode 100644 (file)
index 0000000..2f9df25
--- /dev/null
@@ -0,0 +1,19 @@
+<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
diff --git a/docs/.svn/entries b/docs/.svn/entries
new file mode 100644 (file)
index 0000000..54a62f0
--- /dev/null
@@ -0,0 +1,54 @@
+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
diff --git a/docs/.svn/format b/docs/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/docs/.svn/prop-base/DTRules.doc.svn-base b/docs/.svn/prop-base/DTRules.doc.svn-base
new file mode 100644 (file)
index 0000000..5e9587e
--- /dev/null
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/docs/.svn/prop-base/OperatorList.doc.svn-base b/docs/.svn/prop-base/OperatorList.doc.svn-base
new file mode 100644 (file)
index 0000000..5e9587e
--- /dev/null
@@ -0,0 +1,5 @@
+K 13
+svn:mime-type
+V 24
+application/octet-stream
+END
diff --git a/docs/.svn/text-base/DTRules.doc.svn-base b/docs/.svn/text-base/DTRules.doc.svn-base
new file mode 100644 (file)
index 0000000..13f7e45
Binary files /dev/null and b/docs/.svn/text-base/DTRules.doc.svn-base differ
diff --git a/docs/.svn/text-base/OperatorList.doc.svn-base b/docs/.svn/text-base/OperatorList.doc.svn-base
new file mode 100644 (file)
index 0000000..867e0ab
Binary files /dev/null and b/docs/.svn/text-base/OperatorList.doc.svn-base differ
diff --git a/docs/DTRules.doc b/docs/DTRules.doc
new file mode 100644 (file)
index 0000000..13f7e45
Binary files /dev/null and b/docs/DTRules.doc differ
diff --git a/docs/OperatorList.doc b/docs/OperatorList.doc
new file mode 100644 (file)
index 0000000..867e0ab
Binary files /dev/null and b/docs/OperatorList.doc differ
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..2f9df25
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,19 @@
+<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
diff --git a/src/.svn/entries b/src/.svn/entries
new file mode 100644 (file)
index 0000000..8b28ae5
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/src/.svn/format b/src/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/.svn/entries b/src/main/.svn/entries
new file mode 100644 (file)
index 0000000..1cf43a6
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/main/.svn/format b/src/main/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/.svn/entries b/src/main/java/.svn/entries
new file mode 100644 (file)
index 0000000..506e17b
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/main/java/.svn/format b/src/main/java/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/.svn/entries b/src/main/java/com/.svn/entries
new file mode 100644 (file)
index 0000000..d5a3c21
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/main/java/com/.svn/format b/src/main/java/com/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/.svn/entries b/src/main/java/com/dtrules/.svn/entries
new file mode 100644 (file)
index 0000000..d766100
--- /dev/null
@@ -0,0 +1,67 @@
+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
diff --git a/src/main/java/com/dtrules/.svn/format b/src/main/java/com/dtrules/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/.svn/text-base/App.java.svn-base b/src/main/java/com/dtrules/.svn/text-base/App.java.svn-base
new file mode 100644 (file)
index 0000000..e65a5fc
--- /dev/null
@@ -0,0 +1,13 @@
+package com.dtrules;
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/src/main/java/com/dtrules/App.java b/src/main/java/com/dtrules/App.java
new file mode 100644 (file)
index 0000000..e65a5fc
--- /dev/null
@@ -0,0 +1,13 @@
+package com.dtrules;
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}
diff --git a/src/main/java/com/dtrules/admin/.svn/entries b/src/main/java/com/dtrules/admin/.svn/entries
new file mode 100644 (file)
index 0000000..7cac700
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/src/main/java/com/dtrules/admin/.svn/format b/src/main/java/com/dtrules/admin/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/admin/.svn/text-base/IRulesAdminService.java.svn-base b/src/main/java/com/dtrules/admin/.svn/text-base/IRulesAdminService.java.svn-base
new file mode 100644 (file)
index 0000000..22fd985
--- /dev/null
@@ -0,0 +1,74 @@
+/*  
+ * 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);
+
+}
diff --git a/src/main/java/com/dtrules/admin/.svn/text-base/RulesAdminService.java.svn-base b/src/main/java/com/dtrules/admin/.svn/text-base/RulesAdminService.java.svn-base
new file mode 100644 (file)
index 0000000..379c824
--- /dev/null
@@ -0,0 +1,411 @@
+/*  
+ * 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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/admin/IRulesAdminService.java b/src/main/java/com/dtrules/admin/IRulesAdminService.java
new file mode 100644 (file)
index 0000000..22fd985
--- /dev/null
@@ -0,0 +1,74 @@
+/*  
+ * 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);
+
+}
diff --git a/src/main/java/com/dtrules/admin/RulesAdminService.java b/src/main/java/com/dtrules/admin/RulesAdminService.java
new file mode 100644 (file)
index 0000000..379c824
--- /dev/null
@@ -0,0 +1,411 @@
+/*  
+ * 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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/entries b/src/main/java/com/dtrules/decisiontables/.svn/entries
new file mode 100644 (file)
index 0000000..42803a9
--- /dev/null
@@ -0,0 +1,168 @@
+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
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/format b/src/main/java/com/dtrules/decisiontables/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/ANode.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/ANode.java.svn-base
new file mode 100644 (file)
index 0000000..9a48def
--- /dev/null
@@ -0,0 +1,188 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/BalanceTable.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/BalanceTable.java.svn-base
new file mode 100644 (file)
index 0000000..01ae6fc
--- /dev/null
@@ -0,0 +1,123 @@
+/*  
+ * 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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/CNode.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/CNode.java.svn-base
new file mode 100644 (file)
index 0000000..5ee3af9
--- /dev/null
@@ -0,0 +1,139 @@
+/*  
+ * $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);
+       }
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/CompilerError.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/CompilerError.java.svn-base
new file mode 100644 (file)
index 0000000..3c546ff
--- /dev/null
@@ -0,0 +1,115 @@
+/*  
+ * $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;
+    }
+   
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/DTLoader.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/DTLoader.java.svn-base
new file mode 100644 (file)
index 0000000..8b5751f
--- /dev/null
@@ -0,0 +1,420 @@
+/*  
+ * $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;
+       }
+       
+       
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/DTNode.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/DTNode.java.svn-base
new file mode 100644 (file)
index 0000000..f18eb93
--- /dev/null
@@ -0,0 +1,75 @@
+/*  
+ * $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();
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base
new file mode 100644 (file)
index 0000000..7351417
--- /dev/null
@@ -0,0 +1,176 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/.svn/text-base/RDecisionTable.java.svn-base b/src/main/java/com/dtrules/decisiontables/.svn/text-base/RDecisionTable.java.svn-base
new file mode 100644 (file)
index 0000000..07aa449
--- /dev/null
@@ -0,0 +1,1092 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/decisiontables/ANode.java b/src/main/java/com/dtrules/decisiontables/ANode.java
new file mode 100644 (file)
index 0000000..9a48def
--- /dev/null
@@ -0,0 +1,188 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/BalanceTable.java b/src/main/java/com/dtrules/decisiontables/BalanceTable.java
new file mode 100644 (file)
index 0000000..01ae6fc
--- /dev/null
@@ -0,0 +1,123 @@
+/*  
+ * 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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/CNode.java b/src/main/java/com/dtrules/decisiontables/CNode.java
new file mode 100644 (file)
index 0000000..5ee3af9
--- /dev/null
@@ -0,0 +1,139 @@
+/*  
+ * $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);
+       }
+}
diff --git a/src/main/java/com/dtrules/decisiontables/CompilerError.java b/src/main/java/com/dtrules/decisiontables/CompilerError.java
new file mode 100644 (file)
index 0000000..3c546ff
--- /dev/null
@@ -0,0 +1,115 @@
+/*  
+ * $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;
+    }
+   
+}
diff --git a/src/main/java/com/dtrules/decisiontables/DTLoader.java b/src/main/java/com/dtrules/decisiontables/DTLoader.java
new file mode 100644 (file)
index 0000000..8b5751f
--- /dev/null
@@ -0,0 +1,420 @@
+/*  
+ * $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;
+       }
+       
+       
+}
diff --git a/src/main/java/com/dtrules/decisiontables/DTNode.java b/src/main/java/com/dtrules/decisiontables/DTNode.java
new file mode 100644 (file)
index 0000000..f18eb93
--- /dev/null
@@ -0,0 +1,75 @@
+/*  
+ * $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();
+}
diff --git a/src/main/java/com/dtrules/decisiontables/DecisionTableTypeTest.java b/src/main/java/com/dtrules/decisiontables/DecisionTableTypeTest.java
new file mode 100644 (file)
index 0000000..7351417
--- /dev/null
@@ -0,0 +1,176 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/decisiontables/RDecisionTable.java b/src/main/java/com/dtrules/decisiontables/RDecisionTable.java
new file mode 100644 (file)
index 0000000..07aa449
--- /dev/null
@@ -0,0 +1,1092 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/entity/.svn/entries b/src/main/java/com/dtrules/entity/.svn/entries
new file mode 100644 (file)
index 0000000..3ef995a
--- /dev/null
@@ -0,0 +1,64 @@
+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
diff --git a/src/main/java/com/dtrules/entity/.svn/format b/src/main/java/com/dtrules/entity/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/entity/.svn/text-base/IREntity.java.svn-base b/src/main/java/com/dtrules/entity/.svn/text-base/IREntity.java.svn-base
new file mode 100644 (file)
index 0000000..e039e17
--- /dev/null
@@ -0,0 +1,158 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/entity/.svn/text-base/REntity.java.svn-base b/src/main/java/com/dtrules/entity/.svn/text-base/REntity.java.svn-base
new file mode 100644 (file)
index 0000000..ea6d041
--- /dev/null
@@ -0,0 +1,357 @@
+/*  
+ * $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>");
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/entity/.svn/text-base/REntityEntry.java.svn-base b/src/main/java/com/dtrules/entity/.svn/text-base/REntityEntry.java.svn-base
new file mode 100644 (file)
index 0000000..707412a
--- /dev/null
@@ -0,0 +1,195 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/entity/IREntity.java b/src/main/java/com/dtrules/entity/IREntity.java
new file mode 100644 (file)
index 0000000..e039e17
--- /dev/null
@@ -0,0 +1,158 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/entity/REntity.java b/src/main/java/com/dtrules/entity/REntity.java
new file mode 100644 (file)
index 0000000..ea6d041
--- /dev/null
@@ -0,0 +1,357 @@
+/*  
+ * $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>");
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/entity/REntityEntry.java b/src/main/java/com/dtrules/entity/REntityEntry.java
new file mode 100644 (file)
index 0000000..707412a
--- /dev/null
@@ -0,0 +1,195 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/infrastructure/.svn/entries b/src/main/java/com/dtrules/infrastructure/.svn/entries
new file mode 100644 (file)
index 0000000..44e3187
--- /dev/null
@@ -0,0 +1,40 @@
+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
diff --git a/src/main/java/com/dtrules/infrastructure/.svn/format b/src/main/java/com/dtrules/infrastructure/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/infrastructure/.svn/text-base/RulesException.java.svn-base b/src/main/java/com/dtrules/infrastructure/.svn/text-base/RulesException.java.svn-base
new file mode 100644 (file)
index 0000000..781d4a4
--- /dev/null
@@ -0,0 +1,115 @@
+/*  
+ * $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;
+    }
+
+    
+}
diff --git a/src/main/java/com/dtrules/infrastructure/RulesException.java b/src/main/java/com/dtrules/infrastructure/RulesException.java
new file mode 100644 (file)
index 0000000..781d4a4
--- /dev/null
@@ -0,0 +1,115 @@
+/*  
+ * $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;
+    }
+
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/entries b/src/main/java/com/dtrules/interpreter/.svn/entries
new file mode 100644 (file)
index 0000000..1eadec4
--- /dev/null
@@ -0,0 +1,277 @@
+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
diff --git a/src/main/java/com/dtrules/interpreter/.svn/format b/src/main/java/com/dtrules/interpreter/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/ARObject.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/ARObject.java.svn-base
new file mode 100644 (file)
index 0000000..ab3fe7f
--- /dev/null
@@ -0,0 +1,169 @@
+/*  
+ * $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);
+    }    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/IRObject.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/IRObject.java.svn-base
new file mode 100644 (file)
index 0000000..e8ae333
--- /dev/null
@@ -0,0 +1,128 @@
+/*  
+ * $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;
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RArray.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RArray.java.svn-base
new file mode 100644 (file)
index 0000000..232fdfe
--- /dev/null
@@ -0,0 +1,271 @@
+/*  
+ * $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();
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RBoolean.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RBoolean.java.svn-base
new file mode 100644 (file)
index 0000000..5332ea2
--- /dev/null
@@ -0,0 +1,121 @@
+/*  
+ * $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();
+       }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RDouble.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RDouble.java.svn-base
new file mode 100644 (file)
index 0000000..ee8ef3c
--- /dev/null
@@ -0,0 +1,127 @@
+/*  
+ * $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);
+    }
+
+       
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RInteger.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RInteger.java.svn-base
new file mode 100644 (file)
index 0000000..1092059
--- /dev/null
@@ -0,0 +1,121 @@
+/*  
+ * $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);     
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RMark.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RMark.java.svn-base
new file mode 100644 (file)
index 0000000..2aed9de
--- /dev/null
@@ -0,0 +1,44 @@
+/*  
+ * $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;
+    }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RName.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RName.java.svn-base
new file mode 100644 (file)
index 0000000..2da35ba
--- /dev/null
@@ -0,0 +1,259 @@
+/*  
+ * $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);
+       }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RNull.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RNull.java.svn-base
new file mode 100644 (file)
index 0000000..ff95d94
--- /dev/null
@@ -0,0 +1,85 @@
+/*  
+ * $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;
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RString.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RString.java.svn-base
new file mode 100644 (file)
index 0000000..debdb8e
--- /dev/null
@@ -0,0 +1,312 @@
+/*  
+ * $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());
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RTable.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RTable.java.svn-base
new file mode 100644 (file)
index 0000000..b3cd468
--- /dev/null
@@ -0,0 +1,237 @@
+/*  
+ * 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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RTime.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RTime.java.svn-base
new file mode 100644 (file)
index 0000000..5952863
--- /dev/null
@@ -0,0 +1,147 @@
+/*  
+ * $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());
+       }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/RXmlValue.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/RXmlValue.java.svn-base
new file mode 100644 (file)
index 0000000..6004ca8
--- /dev/null
@@ -0,0 +1,154 @@
+/**
+ * 
+ */
+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;
+    }
+
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/SimpleTokenizer.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/SimpleTokenizer.java.svn-base
new file mode 100644 (file)
index 0000000..164b31a
--- /dev/null
@@ -0,0 +1,136 @@
+/*  
+ * $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));
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/.svn/text-base/Token.java.svn-base b/src/main/java/com/dtrules/interpreter/.svn/text-base/Token.java.svn-base
new file mode 100644 (file)
index 0000000..520e846
--- /dev/null
@@ -0,0 +1,99 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/ARObject.java b/src/main/java/com/dtrules/interpreter/ARObject.java
new file mode 100644 (file)
index 0000000..ab3fe7f
--- /dev/null
@@ -0,0 +1,169 @@
+/*  
+ * $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);
+    }    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/IRObject.java b/src/main/java/com/dtrules/interpreter/IRObject.java
new file mode 100644 (file)
index 0000000..e8ae333
--- /dev/null
@@ -0,0 +1,128 @@
+/*  
+ * $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;
+}
diff --git a/src/main/java/com/dtrules/interpreter/RArray.java b/src/main/java/com/dtrules/interpreter/RArray.java
new file mode 100644 (file)
index 0000000..232fdfe
--- /dev/null
@@ -0,0 +1,271 @@
+/*  
+ * $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();
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/RBoolean.java b/src/main/java/com/dtrules/interpreter/RBoolean.java
new file mode 100644 (file)
index 0000000..5332ea2
--- /dev/null
@@ -0,0 +1,121 @@
+/*  
+ * $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();
+       }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/RDouble.java b/src/main/java/com/dtrules/interpreter/RDouble.java
new file mode 100644 (file)
index 0000000..ee8ef3c
--- /dev/null
@@ -0,0 +1,127 @@
+/*  
+ * $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);
+    }
+
+       
+}
diff --git a/src/main/java/com/dtrules/interpreter/RInteger.java b/src/main/java/com/dtrules/interpreter/RInteger.java
new file mode 100644 (file)
index 0000000..1092059
--- /dev/null
@@ -0,0 +1,121 @@
+/*  
+ * $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);     
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/RMark.java b/src/main/java/com/dtrules/interpreter/RMark.java
new file mode 100644 (file)
index 0000000..2aed9de
--- /dev/null
@@ -0,0 +1,44 @@
+/*  
+ * $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;
+    }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/RName.java b/src/main/java/com/dtrules/interpreter/RName.java
new file mode 100644 (file)
index 0000000..2da35ba
--- /dev/null
@@ -0,0 +1,259 @@
+/*  
+ * $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);
+       }
+
+}
diff --git a/src/main/java/com/dtrules/interpreter/RNull.java b/src/main/java/com/dtrules/interpreter/RNull.java
new file mode 100644 (file)
index 0000000..ff95d94
--- /dev/null
@@ -0,0 +1,85 @@
+/*  
+ * $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;
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/RString.java b/src/main/java/com/dtrules/interpreter/RString.java
new file mode 100644 (file)
index 0000000..debdb8e
--- /dev/null
@@ -0,0 +1,312 @@
+/*  
+ * $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());
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/RTable.java b/src/main/java/com/dtrules/interpreter/RTable.java
new file mode 100644 (file)
index 0000000..b3cd468
--- /dev/null
@@ -0,0 +1,237 @@
+/*  
+ * 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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/RTime.java b/src/main/java/com/dtrules/interpreter/RTime.java
new file mode 100644 (file)
index 0000000..5952863
--- /dev/null
@@ -0,0 +1,147 @@
+/*  
+ * $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());
+       }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/RXmlValue.java b/src/main/java/com/dtrules/interpreter/RXmlValue.java
new file mode 100644 (file)
index 0000000..6004ca8
--- /dev/null
@@ -0,0 +1,154 @@
+/**
+ * 
+ */
+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;
+    }
+
+    
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/SimpleTokenizer.java b/src/main/java/com/dtrules/interpreter/SimpleTokenizer.java
new file mode 100644 (file)
index 0000000..164b31a
--- /dev/null
@@ -0,0 +1,136 @@
+/*  
+ * $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));
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/interpreter/Token.java b/src/main/java/com/dtrules/interpreter/Token.java
new file mode 100644 (file)
index 0000000..520e846
--- /dev/null
@@ -0,0 +1,99 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/entries b/src/main/java/com/dtrules/interpreter/operators/.svn/entries
new file mode 100644 (file)
index 0000000..1bcce0c
--- /dev/null
@@ -0,0 +1,180 @@
+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
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/format b/src/main/java/com/dtrules/interpreter/operators/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RArrayOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RArrayOps.java.svn-base
new file mode 100644 (file)
index 0000000..c0d88dd
--- /dev/null
@@ -0,0 +1,480 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RBooleanOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RBooleanOps.java.svn-base
new file mode 100644 (file)
index 0000000..b606eb9
--- /dev/null
@@ -0,0 +1,407 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RControl.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RControl.java.svn-base
new file mode 100644 (file)
index 0000000..2affe69
--- /dev/null
@@ -0,0 +1,432 @@
+/*  
+ * $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);
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RDateTimeOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RDateTimeOps.java.svn-base
new file mode 100644 (file)
index 0000000..fa0f5d0
--- /dev/null
@@ -0,0 +1,457 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMath.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMath.java.svn-base
new file mode 100644 (file)
index 0000000..d5e7868
--- /dev/null
@@ -0,0 +1,301 @@
+/*  
+ * $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));
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMiscOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RMiscOps.java.svn-base
new file mode 100644 (file)
index 0000000..4d9e84a
--- /dev/null
@@ -0,0 +1,742 @@
+/*  
+ * $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));
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/ROperator.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/ROperator.java.svn-base
new file mode 100644 (file)
index 0000000..618c467
--- /dev/null
@@ -0,0 +1,124 @@
+/*  
+ * $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();
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RTableOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RTableOps.java.svn-base
new file mode 100644 (file)
index 0000000..6c2cbfd
--- /dev/null
@@ -0,0 +1,166 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RXmlValueOps.java.svn-base b/src/main/java/com/dtrules/interpreter/operators/.svn/text-base/RXmlValueOps.java.svn-base
new file mode 100644 (file)
index 0000000..43bed6c
--- /dev/null
@@ -0,0 +1,81 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/RArrayOps.java b/src/main/java/com/dtrules/interpreter/operators/RArrayOps.java
new file mode 100644 (file)
index 0000000..c0d88dd
--- /dev/null
@@ -0,0 +1,480 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/RBooleanOps.java b/src/main/java/com/dtrules/interpreter/operators/RBooleanOps.java
new file mode 100644 (file)
index 0000000..b606eb9
--- /dev/null
@@ -0,0 +1,407 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/RControl.java b/src/main/java/com/dtrules/interpreter/operators/RControl.java
new file mode 100644 (file)
index 0000000..2affe69
--- /dev/null
@@ -0,0 +1,432 @@
+/*  
+ * $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);
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/RDateTimeOps.java b/src/main/java/com/dtrules/interpreter/operators/RDateTimeOps.java
new file mode 100644 (file)
index 0000000..fa0f5d0
--- /dev/null
@@ -0,0 +1,457 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/RMath.java b/src/main/java/com/dtrules/interpreter/operators/RMath.java
new file mode 100644 (file)
index 0000000..d5e7868
--- /dev/null
@@ -0,0 +1,301 @@
+/*  
+ * $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));
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/RMiscOps.java b/src/main/java/com/dtrules/interpreter/operators/RMiscOps.java
new file mode 100644 (file)
index 0000000..4d9e84a
--- /dev/null
@@ -0,0 +1,742 @@
+/*  
+ * $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));
+        }
+    }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/ROperator.java b/src/main/java/com/dtrules/interpreter/operators/ROperator.java
new file mode 100644 (file)
index 0000000..618c467
--- /dev/null
@@ -0,0 +1,124 @@
+/*  
+ * $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();
+       }
+}
diff --git a/src/main/java/com/dtrules/interpreter/operators/RTableOps.java b/src/main/java/com/dtrules/interpreter/operators/RTableOps.java
new file mode 100644 (file)
index 0000000..6c2cbfd
--- /dev/null
@@ -0,0 +1,166 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/interpreter/operators/RXmlValueOps.java b/src/main/java/com/dtrules/interpreter/operators/RXmlValueOps.java
new file mode 100644 (file)
index 0000000..43bed6c
--- /dev/null
@@ -0,0 +1,81 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/.svn/entries b/src/main/java/com/dtrules/mapping/.svn/entries
new file mode 100644 (file)
index 0000000..ac4d13d
--- /dev/null
@@ -0,0 +1,270 @@
+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
diff --git a/src/main/java/com/dtrules/mapping/.svn/format b/src/main/java/com/dtrules/mapping/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/AttributeInfo.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/AttributeInfo.java.svn-base
new file mode 100644 (file)
index 0000000..bc9a75c
--- /dev/null
@@ -0,0 +1,186 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/DataMap.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/DataMap.java.svn-base
new file mode 100644 (file)
index 0000000..b283b60
--- /dev/null
@@ -0,0 +1,541 @@
+/*  
+ * $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());
+        }
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/DataObjectMap.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/DataObjectMap.java.svn-base
new file mode 100644 (file)
index 0000000..130b638
--- /dev/null
@@ -0,0 +1,161 @@
+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;
+    }
+}
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/EntityInfo.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/EntityInfo.java.svn-base
new file mode 100644 (file)
index 0000000..cafd54e
--- /dev/null
@@ -0,0 +1,57 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/LoadDatamapData.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/LoadDatamapData.java.svn-base
new file mode 100644 (file)
index 0000000..9816a13
--- /dev/null
@@ -0,0 +1,229 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/LoadMap.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/LoadMap.java.svn-base
new file mode 100644 (file)
index 0000000..f4c51d7
--- /dev/null
@@ -0,0 +1,321 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/LoadMapping.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/LoadMapping.java.svn-base
new file mode 100644 (file)
index 0000000..66176d3
--- /dev/null
@@ -0,0 +1,368 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/LoadXMLData.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/LoadXMLData.java.svn-base
new file mode 100644 (file)
index 0000000..9710d3c
--- /dev/null
@@ -0,0 +1,368 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/MapGenerator.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/MapGenerator.java.svn-base
new file mode 100644 (file)
index 0000000..c278f64
--- /dev/null
@@ -0,0 +1,217 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/Mapping.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/Mapping.java.svn-base
new file mode 100644 (file)
index 0000000..0f81b97
--- /dev/null
@@ -0,0 +1,287 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/mapping/.svn/text-base/XMLTag.java.svn-base b/src/main/java/com/dtrules/mapping/.svn/text-base/XMLTag.java.svn-base
new file mode 100644 (file)
index 0000000..b36af14
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * 
+ */
+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
diff --git a/src/main/java/com/dtrules/mapping/AttributeInfo.java b/src/main/java/com/dtrules/mapping/AttributeInfo.java
new file mode 100644 (file)
index 0000000..bc9a75c
--- /dev/null
@@ -0,0 +1,186 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/DataMap.java b/src/main/java/com/dtrules/mapping/DataMap.java
new file mode 100644 (file)
index 0000000..b283b60
--- /dev/null
@@ -0,0 +1,541 @@
+/*  
+ * $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());
+        }
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/mapping/DataObjectMap.java b/src/main/java/com/dtrules/mapping/DataObjectMap.java
new file mode 100644 (file)
index 0000000..130b638
--- /dev/null
@@ -0,0 +1,161 @@
+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;
+    }
+}
diff --git a/src/main/java/com/dtrules/mapping/EntityInfo.java b/src/main/java/com/dtrules/mapping/EntityInfo.java
new file mode 100644 (file)
index 0000000..cafd54e
--- /dev/null
@@ -0,0 +1,57 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/LoadDatamapData.java b/src/main/java/com/dtrules/mapping/LoadDatamapData.java
new file mode 100644 (file)
index 0000000..9816a13
--- /dev/null
@@ -0,0 +1,229 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/LoadMap.java b/src/main/java/com/dtrules/mapping/LoadMap.java
new file mode 100644 (file)
index 0000000..f4c51d7
--- /dev/null
@@ -0,0 +1,321 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/mapping/LoadMapping.java b/src/main/java/com/dtrules/mapping/LoadMapping.java
new file mode 100644 (file)
index 0000000..66176d3
--- /dev/null
@@ -0,0 +1,368 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/LoadXMLData.java b/src/main/java/com/dtrules/mapping/LoadXMLData.java
new file mode 100644 (file)
index 0000000..9710d3c
--- /dev/null
@@ -0,0 +1,368 @@
+/*  
+ * $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;
+       }
+
+       
+       }
diff --git a/src/main/java/com/dtrules/mapping/MapGenerator.java b/src/main/java/com/dtrules/mapping/MapGenerator.java
new file mode 100644 (file)
index 0000000..c278f64
--- /dev/null
@@ -0,0 +1,217 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/mapping/Mapping.java b/src/main/java/com/dtrules/mapping/Mapping.java
new file mode 100644 (file)
index 0000000..0f81b97
--- /dev/null
@@ -0,0 +1,287 @@
+/*  
+ * $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;
+    }
+    
+    
+}
diff --git a/src/main/java/com/dtrules/mapping/XMLTag.java b/src/main/java/com/dtrules/mapping/XMLTag.java
new file mode 100644 (file)
index 0000000..b36af14
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * 
+ */
+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
diff --git a/src/main/java/com/dtrules/session/.svn/entries b/src/main/java/com/dtrules/session/.svn/entries
new file mode 100644 (file)
index 0000000..6522a4a
--- /dev/null
@@ -0,0 +1,224 @@
+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
diff --git a/src/main/java/com/dtrules/session/.svn/format b/src/main/java/com/dtrules/session/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/DTState.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/DTState.java.svn-base
new file mode 100644 (file)
index 0000000..7150912
--- /dev/null
@@ -0,0 +1,704 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/EDDLoader.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/EDDLoader.java.svn-base
new file mode 100644 (file)
index 0000000..51df3ea
--- /dev/null
@@ -0,0 +1,146 @@
+/*  
+ * $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;
+       }
+
+}
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/EntityFactory.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/EntityFactory.java.svn-base
new file mode 100644 (file)
index 0000000..deb11e8
--- /dev/null
@@ -0,0 +1,322 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/ICompiler.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/ICompiler.java.svn-base
new file mode 100644 (file)
index 0000000..3fc1943
--- /dev/null
@@ -0,0 +1,90 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/ICompilerError.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/ICompilerError.java.svn-base
new file mode 100644 (file)
index 0000000..b445e1c
--- /dev/null
@@ -0,0 +1,90 @@
+/*  
+ * $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();
+   
+}
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/IRSession.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/IRSession.java.svn-base
new file mode 100644 (file)
index 0000000..729a18a
--- /dev/null
@@ -0,0 +1,100 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/RSession.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/RSession.java.svn-base
new file mode 100644 (file)
index 0000000..a869846
--- /dev/null
@@ -0,0 +1,449 @@
+/*  
+ * $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);
+        }
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/RuleSet.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/RuleSet.java.svn-base
new file mode 100644 (file)
index 0000000..9c24c9b
--- /dev/null
@@ -0,0 +1,387 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/.svn/text-base/RulesDirectory.java.svn-base b/src/main/java/com/dtrules/session/.svn/text-base/RulesDirectory.java.svn-base
new file mode 100644 (file)
index 0000000..3ee92a9
--- /dev/null
@@ -0,0 +1,242 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/session/DTState.java b/src/main/java/com/dtrules/session/DTState.java
new file mode 100644 (file)
index 0000000..7150912
--- /dev/null
@@ -0,0 +1,704 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/session/EDDLoader.java b/src/main/java/com/dtrules/session/EDDLoader.java
new file mode 100644 (file)
index 0000000..51df3ea
--- /dev/null
@@ -0,0 +1,146 @@
+/*  
+ * $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;
+       }
+
+}
diff --git a/src/main/java/com/dtrules/session/EntityFactory.java b/src/main/java/com/dtrules/session/EntityFactory.java
new file mode 100644 (file)
index 0000000..deb11e8
--- /dev/null
@@ -0,0 +1,322 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/main/java/com/dtrules/session/ICompiler.java b/src/main/java/com/dtrules/session/ICompiler.java
new file mode 100644 (file)
index 0000000..3fc1943
--- /dev/null
@@ -0,0 +1,90 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/ICompilerError.java b/src/main/java/com/dtrules/session/ICompilerError.java
new file mode 100644 (file)
index 0000000..b445e1c
--- /dev/null
@@ -0,0 +1,90 @@
+/*  
+ * $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();
+   
+}
diff --git a/src/main/java/com/dtrules/session/IRSession.java b/src/main/java/com/dtrules/session/IRSession.java
new file mode 100644 (file)
index 0000000..729a18a
--- /dev/null
@@ -0,0 +1,100 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/RSession.java b/src/main/java/com/dtrules/session/RSession.java
new file mode 100644 (file)
index 0000000..a869846
--- /dev/null
@@ -0,0 +1,449 @@
+/*  
+ * $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);
+        }
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/session/RuleSet.java b/src/main/java/com/dtrules/session/RuleSet.java
new file mode 100644 (file)
index 0000000..9c24c9b
--- /dev/null
@@ -0,0 +1,387 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/session/RulesDirectory.java b/src/main/java/com/dtrules/session/RulesDirectory.java
new file mode 100644 (file)
index 0000000..3ee92a9
--- /dev/null
@@ -0,0 +1,242 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/trace/.svn/entries b/src/main/java/com/dtrules/trace/.svn/entries
new file mode 100644 (file)
index 0000000..de2d019
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/src/main/java/com/dtrules/trace/.svn/format b/src/main/java/com/dtrules/trace/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/trace/.svn/text-base/DecisionTableNode.java.svn-base b/src/main/java/com/dtrules/trace/.svn/text-base/DecisionTableNode.java.svn-base
new file mode 100644 (file)
index 0000000..443b9ef
--- /dev/null
@@ -0,0 +1,79 @@
+/*  
+ * 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
+
+    }
+
+}
diff --git a/src/main/java/com/dtrules/trace/.svn/text-base/TraceNode.java.svn-base b/src/main/java/com/dtrules/trace/.svn/text-base/TraceNode.java.svn-base
new file mode 100644 (file)
index 0000000..826ce5d
--- /dev/null
@@ -0,0 +1,94 @@
+/*  
+ * $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();
+}
diff --git a/src/main/java/com/dtrules/trace/DecisionTableNode.java b/src/main/java/com/dtrules/trace/DecisionTableNode.java
new file mode 100644 (file)
index 0000000..443b9ef
--- /dev/null
@@ -0,0 +1,79 @@
+/*  
+ * 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
+
+    }
+
+}
diff --git a/src/main/java/com/dtrules/trace/TraceNode.java b/src/main/java/com/dtrules/trace/TraceNode.java
new file mode 100644 (file)
index 0000000..826ce5d
--- /dev/null
@@ -0,0 +1,94 @@
+/*  
+ * $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();
+}
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/entries b/src/main/java/com/dtrules/xmlparser/.svn/entries
new file mode 100644 (file)
index 0000000..9cf88a5
--- /dev/null
@@ -0,0 +1,144 @@
+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
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/format b/src/main/java/com/dtrules/xmlparser/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.flex.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.flex.svn-base
new file mode 100644 (file)
index 0000000..657458f
--- /dev/null
@@ -0,0 +1,311 @@
+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("&amp;"); 
+    static private Pattern xlt = Pattern.compile("&lt;"); 
+    static private Pattern xgt = Pattern.compile("&gt;"); 
+    static private Pattern xsqu = Pattern.compile("&apos;");
+    static private Pattern xdqu = Pattern.compile("&quot;"); 
+
+     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("&amp;");
+             s= lt.matcher(s).replaceAll("&lt;");
+             s= gt.matcher(s).replaceAll("&gt;");
+             s= squ.matcher(s).replaceAll("&apos;");
+             s= dqu.matcher(s).replaceAll("&quot;");
+         }
+        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()); }
+
+}
+
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.java.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/GenericXMLParser.java.svn-base
new file mode 100644 (file)
index 0000000..b2d9e57
--- /dev/null
@@ -0,0 +1,874 @@
+/* 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("&amp;"); 
+    static private Pattern xlt = Pattern.compile("&lt;"); 
+    static private Pattern xgt = Pattern.compile("&gt;"); 
+    static private Pattern xsqu = Pattern.compile("&apos;");
+    static private Pattern xdqu = Pattern.compile("&quot;"); 
+
+     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("&amp;");
+             s= lt.matcher(s).replaceAll("&lt;");
+             s= gt.matcher(s).replaceAll("&gt;");
+             s= squ.matcher(s).replaceAll("&apos;");
+             s= dqu.matcher(s).replaceAll("&quot;");
+         }
+        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);
+          }
+      }
+    }
+  }
+
+
+}
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/IGenericXMLParser.java.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/IGenericXMLParser.java.svn-base
new file mode 100644 (file)
index 0000000..a57d880
--- /dev/null
@@ -0,0 +1,98 @@
+/*  
+ * $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.
+}
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/IXMLPrinter.java.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/IXMLPrinter.java.svn-base
new file mode 100644 (file)
index 0000000..07ee9db
--- /dev/null
@@ -0,0 +1,171 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/XMLPrinter.java.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/XMLPrinter.java.svn-base
new file mode 100644 (file)
index 0000000..5b223e9
--- /dev/null
@@ -0,0 +1,535 @@
+/*  
+ * $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();
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/xmlparser/.svn/text-base/compileGenericXMLParser.bat.svn-base b/src/main/java/com/dtrules/xmlparser/.svn/text-base/compileGenericXMLParser.bat.svn-base
new file mode 100644 (file)
index 0000000..5f60cb3
--- /dev/null
@@ -0,0 +1,6 @@
+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
diff --git a/src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex b/src/main/java/com/dtrules/xmlparser/GenericXMLParser.flex
new file mode 100644 (file)
index 0000000..657458f
--- /dev/null
@@ -0,0 +1,311 @@
+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("&amp;"); 
+    static private Pattern xlt = Pattern.compile("&lt;"); 
+    static private Pattern xgt = Pattern.compile("&gt;"); 
+    static private Pattern xsqu = Pattern.compile("&apos;");
+    static private Pattern xdqu = Pattern.compile("&quot;"); 
+
+     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("&amp;");
+             s= lt.matcher(s).replaceAll("&lt;");
+             s= gt.matcher(s).replaceAll("&gt;");
+             s= squ.matcher(s).replaceAll("&apos;");
+             s= dqu.matcher(s).replaceAll("&quot;");
+         }
+        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()); }
+
+}
+
diff --git a/src/main/java/com/dtrules/xmlparser/GenericXMLParser.java b/src/main/java/com/dtrules/xmlparser/GenericXMLParser.java
new file mode 100644 (file)
index 0000000..b2d9e57
--- /dev/null
@@ -0,0 +1,874 @@
+/* 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("&amp;"); 
+    static private Pattern xlt = Pattern.compile("&lt;"); 
+    static private Pattern xgt = Pattern.compile("&gt;"); 
+    static private Pattern xsqu = Pattern.compile("&apos;");
+    static private Pattern xdqu = Pattern.compile("&quot;"); 
+
+     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("&amp;");
+             s= lt.matcher(s).replaceAll("&lt;");
+             s= gt.matcher(s).replaceAll("&gt;");
+             s= squ.matcher(s).replaceAll("&apos;");
+             s= dqu.matcher(s).replaceAll("&quot;");
+         }
+        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);
+          }
+      }
+    }
+  }
+
+
+}
diff --git a/src/main/java/com/dtrules/xmlparser/GenericXMLParser.java~ b/src/main/java/com/dtrules/xmlparser/GenericXMLParser.java~
new file mode 100644 (file)
index 0000000..b8b0fa8
--- /dev/null
@@ -0,0 +1,874 @@
+/* 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("&amp;"); 
+    static private Pattern xlt = Pattern.compile("&lt;"); 
+    static private Pattern xgt = Pattern.compile("&gt;"); 
+    static private Pattern xsqu = Pattern.compile("&apos;");
+    static private Pattern xdqu = Pattern.compile("&quot;"); 
+
+     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("&amp;");
+             s= lt.matcher(s).replaceAll("&lt;");
+             s= gt.matcher(s).replaceAll("&gt;");
+             s= squ.matcher(s).replaceAll("&apos;");
+             s= dqu.matcher(s).replaceAll("&quot;");
+         }
+        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);
+          }
+      }
+    }
+  }
+
+
+}
diff --git a/src/main/java/com/dtrules/xmlparser/IGenericXMLParser.java b/src/main/java/com/dtrules/xmlparser/IGenericXMLParser.java
new file mode 100644 (file)
index 0000000..a57d880
--- /dev/null
@@ -0,0 +1,98 @@
+/*  
+ * $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.
+}
diff --git a/src/main/java/com/dtrules/xmlparser/IXMLPrinter.java b/src/main/java/com/dtrules/xmlparser/IXMLPrinter.java
new file mode 100644 (file)
index 0000000..07ee9db
--- /dev/null
@@ -0,0 +1,171 @@
+/*  
+ * $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
diff --git a/src/main/java/com/dtrules/xmlparser/XMLPrinter.java b/src/main/java/com/dtrules/xmlparser/XMLPrinter.java
new file mode 100644 (file)
index 0000000..5b223e9
--- /dev/null
@@ -0,0 +1,535 @@
+/*  
+ * $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();
+    }
+    
+}
diff --git a/src/main/java/com/dtrules/xmlparser/compileGenericXMLParser.bat b/src/main/java/com/dtrules/xmlparser/compileGenericXMLParser.bat
new file mode 100644 (file)
index 0000000..5f60cb3
--- /dev/null
@@ -0,0 +1,6 @@
+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
diff --git a/src/test/.svn/entries b/src/test/.svn/entries
new file mode 100644 (file)
index 0000000..235d7f2
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/test/.svn/format b/src/test/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/.svn/entries b/src/test/com/.svn/entries
new file mode 100644 (file)
index 0000000..5722ea1
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/test/com/.svn/format b/src/test/com/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/.svn/entries b/src/test/com/dtrules/.svn/entries
new file mode 100644 (file)
index 0000000..3927146
--- /dev/null
@@ -0,0 +1,46 @@
+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
diff --git a/src/test/com/dtrules/.svn/format b/src/test/com/dtrules/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/admin/.svn/entries b/src/test/com/dtrules/admin/.svn/entries
new file mode 100644 (file)
index 0000000..492cc11
--- /dev/null
@@ -0,0 +1,40 @@
+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
diff --git a/src/test/com/dtrules/admin/.svn/format b/src/test/com/dtrules/admin/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/admin/.svn/text-base/RulesAdminServiceTest.java.svn-base b/src/test/com/dtrules/admin/.svn/text-base/RulesAdminServiceTest.java.svn-base
new file mode 100644 (file)
index 0000000..0bf4be8
--- /dev/null
@@ -0,0 +1,55 @@
+/*  
+ * $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
+       }
+
+}
diff --git a/src/test/com/dtrules/admin/RulesAdminServiceTest.java b/src/test/com/dtrules/admin/RulesAdminServiceTest.java
new file mode 100644 (file)
index 0000000..0bf4be8
--- /dev/null
@@ -0,0 +1,55 @@
+/*  
+ * $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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/.svn/entries b/src/test/com/dtrules/decisiontables/.svn/entries
new file mode 100644 (file)
index 0000000..09f41e5
--- /dev/null
@@ -0,0 +1,88 @@
+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
diff --git a/src/test/com/dtrules/decisiontables/.svn/format b/src/test/com/dtrules/decisiontables/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/decisiontables/.svn/text-base/ANodeTest.java.svn-base b/src/test/com/dtrules/decisiontables/.svn/text-base/ANodeTest.java.svn-base
new file mode 100644 (file)
index 0000000..1da33d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/.svn/text-base/CNodeTest.java.svn-base b/src/test/com/dtrules/decisiontables/.svn/text-base/CNodeTest.java.svn-base
new file mode 100644 (file)
index 0000000..8bb2133
--- /dev/null
@@ -0,0 +1,78 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/.svn/text-base/DTLoaderTest.java.svn-base b/src/test/com/dtrules/decisiontables/.svn/text-base/DTLoaderTest.java.svn-base
new file mode 100644 (file)
index 0000000..23a2933
--- /dev/null
@@ -0,0 +1,211 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base b/src/test/com/dtrules/decisiontables/.svn/text-base/DecisionTableTypeTest.java.svn-base
new file mode 100644 (file)
index 0000000..ed2826a
--- /dev/null
@@ -0,0 +1,187 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/test/com/dtrules/decisiontables/.svn/text-base/RDecisionTableTest.java.svn-base b/src/test/com/dtrules/decisiontables/.svn/text-base/RDecisionTableTest.java.svn-base
new file mode 100644 (file)
index 0000000..0dfff07
--- /dev/null
@@ -0,0 +1,113 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/ANodeTest.java b/src/test/com/dtrules/decisiontables/ANodeTest.java
new file mode 100644 (file)
index 0000000..1da33d9
--- /dev/null
@@ -0,0 +1,67 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/CNodeTest.java b/src/test/com/dtrules/decisiontables/CNodeTest.java
new file mode 100644 (file)
index 0000000..8bb2133
--- /dev/null
@@ -0,0 +1,78 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/DTLoaderTest.java b/src/test/com/dtrules/decisiontables/DTLoaderTest.java
new file mode 100644 (file)
index 0000000..23a2933
--- /dev/null
@@ -0,0 +1,211 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/decisiontables/DecisionTableTypeTest.java b/src/test/com/dtrules/decisiontables/DecisionTableTypeTest.java
new file mode 100644 (file)
index 0000000..ed2826a
--- /dev/null
@@ -0,0 +1,187 @@
+/*  
+ * $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;
+    }
+    
+}
diff --git a/src/test/com/dtrules/decisiontables/RDecisionTableTest.java b/src/test/com/dtrules/decisiontables/RDecisionTableTest.java
new file mode 100644 (file)
index 0000000..0dfff07
--- /dev/null
@@ -0,0 +1,113 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/entity/.svn/entries b/src/test/com/dtrules/entity/.svn/entries
new file mode 100644 (file)
index 0000000..0263216
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/src/test/com/dtrules/entity/.svn/format b/src/test/com/dtrules/entity/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/entity/.svn/text-base/REntityEntryTest.java.svn-base b/src/test/com/dtrules/entity/.svn/text-base/REntityEntryTest.java.svn-base
new file mode 100644 (file)
index 0000000..fc3ae80
--- /dev/null
@@ -0,0 +1,62 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/entity/.svn/text-base/REntityTest.java.svn-base b/src/test/com/dtrules/entity/.svn/text-base/REntityTest.java.svn-base
new file mode 100644 (file)
index 0000000..cbb5a34
--- /dev/null
@@ -0,0 +1,340 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/entity/REntityEntryTest.java b/src/test/com/dtrules/entity/REntityEntryTest.java
new file mode 100644 (file)
index 0000000..fc3ae80
--- /dev/null
@@ -0,0 +1,62 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/entity/REntityTest.java b/src/test/com/dtrules/entity/REntityTest.java
new file mode 100644 (file)
index 0000000..cbb5a34
--- /dev/null
@@ -0,0 +1,340 @@
+/*  
+ * 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
+       }
+
+}
diff --git a/src/test/com/dtrules/interpreter/.svn/entries b/src/test/com/dtrules/interpreter/.svn/entries
new file mode 100644 (file)
index 0000000..7a3a619
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/src/test/com/dtrules/interpreter/.svn/format b/src/test/com/dtrules/interpreter/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/interpreter/operators/.svn/entries b/src/test/com/dtrules/interpreter/operators/.svn/entries
new file mode 100644 (file)
index 0000000..1326dc6
--- /dev/null
@@ -0,0 +1,40 @@
+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
diff --git a/src/test/com/dtrules/interpreter/operators/.svn/format b/src/test/com/dtrules/interpreter/operators/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/interpreter/operators/.svn/text-base/OperatorTest.java.svn-base b/src/test/com/dtrules/interpreter/operators/.svn/text-base/OperatorTest.java.svn-base
new file mode 100644 (file)
index 0000000..05ffae0
--- /dev/null
@@ -0,0 +1,139 @@
+/*  
+ * $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");
+            }
+        }    
+      }
+}
diff --git a/src/test/com/dtrules/interpreter/operators/OperatorTest.java b/src/test/com/dtrules/interpreter/operators/OperatorTest.java
new file mode 100644 (file)
index 0000000..05ffae0
--- /dev/null
@@ -0,0 +1,139 @@
+/*  
+ * $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");
+            }
+        }    
+      }
+}
diff --git a/src/test/com/dtrules/mapping/.svn/entries b/src/test/com/dtrules/mapping/.svn/entries
new file mode 100644 (file)
index 0000000..4c7bce4
--- /dev/null
@@ -0,0 +1,28 @@
+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
diff --git a/src/test/com/dtrules/mapping/.svn/format b/src/test/com/dtrules/mapping/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/test/.svn/entries b/src/test/com/dtrules/test/.svn/entries
new file mode 100644 (file)
index 0000000..4f32685
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/src/test/com/dtrules/test/.svn/format b/src/test/com/dtrules/test/.svn/format
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/src/test/com/dtrules/test/.svn/text-base/AllUnitTest.java.svn-base b/src/test/com/dtrules/test/.svn/text-base/AllUnitTest.java.svn-base
new file mode 100644 (file)
index 0000000..838ecac
--- /dev/null
@@ -0,0 +1,37 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/test/com/dtrules/test/.svn/text-base/BaseTest.java.svn-base b/src/test/com/dtrules/test/.svn/text-base/BaseTest.java.svn-base
new file mode 100644 (file)
index 0000000..a2bd1fb
--- /dev/null
@@ -0,0 +1,49 @@
+/*  
+ * 
+ * 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");
+                }
+            }
+        }
+    }
+}
diff --git a/src/test/com/dtrules/test/AllUnitTest.java b/src/test/com/dtrules/test/AllUnitTest.java
new file mode 100644 (file)
index 0000000..838ecac
--- /dev/null
@@ -0,0 +1,37 @@
+/*  
+ * $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;
+    }
+}
diff --git a/src/test/com/dtrules/test/BaseTest.java b/src/test/com/dtrules/test/BaseTest.java
new file mode 100644 (file)
index 0000000..a2bd1fb
--- /dev/null
@@ -0,0 +1,49 @@
+/*  
+ * 
+ * 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");
+                }
+            }
+        }
+    }
+}
diff --git a/target/DTRules-1.19-SNAPSHOT-sources.jar b/target/DTRules-1.19-SNAPSHOT-sources.jar
new file mode 100644 (file)
index 0000000..1843509
Binary files /dev/null and b/target/DTRules-1.19-SNAPSHOT-sources.jar differ
diff --git a/target/DTRules-1.19-SNAPSHOT.jar b/target/DTRules-1.19-SNAPSHOT.jar
new file mode 100644 (file)
index 0000000..d6089bd
Binary files /dev/null and b/target/DTRules-1.19-SNAPSHOT.jar differ
diff --git a/target/classes/com/dtrules/App.class b/target/classes/com/dtrules/App.class
new file mode 100644 (file)
index 0000000..e072829
Binary files /dev/null and b/target/classes/com/dtrules/App.class differ
diff --git a/target/classes/com/dtrules/admin/IRulesAdminService.class b/target/classes/com/dtrules/admin/IRulesAdminService.class
new file mode 100644 (file)
index 0000000..a1b5912
Binary files /dev/null and b/target/classes/com/dtrules/admin/IRulesAdminService.class differ
diff --git a/target/classes/com/dtrules/admin/RulesAdminService.class b/target/classes/com/dtrules/admin/RulesAdminService.class
new file mode 100644 (file)
index 0000000..8f0d939
Binary files /dev/null and b/target/classes/com/dtrules/admin/RulesAdminService.class differ
diff --git a/target/classes/com/dtrules/decisiontables/ANode.class b/target/classes/com/dtrules/decisiontables/ANode.class
new file mode 100644 (file)
index 0000000..77f9e3a
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/ANode.class differ
diff --git a/target/classes/com/dtrules/decisiontables/BalanceTable.class b/target/classes/com/dtrules/decisiontables/BalanceTable.class
new file mode 100644 (file)
index 0000000..887cc5b
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/BalanceTable.class differ
diff --git a/target/classes/com/dtrules/decisiontables/CNode.class b/target/classes/com/dtrules/decisiontables/CNode.class
new file mode 100644 (file)
index 0000000..0a979c1
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/CNode.class differ
diff --git a/target/classes/com/dtrules/decisiontables/CompilerError.class b/target/classes/com/dtrules/decisiontables/CompilerError.class
new file mode 100644 (file)
index 0000000..05b0fbb
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/CompilerError.class differ
diff --git a/target/classes/com/dtrules/decisiontables/DTLoader.class b/target/classes/com/dtrules/decisiontables/DTLoader.class
new file mode 100644 (file)
index 0000000..e65e6ab
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/DTLoader.class differ
diff --git a/target/classes/com/dtrules/decisiontables/DTNode$Coordinate.class b/target/classes/com/dtrules/decisiontables/DTNode$Coordinate.class
new file mode 100644 (file)
index 0000000..200fcd8
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/DTNode$Coordinate.class differ
diff --git a/target/classes/com/dtrules/decisiontables/DTNode.class b/target/classes/com/dtrules/decisiontables/DTNode.class
new file mode 100644 (file)
index 0000000..0577dc1
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/DTNode.class differ
diff --git a/target/classes/com/dtrules/decisiontables/DecisionTableTypeTest.class b/target/classes/com/dtrules/decisiontables/DecisionTableTypeTest.class
new file mode 100644 (file)
index 0000000..960e35d
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/DecisionTableTypeTest.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$1.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$1.class
new file mode 100644 (file)
index 0000000..f7ca35f
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$1.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$1.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$1.class
new file mode 100644 (file)
index 0000000..cc07ea3
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$1.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$2.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$2.class
new file mode 100644 (file)
index 0000000..aaa6613
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$2.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$3.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$3.class
new file mode 100644 (file)
index 0000000..e5d43df
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type$3.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$Type.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type.class
new file mode 100644 (file)
index 0000000..425324c
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$Type.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable$UnbalancedType.class b/target/classes/com/dtrules/decisiontables/RDecisionTable$UnbalancedType.class
new file mode 100644 (file)
index 0000000..9b0eeba
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable$UnbalancedType.class differ
diff --git a/target/classes/com/dtrules/decisiontables/RDecisionTable.class b/target/classes/com/dtrules/decisiontables/RDecisionTable.class
new file mode 100644 (file)
index 0000000..c25ba8f
Binary files /dev/null and b/target/classes/com/dtrules/decisiontables/RDecisionTable.class differ
diff --git a/target/classes/com/dtrules/entity/IREntity.class b/target/classes/com/dtrules/entity/IREntity.class
new file mode 100644 (file)
index 0000000..e91c030
Binary files /dev/null and b/target/classes/com/dtrules/entity/IREntity.class differ
diff --git a/target/classes/com/dtrules/entity/REntity.class b/target/classes/com/dtrules/entity/REntity.class
new file mode 100644 (file)
index 0000000..f98e070
Binary files /dev/null and b/target/classes/com/dtrules/entity/REntity.class differ
diff --git a/target/classes/com/dtrules/entity/REntityEntry.class b/target/classes/com/dtrules/entity/REntityEntry.class
new file mode 100644 (file)
index 0000000..12f0845
Binary files /dev/null and b/target/classes/com/dtrules/entity/REntityEntry.class differ
diff --git a/target/classes/com/dtrules/infrastructure/RulesException.class b/target/classes/com/dtrules/infrastructure/RulesException.class
new file mode 100644 (file)
index 0000000..0344ba8
Binary files /dev/null and b/target/classes/com/dtrules/infrastructure/RulesException.class differ
diff --git a/target/classes/com/dtrules/interpreter/ARObject.class b/target/classes/com/dtrules/interpreter/ARObject.class
new file mode 100644 (file)
index 0000000..b153ead
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/ARObject.class differ
diff --git a/target/classes/com/dtrules/interpreter/IRObject.class b/target/classes/com/dtrules/interpreter/IRObject.class
new file mode 100644 (file)
index 0000000..417381b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/IRObject.class differ
diff --git a/target/classes/com/dtrules/interpreter/RArray.class b/target/classes/com/dtrules/interpreter/RArray.class
new file mode 100644 (file)
index 0000000..a9e210f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RArray.class differ
diff --git a/target/classes/com/dtrules/interpreter/RBoolean.class b/target/classes/com/dtrules/interpreter/RBoolean.class
new file mode 100644 (file)
index 0000000..7dd64d5
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RBoolean.class differ
diff --git a/target/classes/com/dtrules/interpreter/RDouble.class b/target/classes/com/dtrules/interpreter/RDouble.class
new file mode 100644 (file)
index 0000000..50f322f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RDouble.class differ
diff --git a/target/classes/com/dtrules/interpreter/RInteger.class b/target/classes/com/dtrules/interpreter/RInteger.class
new file mode 100644 (file)
index 0000000..e91c7ab
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RInteger.class differ
diff --git a/target/classes/com/dtrules/interpreter/RMark.class b/target/classes/com/dtrules/interpreter/RMark.class
new file mode 100644 (file)
index 0000000..1e068f6
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RMark.class differ
diff --git a/target/classes/com/dtrules/interpreter/RName.class b/target/classes/com/dtrules/interpreter/RName.class
new file mode 100644 (file)
index 0000000..62229ae
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RName.class differ
diff --git a/target/classes/com/dtrules/interpreter/RNull.class b/target/classes/com/dtrules/interpreter/RNull.class
new file mode 100644 (file)
index 0000000..192adbf
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RNull.class differ
diff --git a/target/classes/com/dtrules/interpreter/RString.class b/target/classes/com/dtrules/interpreter/RString.class
new file mode 100644 (file)
index 0000000..70717ec
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RString.class differ
diff --git a/target/classes/com/dtrules/interpreter/RTable.class b/target/classes/com/dtrules/interpreter/RTable.class
new file mode 100644 (file)
index 0000000..5ec27b4
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RTable.class differ
diff --git a/target/classes/com/dtrules/interpreter/RTime.class b/target/classes/com/dtrules/interpreter/RTime.class
new file mode 100644 (file)
index 0000000..66d7caf
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RTime.class differ
diff --git a/target/classes/com/dtrules/interpreter/RXmlValue.class b/target/classes/com/dtrules/interpreter/RXmlValue.class
new file mode 100644 (file)
index 0000000..41419bc
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/RXmlValue.class differ
diff --git a/target/classes/com/dtrules/interpreter/SimpleTokenizer.class b/target/classes/com/dtrules/interpreter/SimpleTokenizer.class
new file mode 100644 (file)
index 0000000..0d80f80
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/SimpleTokenizer.class differ
diff --git a/target/classes/com/dtrules/interpreter/Token$Type.class b/target/classes/com/dtrules/interpreter/Token$Type.class
new file mode 100644 (file)
index 0000000..0bfefba
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/Token$Type.class differ
diff --git a/target/classes/com/dtrules/interpreter/Token.class b/target/classes/com/dtrules/interpreter/Token.class
new file mode 100644 (file)
index 0000000..0cc29a6
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/Token.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$AddArray.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$AddArray.class
new file mode 100644 (file)
index 0000000..723e8e8
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$AddArray.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Add_no_dups.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Add_no_dups.class
new file mode 100644 (file)
index 0000000..bafbff8
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Add_no_dups.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addat.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addat.class
new file mode 100644 (file)
index 0000000..12a04be
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addat.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addto.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addto.class
new file mode 100644 (file)
index 0000000..645f0b3
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Addto.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Arraytomark.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Arraytomark.class
new file mode 100644 (file)
index 0000000..5eca804
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Arraytomark.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Clear.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Clear.class
new file mode 100644 (file)
index 0000000..a50e07c
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Clear.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Copyelements.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Copyelements.class
new file mode 100644 (file)
index 0000000..131acbb
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Copyelements.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Getat.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Getat.class
new file mode 100644 (file)
index 0000000..afb6d41
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Getat.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Length.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Length.class
new file mode 100644 (file)
index 0000000..1879cc2
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Length.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Mark.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Mark.class
new file mode 100644 (file)
index 0000000..9949565
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Mark.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Memberof.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Memberof.class
new file mode 100644 (file)
index 0000000..d991587
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Memberof.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Merge.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Merge.class
new file mode 100644 (file)
index 0000000..abee5da
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Merge.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Newarray.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Newarray.class
new file mode 100644 (file)
index 0000000..6b38253
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Newarray.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Randomize.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Randomize.class
new file mode 100644 (file)
index 0000000..f964b90
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Randomize.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Remove.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Remove.class
new file mode 100644 (file)
index 0000000..cf69c3f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Remove.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Removeat.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Removeat.class
new file mode 100644 (file)
index 0000000..1d289fb
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Removeat.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortarray.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortarray.class
new file mode 100644 (file)
index 0000000..1f9f484
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortarray.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortentities.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortentities.class
new file mode 100644 (file)
index 0000000..e7cb986
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Sortentities.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps$Tokenize.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Tokenize.class
new file mode 100644 (file)
index 0000000..3b12b64
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps$Tokenize.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RArrayOps.class b/target/classes/com/dtrules/interpreter/operators/RArrayOps.class
new file mode 100644 (file)
index 0000000..fb1ac0b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RArrayOps.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$And.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$And.class
new file mode 100644 (file)
index 0000000..3c94a7a
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$And.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleanequal.class
new file mode 100644 (file)
index 0000000..b344d2f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleannotequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleannotequal.class
new file mode 100644 (file)
index 0000000..79a6a14
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Booleannotequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Equal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Equal.class
new file mode 100644 (file)
index 0000000..46c4721
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Equal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FEqual.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FEqual.class
new file mode 100644 (file)
index 0000000..2e0aa82
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FEqual.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthan.class
new file mode 100644 (file)
index 0000000..eb9a761
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthanequal.class
new file mode 100644 (file)
index 0000000..fea28fd
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FGreaterthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthan.class
new file mode 100644 (file)
index 0000000..5012877
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthanequal.class
new file mode 100644 (file)
index 0000000..d3b6cce
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$FLessthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthan.class
new file mode 100644 (file)
index 0000000..f3858fe
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthanequal.class
new file mode 100644 (file)
index 0000000..708cb6f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Greaterthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Isnull.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Isnull.class
new file mode 100644 (file)
index 0000000..76f9d93
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Isnull.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthan.class
new file mode 100644 (file)
index 0000000..4dee8e7
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthanequal.class
new file mode 100644 (file)
index 0000000..f959e2b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Lessthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Not.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Not.class
new file mode 100644 (file)
index 0000000..b9cf569
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Not.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Or.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Or.class
new file mode 100644 (file)
index 0000000..5923a36
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Or.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Req.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Req.class
new file mode 100644 (file)
index 0000000..9e1b958
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Req.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SConcat.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SConcat.class
new file mode 100644 (file)
index 0000000..5c48592
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SConcat.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqual.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqual.class
new file mode 100644 (file)
index 0000000..e5bff74
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqual.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqualIgnoreCase.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqualIgnoreCase.class
new file mode 100644 (file)
index 0000000..a99113a
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SEqualIgnoreCase.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthan.class
new file mode 100644 (file)
index 0000000..3e22a0f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthanequal.class
new file mode 100644 (file)
index 0000000..2739600
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SGreaterthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthan.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthan.class
new file mode 100644 (file)
index 0000000..98e3982
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthan.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthanequal.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthanequal.class
new file mode 100644 (file)
index 0000000..ce56d1e
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$SLessthanequal.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Strremove.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Strremove.class
new file mode 100644 (file)
index 0000000..f3749da
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps$Strremove.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RBooleanOps.class b/target/classes/com/dtrules/interpreter/operators/RBooleanOps.class
new file mode 100644 (file)
index 0000000..b50bbad
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RBooleanOps.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Allocate.class b/target/classes/com/dtrules/interpreter/operators/RControl$Allocate.class
new file mode 100644 (file)
index 0000000..ee72f03
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Allocate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Deallocate.class b/target/classes/com/dtrules/interpreter/operators/RControl$Deallocate.class
new file mode 100644 (file)
index 0000000..8702538
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Deallocate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Doloop.class b/target/classes/com/dtrules/interpreter/operators/RControl$Doloop.class
new file mode 100644 (file)
index 0000000..4ee3205
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Doloop.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Entityforall.class b/target/classes/com/dtrules/interpreter/operators/RControl$Entityforall.class
new file mode 100644 (file)
index 0000000..e1b6a30
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Entityforall.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Execute.class b/target/classes/com/dtrules/interpreter/operators/RControl$Execute.class
new file mode 100644 (file)
index 0000000..0d3548d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Execute.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$ExecuteTable.class b/target/classes/com/dtrules/interpreter/operators/RControl$ExecuteTable.class
new file mode 100644 (file)
index 0000000..7f814c9
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$ExecuteTable.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$For.class b/target/classes/com/dtrules/interpreter/operators/RControl$For.class
new file mode 100644 (file)
index 0000000..f5624a1
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$For.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$ForFirstElse.class b/target/classes/com/dtrules/interpreter/operators/RControl$ForFirstElse.class
new file mode 100644 (file)
index 0000000..cd282c1
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$ForFirstElse.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Forall.class b/target/classes/com/dtrules/interpreter/operators/RControl$Forall.class
new file mode 100644 (file)
index 0000000..7a375ee
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Forall.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Forallr.class b/target/classes/com/dtrules/interpreter/operators/RControl$Forallr.class
new file mode 100644 (file)
index 0000000..a737eb8
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Forallr.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Forfirst.class b/target/classes/com/dtrules/interpreter/operators/RControl$Forfirst.class
new file mode 100644 (file)
index 0000000..68eebdb
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Forfirst.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Forr.class b/target/classes/com/dtrules/interpreter/operators/RControl$Forr.class
new file mode 100644 (file)
index 0000000..5d67600
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Forr.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$If.class b/target/classes/com/dtrules/interpreter/operators/RControl$If.class
new file mode 100644 (file)
index 0000000..b2d3f5f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$If.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Ifelse.class b/target/classes/com/dtrules/interpreter/operators/RControl$Ifelse.class
new file mode 100644 (file)
index 0000000..9456e19
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Ifelse.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Localfetch.class b/target/classes/com/dtrules/interpreter/operators/RControl$Localfetch.class
new file mode 100644 (file)
index 0000000..2ad4a48
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Localfetch.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$Localstore.class b/target/classes/com/dtrules/interpreter/operators/RControl$Localstore.class
new file mode 100644 (file)
index 0000000..47c108b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$Localstore.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl$While.class b/target/classes/com/dtrules/interpreter/operators/RControl$While.class
new file mode 100644 (file)
index 0000000..34a6d3e
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl$While.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RControl.class b/target/classes/com/dtrules/interpreter/operators/RControl.class
new file mode 100644 (file)
index 0000000..845e2a5
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RControl.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddDays.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddDays.class
new file mode 100644 (file)
index 0000000..006cc9f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddDays.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddMonths.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddMonths.class
new file mode 100644 (file)
index 0000000..84bb355
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddMonths.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddYears.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddYears.class
new file mode 100644 (file)
index 0000000..3ec0e3f
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$AddYears.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DateMinus.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DateMinus.class
new file mode 100644 (file)
index 0000000..9a9e94b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DateMinus.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DatePlus.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DatePlus.class
new file mode 100644 (file)
index 0000000..8aa559c
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DatePlus.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dateeq.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dateeq.class
new file mode 100644 (file)
index 0000000..b50c6e7
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dateeq.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dategt.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dategt.class
new file mode 100644 (file)
index 0000000..5543912
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Dategt.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Datelt.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Datelt.class
new file mode 100644 (file)
index 0000000..074919a
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Datelt.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Days.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Days.class
new file mode 100644 (file)
index 0000000..f170352
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Days.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DaysBetween.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DaysBetween.class
new file mode 100644 (file)
index 0000000..0eb24fe
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$DaysBetween.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$EndOfMonth.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$EndOfMonth.class
new file mode 100644 (file)
index 0000000..e8f5888
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$EndOfMonth.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfMonth.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfMonth.class
new file mode 100644 (file)
index 0000000..c4fd267
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfMonth.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfYear.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfYear.class
new file mode 100644 (file)
index 0000000..98c2652
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$FirstOfYear.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdayofmonth.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdayofmonth.class
new file mode 100644 (file)
index 0000000..fe82bd9
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdayofmonth.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinmonth.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinmonth.class
new file mode 100644 (file)
index 0000000..3796d1c
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinmonth.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinyear.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinyear.class
new file mode 100644 (file)
index 0000000..b6c3f80
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Getdaysinyear.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Gettimestamp.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Gettimestamp.class
new file mode 100644 (file)
index 0000000..211a427
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Gettimestamp.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$MonthsBetween.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$MonthsBetween.class
new file mode 100644 (file)
index 0000000..20dda44
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$MonthsBetween.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Newdate.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Newdate.class
new file mode 100644 (file)
index 0000000..1dc200d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Newdate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$SetCalendar.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$SetCalendar.class
new file mode 100644 (file)
index 0000000..2ac5fa6
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$SetCalendar.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Yearof.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Yearof.class
new file mode 100644 (file)
index 0000000..0fd4a36
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$Yearof.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$YearsBetween.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$YearsBetween.class
new file mode 100644 (file)
index 0000000..3d3cbd1
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps$YearsBetween.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RDateTimeOps.class b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps.class
new file mode 100644 (file)
index 0000000..b14f82d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RDateTimeOps.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Abs.class b/target/classes/com/dtrules/interpreter/operators/RMath$Abs.class
new file mode 100644 (file)
index 0000000..d4d9af5
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Abs.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Add.class b/target/classes/com/dtrules/interpreter/operators/RMath$Add.class
new file mode 100644 (file)
index 0000000..001d027
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Add.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Div.class b/target/classes/com/dtrules/interpreter/operators/RMath$Div.class
new file mode 100644 (file)
index 0000000..56052cf
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Div.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FAbs.class b/target/classes/com/dtrules/interpreter/operators/RMath$FAbs.class
new file mode 100644 (file)
index 0000000..427333e
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FAbs.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FAdd.class b/target/classes/com/dtrules/interpreter/operators/RMath$FAdd.class
new file mode 100644 (file)
index 0000000..c51e4f4
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FAdd.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FDiv.class b/target/classes/com/dtrules/interpreter/operators/RMath$FDiv.class
new file mode 100644 (file)
index 0000000..75dc2cb
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FDiv.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FMul.class b/target/classes/com/dtrules/interpreter/operators/RMath$FMul.class
new file mode 100644 (file)
index 0000000..4b7718d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FMul.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FNegate.class b/target/classes/com/dtrules/interpreter/operators/RMath$FNegate.class
new file mode 100644 (file)
index 0000000..0caf954
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FNegate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$FSub.class b/target/classes/com/dtrules/interpreter/operators/RMath$FSub.class
new file mode 100644 (file)
index 0000000..8ebae68
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$FSub.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Mul.class b/target/classes/com/dtrules/interpreter/operators/RMath$Mul.class
new file mode 100644 (file)
index 0000000..2125fd9
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Mul.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Negate.class b/target/classes/com/dtrules/interpreter/operators/RMath$Negate.class
new file mode 100644 (file)
index 0000000..129be94
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Negate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Roundto.class b/target/classes/com/dtrules/interpreter/operators/RMath$Roundto.class
new file mode 100644 (file)
index 0000000..061b04c
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Roundto.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath$Sub.class b/target/classes/com/dtrules/interpreter/operators/RMath$Sub.class
new file mode 100644 (file)
index 0000000..333e5fa
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath$Sub.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMath.class b/target/classes/com/dtrules/interpreter/operators/RMath.class
new file mode 100644 (file)
index 0000000..df5c973
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMath.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$ActionString.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$ActionString.class
new file mode 100644 (file)
index 0000000..fefe068
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$ActionString.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Clone.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Clone.class
new file mode 100644 (file)
index 0000000..f71c8ca
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Clone.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Createentity.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Createentity.class
new file mode 100644 (file)
index 0000000..e1490ec
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Createentity.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvb.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvb.class
new file mode 100644 (file)
index 0000000..3754be8
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvb.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvd.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvd.class
new file mode 100644 (file)
index 0000000..e1de0b3
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvd.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cve.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cve.class
new file mode 100644 (file)
index 0000000..666e3fa
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cve.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvi.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvi.class
new file mode 100644 (file)
index 0000000..d9a56b2
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvi.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvn.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvn.class
new file mode 100644 (file)
index 0000000..80c4889
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvn.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvr.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvr.class
new file mode 100644 (file)
index 0000000..36ccd9d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvr.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvs.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvs.class
new file mode 100644 (file)
index 0000000..bc6eb8d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Cvs.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Debug.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Debug.class
new file mode 100644 (file)
index 0000000..7799682
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Debug.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Def.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Def.class
new file mode 100644 (file)
index 0000000..ace5f19
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Def.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Dup.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Dup.class
new file mode 100644 (file)
index 0000000..cf6e462
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Dup.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$EntityName.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$EntityName.class
new file mode 100644 (file)
index 0000000..a1f8417
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$EntityName.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entityfetch.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entityfetch.class
new file mode 100644 (file)
index 0000000..044f5f3
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entityfetch.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypop.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypop.class
new file mode 100644 (file)
index 0000000..a610b2d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypop.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypush.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypush.class
new file mode 100644 (file)
index 0000000..2a58b21
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Entitypush.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Find.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Find.class
new file mode 100644 (file)
index 0000000..119a6ce
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Find.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$FromR.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$FromR.class
new file mode 100644 (file)
index 0000000..d2f1c0b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$FromR.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$GetDescription.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$GetDescription.class
new file mode 100644 (file)
index 0000000..abcc8ac
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$GetDescription.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$I.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$I.class
new file mode 100644 (file)
index 0000000..15e4e2d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$I.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Ignore.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Ignore.class
new file mode 100644 (file)
index 0000000..7ca3bbd
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Ignore.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$J.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$J.class
new file mode 100644 (file)
index 0000000..5c29ecd
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$J.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$K.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$K.class
new file mode 100644 (file)
index 0000000..d44638b
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$K.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Null.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Null.class
new file mode 100644 (file)
index 0000000..fe6313d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Null.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Over.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Over.class
new file mode 100644 (file)
index 0000000..d87e970
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Over.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$PStack.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$PStack.class
new file mode 100644 (file)
index 0000000..a1ab0ec
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$PStack.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Pop.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Pop.class
new file mode 100644 (file)
index 0000000..ba3cfc8
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Pop.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Print.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Print.class
new file mode 100644 (file)
index 0000000..6dd0c24
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Print.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$RError.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$RError.class
new file mode 100644 (file)
index 0000000..0710768
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$RError.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$RegexMatch.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$RegexMatch.class
new file mode 100644 (file)
index 0000000..f54eac3
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$RegexMatch.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$SetDebug.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$SetDebug.class
new file mode 100644 (file)
index 0000000..cd03438
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$SetDebug.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Stringlength.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Stringlength.class
new file mode 100644 (file)
index 0000000..d52e9a7
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Stringlength.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Swap.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Swap.class
new file mode 100644 (file)
index 0000000..a32fb67
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Swap.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$ToR.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$ToR.class
new file mode 100644 (file)
index 0000000..161ca42
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$ToR.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Tolowercase.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Tolowercase.class
new file mode 100644 (file)
index 0000000..f28ee19
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Tolowercase.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Touppercase.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Touppercase.class
new file mode 100644 (file)
index 0000000..58421cd
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Touppercase.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceoff.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceoff.class
new file mode 100644 (file)
index 0000000..0c21976
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceoff.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceon.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceon.class
new file mode 100644 (file)
index 0000000..86fd178
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Traceon.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Trim.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Trim.class
new file mode 100644 (file)
index 0000000..671bdc9
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Trim.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$Xdef.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Xdef.class
new file mode 100644 (file)
index 0000000..82271d6
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$Xdef.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps$substring.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps$substring.class
new file mode 100644 (file)
index 0000000..2ea2526
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps$substring.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RMiscOps.class b/target/classes/com/dtrules/interpreter/operators/RMiscOps.class
new file mode 100644 (file)
index 0000000..e6c939e
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RMiscOps.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/ROperator.class b/target/classes/com/dtrules/interpreter/operators/ROperator.class
new file mode 100644 (file)
index 0000000..9507498
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/ROperator.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$GetKeys.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$GetKeys.class
new file mode 100644 (file)
index 0000000..90812ec
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$GetKeys.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$Lookup.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$Lookup.class
new file mode 100644 (file)
index 0000000..7beb99d
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$Lookup.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$NewTable.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$NewTable.class
new file mode 100644 (file)
index 0000000..4e8dfd6
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$NewTable.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$Set.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$Set.class
new file mode 100644 (file)
index 0000000..8595dd9
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$Set.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$SetDescription.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$SetDescription.class
new file mode 100644 (file)
index 0000000..fac4860
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$SetDescription.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps$Translate.class b/target/classes/com/dtrules/interpreter/operators/RTableOps$Translate.class
new file mode 100644 (file)
index 0000000..51b5496
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps$Translate.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RTableOps.class b/target/classes/com/dtrules/interpreter/operators/RTableOps.class
new file mode 100644 (file)
index 0000000..2cddc62
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RTableOps.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$GetXmlAttribute.class b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$GetXmlAttribute.class
new file mode 100644 (file)
index 0000000..6a91f32
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$GetXmlAttribute.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$SetXmlAttribute.class b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$SetXmlAttribute.class
new file mode 100644 (file)
index 0000000..63675ed
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps$SetXmlAttribute.class differ
diff --git a/target/classes/com/dtrules/interpreter/operators/RXmlValueOps.class b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps.class
new file mode 100644 (file)
index 0000000..a8dc90c
Binary files /dev/null and b/target/classes/com/dtrules/interpreter/operators/RXmlValueOps.class differ
diff --git a/target/classes/com/dtrules/mapping/AttributeInfo$Attrib.class b/target/classes/com/dtrules/mapping/AttributeInfo$Attrib.class
new file mode 100644 (file)
index 0000000..8ebddb0
Binary files /dev/null and b/target/classes/com/dtrules/mapping/AttributeInfo$Attrib.class differ
diff --git a/target/classes/com/dtrules/mapping/AttributeInfo.class b/target/classes/com/dtrules/mapping/AttributeInfo.class
new file mode 100644 (file)
index 0000000..21f3ef7
Binary files /dev/null and b/target/classes/com/dtrules/mapping/AttributeInfo.class differ
diff --git a/target/classes/com/dtrules/mapping/DataMap$XmlLoader.class b/target/classes/com/dtrules/mapping/DataMap$XmlLoader.class
new file mode 100644 (file)
index 0000000..754d392
Binary files /dev/null and b/target/classes/com/dtrules/mapping/DataMap$XmlLoader.class differ
diff --git a/target/classes/com/dtrules/mapping/DataMap.class b/target/classes/com/dtrules/mapping/DataMap.class
new file mode 100644 (file)
index 0000000..dd4c6dc
Binary files /dev/null and b/target/classes/com/dtrules/mapping/DataMap.class differ
diff --git a/target/classes/com/dtrules/mapping/DataObjectMap.class b/target/classes/com/dtrules/mapping/DataObjectMap.class
new file mode 100644 (file)
index 0000000..e1461a8
Binary files /dev/null and b/target/classes/com/dtrules/mapping/DataObjectMap.class differ
diff --git a/target/classes/com/dtrules/mapping/EntityInfo.class b/target/classes/com/dtrules/mapping/EntityInfo.class
new file mode 100644 (file)
index 0000000..fbf819b
Binary files /dev/null and b/target/classes/com/dtrules/mapping/EntityInfo.class differ
diff --git a/target/classes/com/dtrules/mapping/LoadDatamapData.class b/target/classes/com/dtrules/mapping/LoadDatamapData.class
new file mode 100644 (file)
index 0000000..d9513a1
Binary files /dev/null and b/target/classes/com/dtrules/mapping/LoadDatamapData.class differ
diff --git a/target/classes/com/dtrules/mapping/LoadMap.class b/target/classes/com/dtrules/mapping/LoadMap.class
new file mode 100644 (file)
index 0000000..d2e7932
Binary files /dev/null and b/target/classes/com/dtrules/mapping/LoadMap.class differ
diff --git a/target/classes/com/dtrules/mapping/LoadMapping.class b/target/classes/com/dtrules/mapping/LoadMapping.class
new file mode 100644 (file)
index 0000000..ea679c6
Binary files /dev/null and b/target/classes/com/dtrules/mapping/LoadMapping.class differ
diff --git a/target/classes/com/dtrules/mapping/LoadXMLData.class b/target/classes/com/dtrules/mapping/LoadXMLData.class
new file mode 100644 (file)
index 0000000..a5f32d1
Binary files /dev/null and b/target/classes/com/dtrules/mapping/LoadXMLData.class differ
diff --git a/target/classes/com/dtrules/mapping/MapGenerator.class b/target/classes/com/dtrules/mapping/MapGenerator.class
new file mode 100644 (file)
index 0000000..0528bd4
Binary files /dev/null and b/target/classes/com/dtrules/mapping/MapGenerator.class differ
diff --git a/target/classes/com/dtrules/mapping/Mapping.class b/target/classes/com/dtrules/mapping/Mapping.class
new file mode 100644 (file)
index 0000000..29141d4
Binary files /dev/null and b/target/classes/com/dtrules/mapping/Mapping.class differ
diff --git a/target/classes/com/dtrules/mapping/XMLTag.class b/target/classes/com/dtrules/mapping/XMLTag.class
new file mode 100644 (file)
index 0000000..8c35ef7
Binary files /dev/null and b/target/classes/com/dtrules/mapping/XMLTag.class differ
diff --git a/target/classes/com/dtrules/session/DTState.class b/target/classes/com/dtrules/session/DTState.class
new file mode 100644 (file)
index 0000000..c829f72
Binary files /dev/null and b/target/classes/com/dtrules/session/DTState.class differ
diff --git a/target/classes/com/dtrules/session/EDDLoader.class b/target/classes/com/dtrules/session/EDDLoader.class
new file mode 100644 (file)
index 0000000..8f4d347
Binary files /dev/null and b/target/classes/com/dtrules/session/EDDLoader.class differ
diff --git a/target/classes/com/dtrules/session/EntityFactory.class b/target/classes/com/dtrules/session/EntityFactory.class
new file mode 100644 (file)
index 0000000..f519e52
Binary files /dev/null and b/target/classes/com/dtrules/session/EntityFactory.class differ
diff --git a/target/classes/com/dtrules/session/ICompiler.class b/target/classes/com/dtrules/session/ICompiler.class
new file mode 100644 (file)
index 0000000..9499d8a
Binary files /dev/null and b/target/classes/com/dtrules/session/ICompiler.class differ
diff --git a/target/classes/com/dtrules/session/ICompilerError$Type.class b/target/classes/com/dtrules/session/ICompilerError$Type.class
new file mode 100644 (file)
index 0000000..bfbac0c
Binary files /dev/null and b/target/classes/com/dtrules/session/ICompilerError$Type.class differ
diff --git a/target/classes/com/dtrules/session/ICompilerError.class b/target/classes/com/dtrules/session/ICompilerError.class
new file mode 100644 (file)
index 0000000..7023a6f
Binary files /dev/null and b/target/classes/com/dtrules/session/ICompilerError.class differ
diff --git a/target/classes/com/dtrules/session/IRSession.class b/target/classes/com/dtrules/session/IRSession.class
new file mode 100644 (file)
index 0000000..06bc055
Binary files /dev/null and b/target/classes/com/dtrules/session/IRSession.class differ
diff --git a/target/classes/com/dtrules/session/RSession.class b/target/classes/com/dtrules/session/RSession.class
new file mode 100644 (file)
index 0000000..0e16624
Binary files /dev/null and b/target/classes/com/dtrules/session/RSession.class differ
diff --git a/target/classes/com/dtrules/session/RuleSet.class b/target/classes/com/dtrules/session/RuleSet.class
new file mode 100644 (file)
index 0000000..7a1a51a
Binary files /dev/null and b/target/classes/com/dtrules/session/RuleSet.class differ
diff --git a/target/classes/com/dtrules/session/RulesDirectory$LoadDirectory.class b/target/classes/com/dtrules/session/RulesDirectory$LoadDirectory.class
new file mode 100644 (file)
index 0000000..ffec469
Binary files /dev/null and b/target/classes/com/dtrules/session/RulesDirectory$LoadDirectory.class differ
diff --git a/target/classes/com/dtrules/session/RulesDirectory.class b/target/classes/com/dtrules/session/RulesDirectory.class
new file mode 100644 (file)
index 0000000..05ce383
Binary files /dev/null and b/target/classes/com/dtrules/session/RulesDirectory.class differ
diff --git a/target/classes/com/dtrules/trace/DecisionTableNode.class b/target/classes/com/dtrules/trace/DecisionTableNode.class
new file mode 100644 (file)
index 0000000..f9d4615
Binary files /dev/null and b/target/classes/com/dtrules/trace/DecisionTableNode.class differ
diff --git a/target/classes/com/dtrules/trace/TraceNode.class b/target/classes/com/dtrules/trace/TraceNode.class
new file mode 100644 (file)
index 0000000..eacc8d4
Binary files /dev/null and b/target/classes/com/dtrules/trace/TraceNode.class differ
diff --git a/target/classes/com/dtrules/xmlparser/GenericXMLParser.class b/target/classes/com/dtrules/xmlparser/GenericXMLParser.class
new file mode 100644 (file)
index 0000000..bade1c4
Binary files /dev/null and b/target/classes/com/dtrules/xmlparser/GenericXMLParser.class differ
diff --git a/target/classes/com/dtrules/xmlparser/IGenericXMLParser.class b/target/classes/com/dtrules/xmlparser/IGenericXMLParser.class
new file mode 100644 (file)
index 0000000..182e25a
Binary files /dev/null and b/target/classes/com/dtrules/xmlparser/IGenericXMLParser.class differ
diff --git a/target/classes/com/dtrules/xmlparser/IXMLPrinter.class b/target/classes/com/dtrules/xmlparser/IXMLPrinter.class
new file mode 100644 (file)
index 0000000..9bff3bc
Binary files /dev/null and b/target/classes/com/dtrules/xmlparser/IXMLPrinter.class differ
diff --git a/target/classes/com/dtrules/xmlparser/XMLPrinter.class b/target/classes/com/dtrules/xmlparser/XMLPrinter.class
new file mode 100644 (file)
index 0000000..cc14bda
Binary files /dev/null and b/target/classes/com/dtrules/xmlparser/XMLPrinter.class differ
diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties
new file mode 100644 (file)
index 0000000..f30edb2
--- /dev/null
@@ -0,0 +1,5 @@
+#Generated by Maven
+#Mon Sep 08 16:23:26 CDT 2008
+version=1.19-SNAPSHOT
+groupId=com.dtrules
+artifactId=DTRules