|
| 1 | +package com.tibco.ep.community.dtschema; |
| 2 | + |
| 3 | + |
| 4 | +import java.io.ByteArrayInputStream; |
| 5 | +import java.io.File; |
| 6 | +import java.io.FileOutputStream; |
| 7 | +import java.io.OutputStream; |
| 8 | +import java.io.StringWriter; |
| 9 | +import java.io.Writer; |
| 10 | +import java.util.List; |
| 11 | + |
| 12 | +import javax.xml.bind.JAXBContext; |
| 13 | +import javax.xml.bind.JAXBElement; |
| 14 | +import javax.xml.bind.Marshaller; |
| 15 | +import javax.xml.namespace.QName; |
| 16 | +import javax.xml.parsers.DocumentBuilder; |
| 17 | +import javax.xml.parsers.DocumentBuilderFactory; |
| 18 | +import javax.xml.transform.OutputKeys; |
| 19 | +import javax.xml.transform.Transformer; |
| 20 | +import javax.xml.transform.TransformerFactory; |
| 21 | +import javax.xml.transform.dom.DOMSource; |
| 22 | +import javax.xml.transform.stream.StreamResult; |
| 23 | + |
| 24 | +import org.w3c.dom.Document; |
| 25 | + |
| 26 | +import com.tibco.ep.ams.model.response.Table; |
| 27 | +import com.tibco.ep.ams.model.response.Table.DecisionTable; |
| 28 | +import com.tibco.ep.ams.model.response.Table.DecisionTable.Columns; |
| 29 | +import com.tibco.ep.ams.model.response.Table.DecisionTable.Columns.Column; |
| 30 | +import com.tibco.ep.ams.model.response.Table.DecisionTable.Rule; |
| 31 | +import com.tibco.ep.ams.model.response.Table.DecisionTable.Rule.Act; |
| 32 | +import com.tibco.ep.ams.model.response.Table.DecisionTable.Rule.Cond; |
| 33 | +import com.tibco.ep.ams.model.response.Table.Md; |
| 34 | +import com.tibco.ep.ams.model.response.Table.Md.Prop; |
| 35 | + |
| 36 | +/** |
| 37 | + * This sample demonstrates generating Java wrappers from a decision table model (schema file) and |
| 38 | + * using the wrappers to create and populate a StreamBase decision table. For simplicity, the actual |
| 39 | + * content written to the decision table is hard-coded. |
| 40 | + * |
| 41 | + * A StreamBase decision table is serialized to XML as in this example |
| 42 | + * |
| 43 | + * <?xml version="1.0" encoding="UTF-8"?> |
| 44 | + * <Table> |
| 45 | + * <md> |
| 46 | + * <prop name="Priority" value="5"/> |
| 47 | + * <prop name="EffectiveDate" type="String" value="2018-03-22 15:06:39"/> |
| 48 | + * <prop name="ExpiryDate" type="String" value="2018-03-23 15:06:41"/> |
| 49 | + * <prop name="SingleRowExecution" type="Boolean" value="true"/> |
| 50 | + * </md> |
| 51 | + * <decisionTable> |
| 52 | + * <rule id="1"> |
| 53 | + * <cond colId="0" expr="Alice" id="1_0"/> |
| 54 | + * <cond colId="1" expr="34" id="1_1"/> |
| 55 | + * <act colId="2" expr="true" id="1_2"/> |
| 56 | + * <act colId="3" expr="2500" id="1_3"/> |
| 57 | + * <act colId="4" expr="Visa Granted" id="1_4"/> |
| 58 | + * </rule> |
| 59 | + * <rule id="2"> |
| 60 | + * <cond colId="0" expr="Bob" id="2_0"/> |
| 61 | + * <cond colId="1" expr="61" id="2_1"/> |
| 62 | + * <act colId="2" expr="false" id="2_2"/> |
| 63 | + * <act colId="3" expr="5000" id="2_3"/> |
| 64 | + * <act colId="4" expr="N/A" id="2_4"/> |
| 65 | + * </rule> |
| 66 | + * <columns> |
| 67 | + * <column columnType="CONDITION" id="0" name="Name" propertyPath="Name"/> |
| 68 | + * <column columnType="CONDITION" id="1" name="Age" propertyPath="Age" propertyType="1"/> |
| 69 | + * <column columnType="ACTION" id="2" name="Eligible" propertyPath="Eligible" propertyType="4"/> |
| 70 | + * <column columnType="ACTION" id="3" name="CreditLimit" propertyPath="CreditLimit" propertyType="1"/> |
| 71 | + * <column columnType="ACTION" id="4" name="Status" propertyPath="Status"/> |
| 72 | + * </columns> |
| 73 | + * </decisionTable> |
| 74 | + * </Table> |
| 75 | + * |
| 76 | + * <p/> |
| 77 | + * The IDs of the rules, columns, conditions, actions, are related and are assigned as follows: |
| 78 | + * |
| 79 | + * <list> |
| 80 | + * <li>Each rule is assigned a one-based, monotonically increasing ID. |
| 81 | + * <li>Each column is assigned a zero-based, monotonically increasing ID. |
| 82 | + * <li>Each condition and action includes a colId indicating its association with a particular table column. |
| 83 | + * <li>Each condition and action also includes an id, which is formatted as "ruleID_columnID". |
| 84 | + * </list> |
| 85 | + * |
| 86 | + * <p/> |
| 87 | + * Note that although the various IDs are hardcoded for simplicity in the example below, they would be expected |
| 88 | + * to assigned programmatically using incrementing counters in a production application. |
| 89 | + * |
| 90 | + * @author jklumpp |
| 91 | + */ |
| 92 | +public class CreateDecisionTable { |
| 93 | + |
| 94 | + /** |
| 95 | + * Demonstrates using Java wrappers generated from a decision table model schema (xsd) |
| 96 | + * to create a StreamBase decision table |
| 97 | + * |
| 98 | + * @param args ignored |
| 99 | + */ |
| 100 | + public static void main(String[] args) { |
| 101 | + |
| 102 | + try { |
| 103 | + |
| 104 | + // Create a decision table |
| 105 | + Table table = new Table(); |
| 106 | + |
| 107 | + // Create metadata for the decision table |
| 108 | + Md metadata = new Md(); |
| 109 | + |
| 110 | + // Add properties to the metadata |
| 111 | + List<Prop> properties = metadata.getProp(); |
| 112 | + properties.add(new Prop("Priority", null, "5")); |
| 113 | + properties.add(new Prop("EffectiveDate", "String", "2018-03-22 15:06:39")); |
| 114 | + properties.add(new Prop("ExpiryDate", "String", "2018-03-23 15:06:41")); |
| 115 | + properties.add(new Prop("SingleRowExecution", "Boolean", "true")); |
| 116 | + |
| 117 | + // Add the metadata to the decision table |
| 118 | + table.setMd(metadata); |
| 119 | + |
| 120 | + // Create the body of the decision table |
| 121 | + DecisionTable decisionTable = new DecisionTable(); |
| 122 | + |
| 123 | + // Create the decision table's columns |
| 124 | + decisionTable.setColumns(new Columns()); |
| 125 | + List<Column> columns = decisionTable.getColumns().getColumn(); |
| 126 | + columns.add(new Column("0", "Name", "Name", null, "CONDITION")); |
| 127 | + columns.add(new Column("1", "Age", "Age", "1", "CONDITION")); |
| 128 | + columns.add(new Column("2", "Eligible", "Eligible", "4", "ACTION")); |
| 129 | + columns.add(new Column("3", "CreditLimit", "CreditLimit", "1", "ACTION")); |
| 130 | + columns.add(new Column("4", "Status", "Status", null, "ACTION")); |
| 131 | + |
| 132 | + // Create rules (rows) for the decision table |
| 133 | + List<Rule> rules = decisionTable.getRule(); |
| 134 | + |
| 135 | + // First rule |
| 136 | + Rule rule = new Rule(); |
| 137 | + rule.setId("1"); |
| 138 | + |
| 139 | + // First rule's conditions |
| 140 | + List<Cond> conditions = rule.getCond(); |
| 141 | + conditions.add(new Cond("1_0", "0", "Alice")); |
| 142 | + conditions.add(new Cond("1_1", "1", "34")); |
| 143 | + |
| 144 | + // First rule's actions |
| 145 | + List<Act> actions = rule.getAct(); |
| 146 | + actions.add(new Act("1_2", "2", "true")); |
| 147 | + actions.add(new Act("1_3", "3", "2500")); |
| 148 | + actions.add(new Act("1_4", "4", "Visa Granted")); |
| 149 | + |
| 150 | + // Add the first rule to the decision table rules |
| 151 | + rules.add(rule); |
| 152 | + |
| 153 | + // Second rule |
| 154 | + rule = new Rule(); |
| 155 | + rule.setId("2"); |
| 156 | + |
| 157 | + // Second rule's conditions |
| 158 | + conditions = rule.getCond(); |
| 159 | + conditions.add(new Cond("2_0", "0", "Bob")); |
| 160 | + conditions.add(new Cond("2_1", "1", "61")); |
| 161 | + |
| 162 | + // Second rule's actions |
| 163 | + actions = rule.getAct(); |
| 164 | + actions.add(new Act("2_2", "2", "false")); |
| 165 | + actions.add(new Act("2_3", "3", "5000")); |
| 166 | + actions.add(new Act("2_4", "4", "N/A")); |
| 167 | + |
| 168 | + // Add the second rule to the decision table rules |
| 169 | + rules.add(rule); |
| 170 | + |
| 171 | + // Add the body to the decision table |
| 172 | + table.setDecisionTable(decisionTable); |
| 173 | + |
| 174 | + // Write the serialized decision table to a file |
| 175 | + serialize(table, new File("sample.sbdt")); |
| 176 | + } |
| 177 | + catch (Exception e) { |
| 178 | + // Minimal error handling |
| 179 | + e.printStackTrace(); |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + /** |
| 184 | + * Serializes a decision table and writes it to a file |
| 185 | + * |
| 186 | + * @param table the decision table |
| 187 | + * @param file the file to write the serialized decision table to |
| 188 | + * @throws Exception if any errors occur |
| 189 | + */ |
| 190 | + private static void serialize(Table table, File file) throws Exception { |
| 191 | + JAXBContext context = JAXBContext.newInstance(table.getClass()); |
| 192 | + Marshaller m = context.createMarshaller(); |
| 193 | + StringWriter writer = new StringWriter(); |
| 194 | + m.marshal(new JAXBElement<Table>(new QName(table.getClass().getSimpleName()), Table.class, table), writer); |
| 195 | + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| 196 | + dbf.setValidating(false); |
| 197 | + DocumentBuilder db = dbf.newDocumentBuilder(); |
| 198 | + Document doc = db.parse(new ByteArrayInputStream(writer.toString().getBytes())); |
| 199 | + int len = prettyPrint(doc, new FileOutputStream(file)); |
| 200 | + System.out.println(String.format("%d bytes written to %s", len, file.getCanonicalPath())); |
| 201 | + } |
| 202 | + |
| 203 | + /** |
| 204 | + * Formats the serialized decision table, including adding newlines and indentation and writes it to an output stream. |
| 205 | + * |
| 206 | + * @param xml an XML document |
| 207 | + * @param os an output stream |
| 208 | + * @return the number of bytes written to the output stream |
| 209 | + * @throws Exception if any errors occur |
| 210 | + */ |
| 211 | + public static final int prettyPrint(Document xml, OutputStream os) throws Exception { |
| 212 | + TransformerFactory tf = TransformerFactory.newInstance(); |
| 213 | + tf.setAttribute("indent-number", "4"); |
| 214 | + Transformer transformer = tf.newTransformer(); |
| 215 | + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
| 216 | + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
| 217 | + Writer out = new StringWriter(); |
| 218 | + transformer.transform(new DOMSource(xml), new StreamResult(out)); |
| 219 | + byte[] bytes = out.toString().getBytes(); |
| 220 | + os.write(bytes); |
| 221 | + return bytes.length; |
| 222 | + } |
| 223 | +} |
0 commit comments