1 21 package org.jsmtpd.config; 22 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.lang.reflect.InvocationTargetException ; 26 import java.lang.reflect.Method ; 27 import java.lang.reflect.Modifier ; 28 29 import javax.xml.parsers.DocumentBuilder ; 30 import javax.xml.parsers.DocumentBuilderFactory ; 31 import javax.xml.parsers.ParserConfigurationException ; 32 33 import org.apache.commons.logging.Log; 34 import org.apache.commons.logging.LogFactory; 35 import org.jsmtpd.core.common.IGenericPlugin; 36 import org.jsmtpd.core.common.PluginInitException; 37 import org.jsmtpd.core.common.PluginLoadingException; 38 import org.jsmtpd.core.common.PluginStore; 39 import org.jsmtpd.core.common.acl.IACL; 40 import org.jsmtpd.core.common.delivery.IDeliveryService; 41 import org.jsmtpd.core.common.dnsService.IDNSResolver; 42 import org.jsmtpd.core.common.filter.FilterTreeNode; 43 import org.jsmtpd.core.common.filter.IFilter; 44 import org.jsmtpd.core.common.inputIPFilter.IFilterIP; 45 import org.jsmtpd.core.common.smtpExtension.ISmtpExtension; 46 import org.w3c.dom.Document ; 47 import org.w3c.dom.NamedNodeMap ; 48 import org.w3c.dom.Node ; 49 import org.w3c.dom.NodeList ; 50 import org.xml.sax.ErrorHandler ; 51 import org.xml.sax.SAXException ; 52 import org.xml.sax.SAXParseException ; 53 54 59 public class PluginLoader implements ErrorHandler { 60 61 64 private PluginStore store = PluginStore.getInstance(); 65 66 69 private SAXParseException lastEx = null; 70 71 74 private Document document; 75 78 private FilterTreeNode filterRoot = null; 79 82 private Log log = LogFactory.getLog(PluginLoader.class); 83 84 private String xmlFileName; 85 86 93 public void init() throws SAXException , IOException , ParserConfigurationException , ElementNotFoundException { 94 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 95 factory.setNamespaceAware(true); 96 factory.setValidating(true); 97 98 try { 99 factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); 100 } catch (IllegalArgumentException x) { 101 x.printStackTrace(); 102 } 103 InputStream xsd = this.getClass().getClassLoader().getResourceAsStream("jsmtpd-plugin-config.xsd"); 104 if (xsd == null) 105 throw new IOException ("File jsmtpd-plugin-config.xsd not found, not in classpath"); 106 factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", xsd); 107 108 DocumentBuilder builder; 109 builder = factory.newDocumentBuilder(); 110 builder.setErrorHandler(this); 111 112 InputStream in = this.getClass().getClassLoader().getResourceAsStream(xmlFileName); 113 if (in == null) 114 throw new IOException ("File "+xmlFileName+" not found, not in classpath"); 115 116 document = builder.parse(in); 117 118 if (lastEx != null) { 119 SAXException toThrow = new SAXException (lastEx); 120 lastEx = null; 121 throw toThrow; 122 } 123 124 } 125 126 130 public void loadDNSService() throws PluginLoaderException { 131 132 NodeList tmp = document.getElementsByTagName("DNSSetup"); 133 Node dnsset = tmp.item(0); 134 NamedNodeMap map = dnsset.getAttributes(); 135 String className = map.getNamedItem("class").getNodeValue(); 136 IGenericPlugin dns = loadGenericPlugin(className, dnsset); 137 try { 138 dns.initPlugin(); 139 } catch (PluginInitException e) { 140 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 141 } 142 store.setResolver((IDNSResolver) dns); 143 } 144 145 149 150 public void loadLocalDeliveryService() throws PluginLoaderException { 151 152 NodeList tmp = document.getElementsByTagName("LocalDeliveryService"); 153 Node ldsset = tmp.item(0); 154 NamedNodeMap map = ldsset.getAttributes(); 155 String className = map.getNamedItem("class").getNodeValue(); 156 IGenericPlugin lds = loadGenericPlugin(className, ldsset); 157 try { 158 lds.initPlugin(); 159 } catch (PluginInitException e) { 160 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 161 } 162 store.setLocalDeliveryService((IDeliveryService) lds); 163 } 164 165 169 public void loadRemoteDeliveryService() throws PluginLoaderException { 170 171 NodeList tmp = document.getElementsByTagName("RemoteDeliveryService"); 172 Node rdsset = tmp.item(0); 173 NamedNodeMap map = rdsset.getAttributes(); 174 String className = map.getNamedItem("class").getNodeValue(); 175 IGenericPlugin rds = loadGenericPlugin(className, rdsset); 176 try { 177 rds.initPlugin(); 178 } catch (PluginInitException e) { 179 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 180 } 181 store.setRemoteDeliveryService((IDeliveryService) rds); 182 } 183 184 188 public void loadACL() throws PluginLoaderException { 189 190 NodeList tmp = document.getElementsByTagName("ACLSetup"); 191 Node aclset = tmp.item(0); 192 NamedNodeMap map = aclset.getAttributes(); 193 String className = map.getNamedItem("class").getNodeValue(); 194 IGenericPlugin acl = loadGenericPlugin(className, aclset); 195 try { 196 acl.initPlugin(); 197 } catch (PluginInitException e) { 198 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 199 } 200 store.setAcl((IACL) acl); 201 } 202 203 208 public void loadFilterTree() throws ModuleNotFoundException { 209 NodeList tmp = document.getElementsByTagName("bodyFilterTree"); 210 Node treeRoot = tmp.item(0); 211 212 NodeList childs = treeRoot.getChildNodes(); 213 for (int i = 0; i < childs.getLength(); i++) { 214 Node flt = childs.item(i); 215 if (flt.getNodeName().equals("filter")) { 216 NamedNodeMap mp = flt.getAttributes(); 217 String logicalName = mp.getNamedItem("name").getNodeValue(); 218 219 log.debug("[tree] Loading filtree with root node [i]" + logicalName); 220 IGenericPlugin plugin = (IGenericPlugin) PluginStore.getInstance().getPluginByLogicalName(logicalName); 221 if (plugin instanceof IFilter) { 222 IFilter module = (IFilter) plugin; 223 filterRoot = new FilterTreeNode(); 224 filterRoot.setFilter(module); 225 appendFilterTreeNode(flt, filterRoot); 226 } else { 227 log.fatal("The filter " + logicalName + " is not a body filter tree plugin !"); 228 throw new ModuleNotFoundException(logicalName); 229 } 230 } 231 } 232 PluginStore.getInstance().setRootFilter(filterRoot); 233 } 234 235 241 public void appendFilterTreeNode(Node node, FilterTreeNode pNode) throws ModuleNotFoundException { 242 246 NodeList childs = node.getChildNodes(); 247 if (childs == null) 248 return; 250 for (int i = 0; i < childs.getLength(); i++) { 251 Node tmp = childs.item(i); 252 253 if (tmp.getNodeName().equals("true")) { 254 NodeList tchilds = tmp.getChildNodes(); 255 if (tchilds != null) { 256 for (int j = 0; j < tchilds.getLength(); j++) { 257 Node ch = tchilds.item(j); 258 if (ch.getNodeName().equals("filter")) { 259 NamedNodeMap mp = ch.getAttributes(); 260 String modName = mp.getNamedItem("name").getNodeValue(); 261 log.debug("[tree] adding " + modName + " as true node to node " + pNode.getFilter().getPluginName()); 262 IGenericPlugin plugin = (IGenericPlugin) PluginStore.getInstance().getPluginByLogicalName(modName); 263 if (plugin instanceof IFilter) { 264 IFilter flt = (IFilter) plugin; 265 FilterTreeNode newNode = new FilterTreeNode(); 266 newNode.setFilter(flt); 267 pNode.setTrueNode(newNode); 268 newNode.setParent(pNode); 269 appendFilterTreeNode(ch, newNode); 270 } else { 271 log.debug( "The filter " + modName + " is not a body filter tree plugin !"); 272 throw new ModuleNotFoundException(modName); 273 } 274 } 275 } 276 } 277 } 278 279 if (tmp.getNodeName().equals("false")) { 280 NodeList tchilds = tmp.getChildNodes(); 281 if (tchilds != null) { 282 for (int j = 0; j < tchilds.getLength(); j++) { 283 Node ch = tchilds.item(j); 284 if (ch.getNodeName().equals("filter")) { 285 NamedNodeMap mp = ch.getAttributes(); 286 String modName = mp.getNamedItem("name").getNodeValue(); 287 log.debug("[tree] adding " + modName + " as false node to node " + pNode.getFilter().getPluginName()); 288 289 IGenericPlugin plugin = (IGenericPlugin) PluginStore.getInstance().getPluginByLogicalName(modName); 290 if (plugin instanceof IFilter) { 291 IFilter flt = (IFilter) PluginStore.getInstance().getPluginByLogicalName(modName); 292 FilterTreeNode newNode = new FilterTreeNode(); 293 newNode.setFilter(flt); 294 pNode.setFalseNode(newNode); 295 newNode.setParent(pNode); 296 appendFilterTreeNode(ch, newNode); 297 } else { 298 log.fatal("The filter " + modName + " is not a body filter tree plugin !"); 299 throw new ModuleNotFoundException(modName); 300 } 301 } 302 } 303 } 304 } 305 306 } 307 308 } 309 310 314 public void loadFilters() throws PluginLoaderException { 315 NodeList tmp = document.getElementsByTagName("filtersetup"); 316 Node filterSetup = tmp.item(0); 317 318 NodeList filters = filterSetup.getChildNodes(); 319 320 for (int i = 0; i < filters.getLength(); i++) { 321 Node current = filters.item(i); 322 if (current.getNodeName().equals("filterInit")) { 323 NamedNodeMap map = current.getAttributes(); 324 String className = map.getNamedItem("class").getNodeValue(); 325 String logicalName = map.getNamedItem("name").getNodeValue(); 326 log.debug("\tTrying to load [c]" + className + " as [i]" + logicalName); 327 IGenericPlugin module = loadGenericPlugin(className, current); 328 try { 329 module.initPlugin(); 330 } catch (PluginInitException e) { 331 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 332 } 333 store.addPlugin(module, logicalName); 334 log.debug("\tLoaded [c]" + className + " as [i]" + logicalName); 335 } 336 } 337 338 } 339 340 344 public void loadInputIPFilterChain() throws ModuleNotFoundException { 345 NodeList tmp = document.getElementsByTagName("inputIPFilterChain"); 346 Node treeRoot = tmp.item(0); 347 348 NodeList childs = treeRoot.getChildNodes(); 349 for (int i = 0; i < childs.getLength(); i++) { 350 Node flt = childs.item(i); 351 if (flt.getNodeName().equals("ipFilter")) { 352 NamedNodeMap mp = flt.getAttributes(); 353 String logicalName = mp.getNamedItem("name").getNodeValue(); 354 355 IGenericPlugin plugin = (IGenericPlugin) PluginStore.getInstance().getPluginByLogicalName(logicalName); 356 if (plugin instanceof IFilterIP) { 357 IFilterIP module = (IFilterIP) plugin; 358 PluginStore.getInstance().addInputIPFilters(module); 359 } else { 360 log.fatal("Plugin " + logicalName + "is not an input IP Filter"); 361 throw new ModuleNotFoundException(logicalName); 362 } 363 } 364 } 365 PluginStore.getInstance().setRootFilter(filterRoot); 366 } 367 368 public void loadSmtpExtensions() throws PluginLoaderException { 369 NodeList tmp = document.getElementsByTagName("smtpExtensions"); 370 Node treeRoot = tmp.item(0); 371 372 NodeList childs = treeRoot.getChildNodes(); 373 for (int i = 0; i < childs.getLength(); i++) { 374 Node extension = childs.item(i); 375 if (extension.getNodeName().equals("smtpExtension")) { 376 NamedNodeMap mp = extension.getAttributes(); 377 String logicalName = mp.getNamedItem("name").getNodeValue(); 378 String className = mp.getNamedItem("class").getNodeValue(); 379 log.info("Loading SMTP Extension plugin " + logicalName + " of class " + className); 380 IGenericPlugin plugin = loadGenericPlugin(className, extension); 381 try { 382 plugin.initPlugin(); 383 } catch (PluginInitException e) { 384 throw new PluginLoaderException("The plugin failed to initialize itsefl",e); 385 } 386 if (plugin instanceof ISmtpExtension) { 387 ISmtpExtension module = (ISmtpExtension) plugin; 388 PluginStore.getInstance().addSmtpExtensions(module); 389 log.info("Loaded SMTP Extension plugin " + plugin.getPluginName() + " as " + logicalName); 390 } else { 391 log.fatal("Plugin " + logicalName + "is not a valid smtp extension"); 392 throw new PluginLoaderException("The plugin "+logicalName+" is not a valid smtp extension"); 393 } 394 } 395 } 396 PluginStore.getInstance().setRootFilter(filterRoot); 397 } 398 399 411 private IGenericPlugin loadGenericPlugin(String className, Node pNode) throws PluginLoaderException { 412 413 IGenericPlugin module = null; 414 try { 415 module = (IGenericPlugin) Class.forName(className).newInstance(); 416 } catch (InstantiationException e1) { 417 throw new PluginLoaderException("Could not instanciate target class",e1); 418 } catch (IllegalAccessException e1) { 419 throw new PluginLoaderException("Illegal access",e1); 420 } catch (ClassNotFoundException e1) { 421 throw new PluginLoaderException("The plugin class does not exists in classpath",e1); 422 } 423 424 NodeList tmp = pNode.getChildNodes(); 425 for (int i = 0; i < tmp.getLength(); i++) { 427 Node cur = tmp.item(i); 428 if (cur.getNodeName().equals("propertyset")) { 429 NamedNodeMap props = cur.getAttributes(); 430 setParam(module, props.getNamedItem("name").getNodeValue(), props.getNamedItem("value").getNodeValue()); 431 } 432 } 433 434 return module; 435 } 436 437 445 private void setParam(IGenericPlugin plug, String name, String value) throws PluginLoaderException { 446 String rName = name.substring(0,1).toUpperCase()+name.substring(1); 447 String lookup = "set" + rName; 448 Method method = methodLookup(plug.getClass(), lookup); 449 invoke(plug, method, value); 450 log.debug("\t[set][c]:" + plug.getClass() + ", set " + name + "=" + value); 451 } 452 453 460 private Method methodLookup(Class clazz, String methodName) throws PluginLoaderException { 461 Method [] meths = clazz.getDeclaredMethods(); 462 String ucMethodName = "set"+methodName.substring(3,4).toUpperCase() + methodName.substring(4); for (int i = 0; i < meths.length; i++) { 464 Method method = meths[i]; 465 if (method.getName().equals(methodName) || method.getName().equals(ucMethodName)) { 466 if (Modifier.isPublic(method.getModifiers())) { 467 Class [] params = method.getParameterTypes(); 468 if ((params == null) || (params.length != 1)) 469 throw new PluginLoaderException("Method " + method.getName() + " must have only one parameter"); 470 return method; 471 } else { 472 throw new PluginLoaderException("Method " + method.getName() + " is not public"); 473 } 474 } 475 } 476 Class parent = clazz.getSuperclass(); 478 if (parent == null) 479 throw new PluginLoaderException("Method " + methodName + " not found in parent types"); 480 else 481 return methodLookup(parent, methodName); 482 } 483 484 494 private void invoke(IGenericPlugin plug, Method meth, String value) throws PluginLoaderException { 495 Class [] params = meth.getParameterTypes(); 496 Object [] effectiveParams = new Object [1]; 497 498 try { 499 if (params[0].getName().equals("java.lang.String")) { 500 effectiveParams[0] = (Object ) value; 501 meth.invoke(plug, effectiveParams); 502 return; 503 } 504 505 if (params[0].getName().equals("int")) { 506 effectiveParams[0] = new Integer (value); meth.invoke(plug, effectiveParams); 508 return; 509 } 510 511 if (params[0].getName().equals("boolean")) { 512 effectiveParams[0] = new Boolean (value); meth.invoke(plug, effectiveParams); 514 return; 515 } 516 517 if (params[0].getName().equals("long")) { 518 effectiveParams[0] = new Long (value); 519 meth.invoke(plug, effectiveParams); 520 return; 521 } 522 } catch (NumberFormatException e) { 523 throw new PluginLoaderException("Could not parse the value from string to number",e); 524 } catch (IllegalArgumentException e) { 525 throw new PluginLoaderException ("Illegal argument",e); 526 } catch (IllegalAccessException e) { 527 throw new PluginLoaderException ("Illegal acces",e); 528 } catch (InvocationTargetException e) { 529 throw new PluginLoaderException ("Invocation target error",e); 530 } 531 532 throw new PluginLoaderException("This kind of parameter is not supported"); 533 } 534 535 public void warning(SAXParseException exception) throws SAXException { 536 lastEx = exception; 537 } 538 539 public void error(SAXParseException exception) throws SAXException { 540 lastEx = exception; 541 } 542 543 public void fatalError(SAXParseException exception) throws SAXException { 544 lastEx = exception; 545 } 546 547 public FilterTreeNode getFilterRoot() { 548 return filterRoot; 549 } 550 public String getXmlFileName() { 551 return xmlFileName; 552 } 553 public void setXmlFileName(String xmlFileName) { 554 this.xmlFileName = xmlFileName; 555 } 556 } | Popular Tags |