001 package biz.hammurapi.rules.jsr94; 002 003 import java.io.File; 004 import java.io.IOException; 005 import java.util.HashMap; 006 import java.util.Map; 007 008 import javax.rules.ConfigurationException; 009 import javax.rules.RuleRuntime; 010 import javax.rules.RuleServiceProviderManager; 011 import javax.rules.admin.RuleAdministrator; 012 import javax.xml.parsers.FactoryConfigurationError; 013 import javax.xml.parsers.ParserConfigurationException; 014 import javax.xml.transform.TransformerException; 015 import javax.xml.xpath.XPathExpressionException; 016 017 import org.w3c.dom.Document; 018 import org.w3c.dom.Element; 019 import org.w3c.dom.Node; 020 import org.w3c.dom.NodeList; 021 import org.xml.sax.SAXException; 022 023 import biz.hammurapi.config.DomConfigFactory; 024 import biz.hammurapi.rules.jsr94.admin.FileRuleAdministrator; 025 import biz.hammurapi.xml.dom.AbstractDomObject; 026 import biz.hammurapi.xml.dom.DOMUtils; 027 import biz.hammurapi.xml.dom.DomSerializable; 028 029 /** 030 * This rule service provider reads configuration from XML files. 031 * XML definitions are read from rules home directory. By default it is <code>.hammurapi-rules</code> directory 032 * in user home directory. This can be changed by setting <code>biz.hammurapi.rules.jsr94.FileRuleServiceProvider:home</code> 033 * property to custom rules home directory name. 034 * @author Pavel Vlasov 035 * @version ${Revision} 036 */ 037 public class FileRuleServiceProvider extends javax.rules.RuleServiceProvider { 038 039 private static String home; 040 041 static { 042 try { 043 RuleServiceProviderManager.registerRuleServiceProvider("biz.hammurapi.rules.jsr94.FileRuleServiceProvider", biz.hammurapi.rules.jsr94.FileRuleServiceProvider.class); 044 } catch (ConfigurationException e) { 045 System.err.println("Could not register biz.hammurapi.rules.jsr94.FileRuleServiceProvider"); 046 e.printStackTrace(); 047 } 048 049 home=System.getProperty(biz.hammurapi.rules.jsr94.FileRuleServiceProvider.class.getName()+":home"); 050 } 051 052 /** 053 * Registration entry 054 * @author Pavel Vlasov 055 * @version ${Revision} 056 */ 057 public static class Registration implements DomSerializable { 058 private String uri; 059 060 /** 061 * @return Returns the uri. 062 */ 063 public String getUri() { 064 return uri; 065 } 066 067 /** 068 * @param uri The uri to set. 069 */ 070 public void setUri(String uri) { 071 this.uri = uri; 072 } 073 074 private String ref; 075 076 /** 077 * @return Returns the ref. 078 */ 079 public String getRef() { 080 return ref; 081 } 082 083 /** 084 * @param ref The ref to set. 085 */ 086 public void setRef(String ref) { 087 this.ref = ref; 088 } 089 090 private Node value; 091 092 /** 093 * @return Returns the value. 094 */ 095 public Node getValue() { 096 return value; 097 } 098 099 /** 100 * @param value The value to set. 101 */ 102 public void setValue(Node value) { 103 this.value = value; 104 } 105 106 /* (non-Javadoc) 107 * @see biz.hammurapi.xml.dom.DomSerializable#toDom(org.w3c.dom.Element) 108 */ 109 public void toDom(Element holder) { 110 holder.setAttribute("uri", uri); 111 if (ref!=null) { 112 holder.setAttribute("ref", ref); 113 } else if (value!=null) { 114 Element de=AbstractDomObject.addElement(holder, "definition"); 115 de.appendChild(holder.getOwnerDocument().importNode(value, true)); 116 } 117 118 if (properties!=null) { 119 DOMUtils.toDom(properties, "properties", holder); 120 } 121 } 122 123 /* (non-Javadoc) 124 * @see biz.hammurapi.config.DomConfigurable#configure(org.w3c.dom.Node, biz.hammurapi.config.Context) 125 */ 126 public Registration(Node configNode) throws biz.hammurapi.config.ConfigurationException, XPathExpressionException { 127 Element configElement = (Element) configNode; 128 uri=configElement.getAttribute("uri"); 129 if (configElement.hasAttribute("ref")) { 130 ref=configElement.getAttribute("ref"); 131 } else { 132 value=DOMUtils.selectSingleNode(configNode, "definition/*"); 133 } 134 135 Node propertiesNode=DOMUtils.selectSingleNode(configNode, "properties"); 136 if (propertiesNode!=null) { 137 properties=(Map) new DomConfigFactory().create(propertiesNode); 138 } 139 } 140 141 142 private Map properties; 143 144 /** 145 * @return Returns the properties. 146 */ 147 public Map getProperties() { 148 return properties; 149 } 150 151 public Registration(String uri, String ref, Node value, Map properties) { 152 super(); 153 // TODO Auto-generated constructor stub 154 this.uri = uri; 155 this.ref = ref; 156 this.value = value; 157 158 if (properties!=null) { 159 this.properties = new HashMap(properties); 160 } 161 } 162 } 163 164 private Map registrations=new HashMap(); 165 private RuleRuntime runtime; 166 private RuleAdministrator administrator; 167 private File regFile; 168 169 /** 170 * Constructs rule service provider and reads 171 * rule definitions from XML file <code>registrations.xml</code> in 172 * rules home directory. 173 * 174 */ 175 public FileRuleServiceProvider() { 176 File homeDir; 177 178 if (home==null) { 179 homeDir=new File(new File(System.getProperty("user.home")), ".hammurapi-rules"); 180 } else { 181 homeDir=new File(home); 182 } 183 184 if (homeDir.exists()) { 185 if (!homeDir.isDirectory()) { 186 errorMessage="Invalid home, not a directory - "+homeDir.getAbsolutePath(); 187 } 188 } else if (!homeDir.mkdirs()) { 189 errorMessage="Cannot create home directory "+homeDir.getAbsolutePath(); 190 } 191 192 regFile=new File(homeDir, "registrations.xml"); 193 try { 194 load(); 195 } catch (Exception e) { 196 errorMessage="Could not load registrations: "+e; 197 } 198 199 runtime=new FileRuleRuntime(registrations); 200 administrator=new FileRuleAdministrator(registrations, regFile); 201 } 202 203 /** 204 * Loads configuration from XML file 205 * @param regFile 206 * @throws SAXException 207 * @throws IOException 208 * @throws ParserConfigurationException 209 * @throws FactoryConfigurationError 210 * @throws TransformerException 211 * @throws biz.hammurapi.config.ConfigurationException 212 * @throws XPathExpressionException 213 */ 214 private void load() throws SAXException, IOException, ParserConfigurationException, FactoryConfigurationError, biz.hammurapi.config.ConfigurationException, XPathExpressionException { 215 if (regFile.exists()) { 216 synchronized (registrations) { 217 registrations.clear(); 218 Document doc=DOMUtils.parse(regFile); 219 NodeList nl=DOMUtils.selectNodeList(doc.getDocumentElement(), "/registrations/registration"); 220 for (int i=0, l=nl.getLength(); i<l; ++i) { 221 Registration r=new Registration(nl.item(i)); 222 registrations.put(r.getUri(), r); 223 } 224 } 225 } 226 } 227 228 private String errorMessage; 229 230 public RuleRuntime getRuleRuntime() throws ConfigurationException { 231 if (errorMessage!=null) { 232 throw new ConfigurationException(errorMessage); 233 } 234 235 return runtime; 236 } 237 238 public RuleAdministrator getRuleAdministrator() throws ConfigurationException { 239 if (errorMessage!=null) { 240 throw new ConfigurationException(errorMessage); 241 } 242 243 return administrator; 244 } 245 }