001: package biz.hammurapi.rules.jsr94.admin;
002:
003: import java.io.File;
004: import java.io.FileInputStream;
005: import java.io.FileOutputStream;
006: import java.io.IOException;
007: import java.io.OutputStream;
008: import java.rmi.RemoteException;
009: import java.util.HashMap;
010: import java.util.Iterator;
011: import java.util.Map;
012:
013: import javax.rules.RuleServiceProvider;
014: import javax.rules.RuleServiceProviderManager;
015: import javax.rules.admin.LocalRuleExecutionSetProvider;
016: import javax.rules.admin.Rule;
017: import javax.rules.admin.RuleAdministrator;
018: import javax.rules.admin.RuleExecutionSet;
019: import javax.rules.admin.RuleExecutionSetDeregistrationException;
020: import javax.rules.admin.RuleExecutionSetProvider;
021: import javax.rules.admin.RuleExecutionSetRegisterException;
022: import javax.xml.parsers.DocumentBuilderFactory;
023: import javax.xml.parsers.FactoryConfigurationError;
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.transform.TransformerException;
026: import javax.xml.transform.stream.StreamResult;
027:
028: import org.apache.commons.cli.CommandLine;
029: import org.apache.commons.cli.CommandLineParser;
030: import org.apache.commons.cli.HelpFormatter;
031: import org.apache.commons.cli.Option;
032: import org.apache.commons.cli.OptionBuilder;
033: import org.apache.commons.cli.Options;
034: import org.apache.commons.cli.PosixParser;
035: import org.apache.xpath.XPathAPI;
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038: import org.w3c.dom.Node;
039: import org.w3c.dom.traversal.NodeIterator;
040: import org.xml.sax.SAXException;
041:
042: import biz.hammurapi.config.ConfigurationException;
043: import biz.hammurapi.rules.jsr94.FileRuleServiceProvider;
044: import biz.hammurapi.rules.jsr94.FileRuleServiceProvider.Registration;
045: import biz.hammurapi.util.StreamPumper;
046: import biz.hammurapi.xml.dom.AbstractDomObject;
047: import biz.hammurapi.xml.dom.DOMUtils;
048: import biz.hammurapi.xml.dom.DomSerializable;
049:
050: /**
051: * This rule administrator stores rulesets in an XML file.
052: * @author Pavel Vlasov
053: * @revision $Revision$
054: */
055: public class FileRuleAdministrator implements
056: javax.rules.admin.RuleAdministrator {
057:
058: private Map registrations;
059: private File regFile;
060:
061: /**
062: * Creates new instance.
063: * @param registrations
064: * @param homeDir
065: */
066: public FileRuleAdministrator(Map registrations, File regFile) {
067: this .registrations = registrations;
068: this .regFile = regFile;
069: }
070:
071: /**
072: * Loads registrations from a file.
073: * @throws SAXException
074: * @throws IOException
075: * @throws ParserConfigurationException
076: * @throws FactoryConfigurationError
077: * @throws TransformerException
078: * @throws ConfigurationException
079: */
080: private void load() throws SAXException, IOException,
081: ParserConfigurationException, FactoryConfigurationError,
082: TransformerException, ConfigurationException {
083: if (regFile.exists()) {
084: registrations.clear();
085: Document doc = DOMUtils.parse(regFile);
086: NodeIterator nit = XPathAPI.selectNodeIterator(doc
087: .getDocumentElement(),
088: "/registrations/registration");
089: Node n;
090: while ((n = nit.nextNode()) != null) {
091: Registration r = new FileRuleServiceProvider.Registration(
092: n);
093: registrations.put(r.getUri(), r);
094: }
095: }
096: }
097:
098: /**
099: * Stores registrations to a file.
100: * @throws ParserConfigurationException
101: * @throws FactoryConfigurationError
102: * @throws TransformerException
103: * @throws IOException
104: */
105: private void store() throws ParserConfigurationException,
106: FactoryConfigurationError, IOException,
107: TransformerException {
108: DOMUtils.serialize(registrations2Dom().getDocumentElement(),
109: regFile);
110: }
111:
112: /**
113: * @return
114: * @throws ParserConfigurationException
115: * @throws FactoryConfigurationError
116: */
117: private Document registrations2Dom()
118: throws ParserConfigurationException,
119: FactoryConfigurationError {
120: Document doc = DocumentBuilderFactory.newInstance()
121: .newDocumentBuilder().newDocument();
122: Element root = AbstractDomObject.addElement(doc,
123: "registrations");
124: Iterator rit = registrations.values().iterator();
125: while (rit.hasNext()) {
126: ((DomSerializable) rit.next()).toDom(AbstractDomObject
127: .addElement(root, "registration"));
128: }
129: return doc;
130: }
131:
132: /**
133: * Creates new RuleExecutionSetProvider. Propeties are passed to the provider.
134: */
135: public RuleExecutionSetProvider getRuleExecutionSetProvider(
136: Map properties) throws RemoteException {
137: return new biz.hammurapi.rules.jsr94.admin.RuleExecutionSetProvider(
138: properties);
139: }
140:
141: /**
142: * Creates new LocalRuleExecutionSetProvider. Properties are passed to the provider.
143: */
144: public LocalRuleExecutionSetProvider getLocalRuleExecutionSetProvider(
145: Map properties) throws RemoteException {
146: return new biz.hammurapi.rules.jsr94.admin.LocalRuleExecutionSetProvider(
147: properties);
148: }
149:
150: /**
151: * Registers rule execution set.
152: * Rule execution set can be registered by reference and by value.
153: * When registered by reference the set url is stored in the file instead of actual XML definition.
154: * To store rule execution set by reference put {"by-reference", Boolean.TRUE} to the properties map.
155: */
156: public void registerRuleExecutionSet(String uri,
157: RuleExecutionSet res, Map properties)
158: throws RuleExecutionSetRegisterException, RemoteException {
159: if (uri.startsWith("direct:")) {
160: throw new RuleExecutionSetRegisterException(
161: "Invalid rule set URI, 'direct:' is a reserved prefix.");
162: }
163: boolean byRef = properties != null
164: && Boolean.TRUE.equals(properties.get("by-reference"));
165: biz.hammurapi.rules.jsr94.admin.RuleExecutionSet cRes = ((biz.hammurapi.rules.jsr94.admin.RuleExecutionSet) res);
166: if (byRef && cRes.isModified()) {
167: throw new RuleExecutionSetRegisterException(
168: "Cannot register modified rule set by reference");
169: }
170:
171: if (byRef && cRes.getUri() == null) {
172: throw new RuleExecutionSetRegisterException(
173: "Cannot register rule set by reference - URI is null");
174: }
175:
176: synchronized (registrations) {
177: try {
178: load();
179: if (byRef) {
180: registrations.put(uri,
181: new FileRuleServiceProvider.Registration(
182: uri, cRes.getUri(), null, cRes
183: .getProperties()));
184: } else {
185: registrations.put(uri,
186: new FileRuleServiceProvider.Registration(
187: uri, null, cRes.getHolder(), cRes
188: .getProperties()));
189: }
190: store();
191: } catch (SAXException e) {
192: throw new RuleExecutionSetRegisterException(
193: "Could not deregister rule set with URI: "
194: + uri + ", " + e, e);
195: } catch (IOException e) {
196: throw new RuleExecutionSetRegisterException(
197: "Could not deregister rule set with URI: "
198: + uri + ", " + e, e);
199: } catch (ParserConfigurationException e) {
200: throw new RuleExecutionSetRegisterException(
201: "Could not deregister rule set with URI: "
202: + uri + ", " + e, e);
203: } catch (FactoryConfigurationError e) {
204: throw new RuleExecutionSetRegisterException(
205: "Could not deregister rule set with URI: "
206: + uri + ", " + e);
207: } catch (TransformerException e) {
208: throw new RuleExecutionSetRegisterException(
209: "Could not deregister rule set with URI: "
210: + uri + ", " + e, e);
211: } catch (ConfigurationException e) {
212: throw new RuleExecutionSetRegisterException(
213: "Could not deregister rule set with URI: "
214: + uri + ", " + e, e);
215: }
216: }
217: }
218:
219: /**
220: * Properties are ignored.
221: */
222: public void deregisterRuleExecutionSet(String uri, Map properties)
223: throws RuleExecutionSetDeregistrationException,
224: RemoteException {
225: synchronized (registrations) {
226: try {
227: load();
228: registrations.remove(uri);
229: store();
230: } catch (SAXException e) {
231: throw new RuleExecutionSetDeregistrationException(
232: "Could not deregister rule set with URI: "
233: + uri + ", " + e, e);
234: } catch (IOException e) {
235: throw new RuleExecutionSetDeregistrationException(
236: "Could not deregister rule set with URI: "
237: + uri + ", " + e, e);
238: } catch (ParserConfigurationException e) {
239: throw new RuleExecutionSetDeregistrationException(
240: "Could not deregister rule set with URI: "
241: + uri + ", " + e, e);
242: } catch (FactoryConfigurationError e) {
243: throw new RuleExecutionSetDeregistrationException(
244: "Could not deregister rule set with URI: "
245: + uri + ", " + e);
246: } catch (TransformerException e) {
247: throw new RuleExecutionSetDeregistrationException(
248: "Could not deregister rule set with URI: "
249: + uri + ", " + e, e);
250: } catch (ConfigurationException e) {
251: throw new RuleExecutionSetDeregistrationException(
252: "Could not deregister rule set with URI: "
253: + uri + ", " + e, e);
254: }
255: }
256: }
257:
258: public static void main(String[] args) throws Exception {
259: System.out
260: .println("Hammurapi Rules administrator. Copyright (C) 2006 Hammurapi Group");
261: String ruleServiceProviderClassName = "biz.hammurapi.rules.jsr94.FileRuleServiceProvider";
262: Class.forName(ruleServiceProviderClassName);
263: RuleServiceProvider serviceProvider = RuleServiceProviderManager
264: .getRuleServiceProvider(ruleServiceProviderClassName);
265: RuleAdministrator administrator = serviceProvider
266: .getRuleAdministrator();
267:
268: if (args.length == 0) {
269: printHelpAndExit();
270: } else if ("register".equals(args[0])) {
271: Options options = new Options();
272:
273: Option helpOption = OptionBuilder.withDescription(
274: "Print this message").isRequired(false).create("h");
275:
276: options.addOption(helpOption);
277:
278: Option fileOption = OptionBuilder.withArgName("file")
279: .hasArg().withDescription("Ruleset file")
280: .isRequired(false).create("f");
281:
282: options.addOption(fileOption);
283:
284: Option urlOption = OptionBuilder.withArgName("URL")
285: .hasArg().withDescription("Ruleset URL")
286: .isRequired(false).create("u");
287:
288: options.addOption(urlOption);
289:
290: Option refOption = OptionBuilder
291: .withArgName("URL")
292: .hasArg()
293: .withDescription(
294: "Ruleset URL to be registered by reference")
295: .isRequired(false).create("r");
296:
297: options.addOption(refOption);
298:
299: Option propertyOption = OptionBuilder.withArgName(
300: "key=value").hasArg().withDescription(
301: "Rule set property").isRequired(false).create("p");
302:
303: options.addOption(propertyOption);
304:
305: Option rulePropertyOption = OptionBuilder.withArgName(
306: "rule name>:<key>=<value").hasArg()
307: .withDescription("Rule property").isRequired(false)
308: .create("R");
309:
310: options.addOption(rulePropertyOption);
311:
312: Option objectFilterOption = OptionBuilder.withArgName(
313: "class name").hasArg().withDescription(
314: "Default object filter").isRequired(false).create(
315: "o");
316:
317: options.addOption(objectFilterOption);
318:
319: CommandLineParser parser = new PosixParser();
320: CommandLine line = null;
321:
322: try {
323: line = parser.parse(options, args);
324: } catch (org.apache.commons.cli.ParseException e) {
325: System.err.println(e.getMessage());
326: System.err.flush();
327: printHelpAndExit("register <uri>", options);
328: }
329:
330: if (line.hasOption("h")) {
331: printHelpAndExit("register <uri>", options);
332: }
333:
334: int no = 0;
335: if (line.hasOption('f')) {
336: ++no;
337: }
338: if (line.hasOption('u')) {
339: ++no;
340: }
341: if (line.hasOption('r')) {
342: ++no;
343: }
344:
345: if (no == 0) {
346: System.out
347: .println("One of -f, -u or -r options must be specified");
348: printHelpAndExit("register <uri>", options);
349: }
350:
351: if (no > 1) {
352: System.out
353: .println("Options -f, -u, and -r are mutually exclusive");
354: printHelpAndExit("register <uri>", options);
355: }
356:
357: String[] largs = line.getArgs();
358: if (largs.length != 2) {
359: System.out.println("Invalid parameters");
360: printHelpAndExit("register <uri>", options);
361: }
362:
363: RuleExecutionSetProvider resp = administrator
364: .getRuleExecutionSetProvider(null);
365:
366: Map properties = null;
367: if (line.hasOption('p')) {
368: properties = new HashMap();
369: String[] props = line.getOptionValues('p');
370: for (int i = 0; i < props.length; i++) {
371: int idx = props[i].indexOf('=');
372: if (idx == -1 || idx == props[i].length() - 1
373: || idx == 0) {
374: System.out
375: .println("Invalid property definition: "
376: + props[i]);
377: printHelpAndExit("register <uri>", options);
378: }
379: properties.put(props[i].substring(0, idx), props[i]
380: .substring(idx + 1));
381: }
382: }
383:
384: if (line.hasOption('f')) {
385: RuleExecutionSet res = resp.createRuleExecutionSet(
386: DOMUtils.parse(
387: new File(line.getOptionValue('f')))
388: .getDocumentElement(), properties);
389: setObjectFilterAndRuleProperties(line, options, res);
390: administrator.registerRuleExecutionSet(largs[1], res,
391: null);
392: }
393:
394: if (line.hasOption('u')) {
395: RuleExecutionSet res = resp.createRuleExecutionSet(line
396: .getOptionValue('u'), properties);
397: setObjectFilterAndRuleProperties(line, options, res);
398: administrator.registerRuleExecutionSet(largs[1], res,
399: null);
400: }
401:
402: if (line.hasOption('r')) {
403: if (line.hasOption('R')) {
404: System.out
405: .println("Rule properties cannot be set in rule sets registered by reference");
406: printHelpAndExit("register <uri>", options);
407: }
408:
409: if (line.hasOption('o')) {
410: System.out
411: .println("Defalut object filter cannot be set in rule sets registered by reference");
412: printHelpAndExit("register <uri>", options);
413: }
414:
415: RuleExecutionSet res = resp.createRuleExecutionSet(line
416: .getOptionValue('r'), properties);
417: HashMap regProperties = new HashMap();
418: regProperties.put("by-reference", Boolean.TRUE);
419: administrator.registerRuleExecutionSet(largs[1], res,
420: regProperties);
421: }
422:
423: } else if ("deregister".equals(args[0])) {
424: Options options = new Options();
425:
426: Option helpOption = OptionBuilder.withDescription(
427: "Print this message").isRequired(false).create("h");
428:
429: options.addOption(helpOption);
430:
431: CommandLineParser parser = new PosixParser();
432: CommandLine line = null;
433:
434: try {
435: line = parser.parse(options, args);
436: } catch (org.apache.commons.cli.ParseException e) {
437: System.err.println(e.getMessage());
438: System.err.flush();
439: printHelpAndExit("deregister <uri>", options);
440: }
441:
442: if (line.hasOption("h")) {
443: printHelpAndExit("deregister <uri>", options);
444: }
445:
446: String[] largs = line.getArgs();
447: if (largs.length != 2) {
448: System.out.println("Invalid parameters");
449: printHelpAndExit("deregister <uri>", options);
450: }
451:
452: administrator.deregisterRuleExecutionSet(largs[1], null);
453: } else if ("list".equals(args[0])) {
454: Options options = new Options();
455:
456: Option helpOption = OptionBuilder.withDescription(
457: "Print this message").isRequired(false).create("h");
458:
459: options.addOption(helpOption);
460:
461: Option fileOption = OptionBuilder.withArgName("file")
462: .hasArg().withDescription("Output file")
463: .isRequired(false).create("f");
464:
465: options.addOption(fileOption);
466:
467: Option xmlOption = OptionBuilder.withDescription(
468: "Output in XML format").isRequired(false).create(
469: "x");
470:
471: options.addOption(xmlOption);
472:
473: Option htmlOption = OptionBuilder.withDescription(
474: "Output in HTML format").isRequired(false).create(
475: "H");
476:
477: options.addOption(htmlOption);
478:
479: CommandLineParser parser = new PosixParser();
480: CommandLine line = null;
481:
482: try {
483: line = parser.parse(options, args);
484: } catch (org.apache.commons.cli.ParseException e) {
485: System.err.println(e.getMessage());
486: System.err.flush();
487: printHelpAndExit("list", options);
488: }
489:
490: if (line.hasOption("h")) {
491: printHelpAndExit("list", options);
492: }
493:
494: OutputStream out;
495: if (line.hasOption('f')) {
496: out = new FileOutputStream(new File(line
497: .getOptionValue('f')));
498: } else {
499: out = System.out;
500: }
501:
502: File regFile = ((FileRuleAdministrator) administrator).regFile;
503:
504: if (line.hasOption('x')) {
505: FileInputStream in = new FileInputStream(regFile);
506: try {
507: new StreamPumper(in, out, null, false).run();
508: } finally {
509: in.close();
510: if (line.hasOption('f')) {
511: out.close();
512: }
513: }
514: } else if (line.hasOption('H')) {
515: try {
516: DOMUtils
517: .style(
518: DOMUtils.parse(regFile),
519: out,
520: FileRuleAdministrator.class
521: .getResourceAsStream("list_html.xsl"),
522: null);
523: } finally {
524: if (line.hasOption('f')) {
525: out.close();
526: }
527: }
528: } else {
529: try {
530: DOMUtils
531: .style(
532: DOMUtils.parse(regFile),
533: out,
534: FileRuleAdministrator.class
535: .getResourceAsStream("list_text.xsl"),
536: null);
537: } finally {
538: if (line.hasOption('f')) {
539: out.close();
540: }
541: }
542: }
543: } else if ("dump".equals(args[0])) {
544: Options options = new Options();
545:
546: Option helpOption = OptionBuilder.withDescription(
547: "Print this message").isRequired(false).create("h");
548:
549: options.addOption(helpOption);
550:
551: Option fileOption = OptionBuilder.withArgName("file")
552: .hasArg().withDescription("Output file")
553: .isRequired(false).create("f");
554:
555: options.addOption(fileOption);
556:
557: Option xmlOption = OptionBuilder.withDescription(
558: "Output in XML format").isRequired(false).create(
559: "x");
560:
561: options.addOption(xmlOption);
562:
563: Option htmlOption = OptionBuilder.withDescription(
564: "Output in HTML format").isRequired(false).create(
565: "H");
566:
567: options.addOption(htmlOption);
568:
569: CommandLineParser parser = new PosixParser();
570: CommandLine line = null;
571:
572: try {
573: line = parser.parse(options, args);
574: } catch (org.apache.commons.cli.ParseException e) {
575: System.err.println(e.getMessage());
576: System.err.flush();
577: printHelpAndExit("dump <uri>", options);
578: }
579:
580: if (line.hasOption("h")) {
581: printHelpAndExit("dump <uri>", options);
582: }
583:
584: String[] largs = line.getArgs();
585: if (largs.length != 2) {
586: System.out.println("Invalid parameters");
587: printHelpAndExit("dump <uri>", options);
588: }
589:
590: OutputStream out;
591: if (line.hasOption('f')) {
592: out = new FileOutputStream(new File(line
593: .getOptionValue('f')));
594: } else {
595: out = System.out;
596: }
597:
598: Object registration = ((FileRuleAdministrator) administrator).registrations
599: .get(largs[1]);
600:
601: if (line.hasOption('x')) {
602: try {
603: DOMUtils.serialize(registration, "registration",
604: new StreamResult(out));
605: } finally {
606: if (line.hasOption('f')) {
607: out.close();
608: }
609: }
610: } else if (line.hasOption('H')) {
611: try {
612: DOMUtils
613: .style(
614: registration,
615: "registration",
616: out,
617: FileRuleAdministrator.class
618: .getResourceAsStream("dump_html.xsl"),
619: null);
620: } finally {
621: if (line.hasOption('f')) {
622: out.close();
623: }
624: }
625: } else {
626: try {
627: DOMUtils
628: .style(
629: registration,
630: "registration",
631: out,
632: FileRuleAdministrator.class
633: .getResourceAsStream("dump_text.xsl"),
634: null);
635: } finally {
636: if (line.hasOption('f')) {
637: out.close();
638: }
639: }
640: }
641: } else {
642: System.out.println("Unrecognized command: " + args[0]);
643: printHelpAndExit();
644: }
645: }
646:
647: /**
648: * Reads default object filter and rule properties from command line and sets them in RuleExecutionSet.
649: * @param line
650: * @param res
651: */
652: private static void setObjectFilterAndRuleProperties(
653: CommandLine line, Options options, RuleExecutionSet res) {
654: if (line.hasOption('o')) {
655: res.setDefaultObjectFilter(line.getOptionValue('o'));
656: }
657:
658: if (line.hasOption('R')) {
659: String[] ruleProperties = line.getOptionValues('R');
660:
661: Z: for (int i = 0; i < ruleProperties.length; i++) {
662: int idx = ruleProperties[i].indexOf(":");
663: if (idx <= 0 || idx == ruleProperties[i].length() - 1) {
664: System.out
665: .println("Rule property format: <Rule name>:<property name>=<property value>");
666: printHelpAndExit("register <uri>", options);
667: }
668:
669: String ruleName = ruleProperties[i].substring(0, idx);
670:
671: int idx2 = ruleProperties[i].indexOf("=", idx);
672: if (idx2 == -1
673: || idx2 == ruleProperties[i].length() - 1) {
674: System.out
675: .println("Rule property format: <Rule name>:<property name>=<property value>");
676: printHelpAndExit("register <uri>", options);
677: }
678:
679: String propertyName = ruleProperties[i].substring(
680: idx + 1, idx2);
681: String propertyValue = ruleProperties[i]
682: .substring(idx2 + 1);
683:
684: Iterator it = res.getRules().iterator();
685: while (it.hasNext()) {
686: Rule rule = (Rule) it.next();
687: if (ruleName.equals(rule.getName())) {
688: rule.setProperty(propertyName, propertyValue);
689: continue Z;
690: }
691: }
692:
693: System.out.println("Rule not found: " + ruleName);
694: printHelpAndExit("register <uri>", options);
695: }
696: }
697:
698: }
699:
700: protected static void printHelpAndExit() {
701: System.out.println("Usage: hradmin command [options]");
702: System.out.println("\tCommands:");
703: System.out
704: .println("\t\tregister <uri> {-f <file> | -u <url> | -r <url>} [-p <name>=<value>] [-R <rule name>:<property name>=<property value>] [-o <object filter>]- Registers rule set.");
705: System.out
706: .println("\t\tderegister <uri> - Unregisters rule set.");
707: System.out
708: .println("\t\tlist [-f <file>] {-x|-H} - Lists names of registered rule sets to console or file.");
709: System.out
710: .println("\t\tdump <uri> [-f <file>] {-x|-H} - Outputs ruleset definition to console or file.");
711: System.out
712: .println("\n\tExecute 'hradmin command -h' for command-specific options");
713:
714: System.exit(1);
715: }
716:
717: protected static void printHelpAndExit(String command,
718: Options options) {
719: HelpFormatter formatter = new HelpFormatter();
720: formatter.printHelp("hradmin " + command + " [options]",
721: options, false);
722: System.exit(1);
723: }
724:
725: }
|