1 10 11 package org.nanocontainer.script.xml; 12 13 import java.io.File ; 14 import java.io.IOException ; 15 import java.io.Reader ; 16 import java.net.MalformedURLException ; 17 import java.net.URL ; 18 import java.security.Permission ; 19 import java.util.ArrayList ; 20 import java.util.List ; 21 22 import javax.xml.parsers.DocumentBuilder ; 23 import javax.xml.parsers.DocumentBuilderFactory ; 24 import javax.xml.parsers.ParserConfigurationException ; 25 26 import org.nanocontainer.ClassNameKey; 27 import org.nanocontainer.ClassPathElement; 28 import org.nanocontainer.DefaultNanoContainer; 29 import org.nanocontainer.NanoContainer; 30 import org.nanocontainer.reflection.DefaultNanoPicoContainer; 31 import org.nanocontainer.integrationkit.ContainerPopulator; 32 import org.nanocontainer.integrationkit.PicoCompositionException; 33 import org.nanocontainer.script.NanoContainerMarkupException; 34 import org.nanocontainer.script.ScriptedContainerBuilder; 35 import org.picocontainer.ComponentMonitor; 36 import org.picocontainer.MutablePicoContainer; 37 import org.picocontainer.Parameter; 38 import org.picocontainer.PicoContainer; 39 import org.picocontainer.defaults.ComponentAdapterFactory; 40 import org.picocontainer.defaults.ComponentMonitorStrategy; 41 import org.picocontainer.defaults.ComponentParameter; 42 import org.picocontainer.defaults.ConstantParameter; 43 import org.picocontainer.defaults.DefaultComponentAdapterFactory; 44 import org.picocontainer.defaults.DefaultPicoContainer; 45 import org.picocontainer.defaults.DelegatingComponentMonitor; 46 import org.w3c.dom.Element ; 47 import org.w3c.dom.NodeList ; 48 import org.xml.sax.EntityResolver ; 49 import org.xml.sax.InputSource ; 50 import org.xml.sax.SAXException ; 51 52 61 public class XMLContainerBuilder extends ScriptedContainerBuilder implements ContainerPopulator { 62 63 private final static String DEFAULT_COMPONENT_ADAPTER_FACTORY = DefaultComponentAdapterFactory.class.getName(); 64 private final static String DEFAULT_COMPONENT_INSTANCE_FACTORY = BeanComponentInstanceFactory.class.getName(); 65 private final static String DEFAULT_COMPONENT_MONITOR = DelegatingComponentMonitor.class.getName(); 66 67 private final static String CONTAINER = "container"; 68 private final static String CLASSPATH = "classpath"; 69 private final static String CLASSLOADER = "classloader"; 70 private static final String CLASS_NAME_KEY = "class-name-key"; 71 private final static String COMPONENT = "component"; 72 private final static String COMPONENT_IMPLEMENTATION = "component-implementation"; 73 private final static String COMPONENT_INSTANCE = "component-instance"; 74 private final static String COMPONENT_ADAPTER = "component-adapter"; 75 private final static String COMPONENT_ADAPTER_FACTORY = "component-adapter-factory"; 76 private final static String COMPONENT_INSTANCE_FACTORY = "component-instance-factory"; 77 private final static String COMPONENT_MONITOR = "component-monitor"; 78 private final static String DECORATING_PICOCONTAINER = "decorating-picocontainer"; 79 private final static String CLASS = "class"; 80 private final static String FACTORY = "factory"; 81 private final static String FILE = "file"; 82 private final static String KEY = "key"; 83 private final static String PARAMETER = "parameter"; 84 private final static String URL = "url"; 85 86 private final static String CLASSNAME = "classname"; 87 private final static String CONTEXT = "context"; 88 private final static String VALUE = "value"; 89 90 private static final String EMPTY = ""; 91 92 private Element rootElement; 93 97 private XMLComponentInstanceFactory componentInstanceFactory; 98 99 public XMLContainerBuilder(Reader script, ClassLoader classLoader) { 100 super(script, classLoader); 101 try { 102 DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 103 parse(documentBuilder, new InputSource (script)); 104 } catch (ParserConfigurationException e) { 105 throw new NanoContainerMarkupException(e); 106 } 107 } 108 109 public XMLContainerBuilder(final URL script, ClassLoader classLoader) { 110 super(script, classLoader); 111 try { 112 DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 113 documentBuilder.setEntityResolver(new EntityResolver () { 114 public InputSource resolveEntity(String publicId, String systemId) throws IOException { 115 URL url = new URL (script, systemId); 116 return new InputSource (url.openStream()); 117 } 118 }); 119 parse(documentBuilder, new InputSource (script.toString())); 120 } catch (ParserConfigurationException e) { 121 throw new NanoContainerMarkupException(e); 122 } 123 } 124 125 private void parse(DocumentBuilder documentBuilder, InputSource inputSource) { 126 try { 127 rootElement = documentBuilder.parse(inputSource).getDocumentElement(); 128 } catch (SAXException e) { 129 throw new NanoContainerMarkupException(e); 130 } catch (IOException e) { 131 throw new NanoContainerMarkupException(e); 132 } 133 } 134 135 protected PicoContainer createContainerFromScript(PicoContainer parentContainer, Object assemblyScope) { 136 try { 137 componentInstanceFactory = createComponentInstanceFactory(rootElement.getAttribute(COMPONENT_INSTANCE_FACTORY)); 139 MutablePicoContainer childContainer = createMutablePicoContainer(rootElement.getAttribute(COMPONENT_ADAPTER_FACTORY), 140 rootElement.getAttribute(COMPONENT_MONITOR), parentContainer); 141 populateContainer(childContainer); 142 return childContainer; 143 } catch (ClassNotFoundException e) { 144 throw new NanoContainerMarkupException("Class not found:" + e.getMessage(), e); 145 } 146 } 147 148 private MutablePicoContainer createMutablePicoContainer(String cafName, String monitorName, PicoContainer parentContainer) throws PicoCompositionException, ClassNotFoundException { 149 MutablePicoContainer container = new DefaultNanoPicoContainer(getClassLoader(),createComponentAdapterFactory(cafName, new DefaultNanoContainer(getClassLoader())), parentContainer); 150 if ( !notSet(monitorName) ){ 151 ComponentMonitor monitor = createComponentMonitor(monitorName); 152 ((ComponentMonitorStrategy)container).changeMonitor(monitor); 153 } 154 return container; 155 } 156 157 public void populateContainer(MutablePicoContainer container) { 158 try { 159 String parentClass = rootElement.getAttribute("parentclassloader"); 160 ClassLoader classLoader = getClassLoader(); 161 if (parentClass != null && !EMPTY.equals(parentClass)) { 162 classLoader = classLoader.loadClass(parentClass).getClassLoader(); 163 } 164 NanoContainer nanoContainer = new DefaultNanoContainer(classLoader, container); 165 registerComponentsAndChildContainers(nanoContainer, rootElement, new DefaultNanoContainer(getClassLoader())); 166 } catch (ClassNotFoundException e) { 167 throw new NanoContainerMarkupException("Class not found: " + e.getMessage(), e); 168 } catch (IOException e) { 169 throw new NanoContainerMarkupException(e); 170 } catch (SAXException e) { 171 throw new NanoContainerMarkupException(e); 172 } 173 } 174 175 private void registerComponentsAndChildContainers(NanoContainer parentContainer, Element containerElement, NanoContainer knownComponentAdapterFactories) throws ClassNotFoundException , IOException , SAXException { 176 177 NanoContainer metaContainer = new DefaultNanoContainer(getClassLoader(), knownComponentAdapterFactories.getPico()); 178 NodeList children = containerElement.getChildNodes(); 179 for (int i = 0; i < children.getLength(); i++) { 181 if (children.item(i) instanceof Element) { 182 Element childElement = (Element) children.item(i); 183 String name = childElement.getNodeName(); 184 if (CLASSPATH.equals(name)) { 185 registerClasspath(parentContainer, childElement); 186 } 187 } 188 } 189 for (int i = 0; i < children.getLength(); i++) { 190 if (children.item(i) instanceof Element) { 191 Element childElement = (Element) children.item(i); 192 String name = childElement.getNodeName(); 193 if (CONTAINER.equals(name)) { 194 MutablePicoContainer childContainer = parentContainer.getPico().makeChildContainer(); 195 NanoContainer childNanoContainer = new DefaultNanoContainer(parentContainer.getComponentClassLoader(), childContainer); 196 registerComponentsAndChildContainers(childNanoContainer, childElement, metaContainer); 197 } else if (COMPONENT_IMPLEMENTATION.equals(name) 198 || COMPONENT.equals(name)) { 199 registerComponentImplementation(parentContainer, childElement); 200 } else if (COMPONENT_INSTANCE.equals(name)) { 201 registerComponentInstance(parentContainer, childElement); 202 } else if (COMPONENT_ADAPTER.equals(name)) { 203 registerComponentAdapter(parentContainer, childElement, metaContainer); 204 } else if (COMPONENT_ADAPTER_FACTORY.equals(name)) { 205 addComponentAdapterFactory(childElement, metaContainer); 206 } else if (CLASSLOADER.equals(name)) { 207 registerClassLoader(parentContainer, childElement, metaContainer); 208 } else if (DECORATING_PICOCONTAINER.equals(name)) { 209 addDecoratingPicoContainer(parentContainer, childElement); 210 } else if (CLASSPATH.equals(name) != true) { 211 throw new NanoContainerMarkupException("Unsupported element:" + name); 212 } 213 } 214 } 215 } 216 217 218 private void addComponentAdapterFactory(Element element, NanoContainer metaContainer) throws MalformedURLException , ClassNotFoundException { 219 if (notSet(element.getAttribute(KEY))) { 220 throw new NanoContainerMarkupException("'" + KEY + "' attribute not specified for " + element.getNodeName()); 221 } 222 Element node = (Element)element.cloneNode(false); 223 NodeList children = element.getChildNodes(); 224 for (int i = 0; i < children.getLength(); i++) { 225 if (children.item(i) instanceof Element) { 226 Element childElement = (Element) children.item(i); 227 String name = childElement.getNodeName(); 228 if (COMPONENT_ADAPTER_FACTORY.equals(name)) { 229 if (!"".equals(childElement.getAttribute(KEY))) { 230 throw new NanoContainerMarkupException("'" + KEY + "' attribute must not be specified for nested " + element.getNodeName()); 231 } 232 childElement = (Element)childElement.cloneNode(true); 233 String key = String.valueOf(System.identityHashCode(childElement)); 234 childElement.setAttribute(KEY, key); 235 addComponentAdapterFactory(childElement, metaContainer); 236 Element parameter = node.getOwnerDocument().createElement(PARAMETER); 238 parameter.setAttribute(KEY, key); 239 node.appendChild(parameter); 240 } else if (PARAMETER.equals(name)) { 241 node.appendChild(childElement.cloneNode(true)); 242 } 243 } 244 } 245 registerComponentImplementation(metaContainer, node); 247 } 248 249 private void registerClassLoader(NanoContainer parentContainer, Element childElement, NanoContainer metaContainer) throws IOException , SAXException , ClassNotFoundException { 250 String parentClass = childElement.getAttribute("parentclassloader"); 251 ClassLoader parentClassLoader = parentContainer.getComponentClassLoader(); 252 if (parentClass != null && !EMPTY.equals(parentClass)) { 253 parentClassLoader = parentClassLoader.loadClass(parentClass).getClassLoader(); 254 } 255 NanoContainer nano = new DefaultNanoContainer(parentClassLoader, parentContainer.getPico()); 256 registerComponentsAndChildContainers(nano, childElement, metaContainer); 257 } 258 259 private void registerClasspath(NanoContainer container, Element classpathElement) throws IOException , ClassNotFoundException { 260 NodeList children = classpathElement.getChildNodes(); 261 for (int i = 0; i < children.getLength(); i++) { 262 if (children.item(i) instanceof Element) { 263 Element childElement = (Element) children.item(i); 264 265 String fileName = childElement.getAttribute(FILE); 266 String urlSpec = childElement.getAttribute(URL); 267 URL url = null; 268 if (urlSpec != null && !EMPTY.equals(urlSpec)) { 269 url = new URL (urlSpec); 270 } else { 271 File file = new File (fileName); 272 if (!file.exists()) { 273 throw new IOException (file.getAbsolutePath() + " doesn't exist"); 274 } 275 url = file.toURL(); 276 } 277 ClassPathElement cpe = container.addClassLoaderURL(url); 278 registerPermissions(cpe, childElement); 279 } 280 } 281 } 282 283 private void registerPermissions(ClassPathElement classPathElement, Element classPathXmlElement) throws ClassNotFoundException { 284 NodeList children = classPathXmlElement.getChildNodes(); 285 for (int i = 0; i < children.getLength(); i++) { 286 if (children.item(i) instanceof Element) { 287 Element childElement = (Element) children.item(i); 288 289 String permissionClassName = childElement.getAttribute(CLASSNAME); 290 String action = childElement.getAttribute(CONTEXT); 291 String value = childElement.getAttribute(VALUE); 292 MutablePicoContainer mpc = new DefaultPicoContainer(); 293 mpc.registerComponentImplementation(Permission .class, Class.forName(permissionClassName),new Parameter[] {new ConstantParameter(action), new ConstantParameter(value)}); 294 295 Permission permission = (Permission ) mpc.getComponentInstanceOfType(Permission .class); 296 classPathElement.grantPermission(permission); 297 } 298 } 299 300 } 301 302 private void registerComponentImplementation(NanoContainer container, Element element) throws ClassNotFoundException , MalformedURLException { 303 String className = element.getAttribute(CLASS); 304 if (notSet(className)) { 305 throw new NanoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName()); 306 } 307 308 Parameter[] parameters = createChildParameters(container, element); 309 Class clazz = container.getComponentClassLoader().loadClass(className); 310 Object key = element.getAttribute(KEY); 311 String classKey = element.getAttribute(CLASS_NAME_KEY); 312 if (notSet(key)) { 313 if (!notSet(classKey)) { 314 key = getClassLoader().loadClass(classKey); 315 } else { 316 key = clazz; 317 } 318 } 319 if (parameters == null) { 320 container.getPico().registerComponentImplementation(key, clazz); 321 } else { 322 container.getPico().registerComponentImplementation(key, clazz, parameters); 323 } 324 } 325 326 private void addDecoratingPicoContainer(NanoContainer parentContainer, Element childElement) throws ClassNotFoundException { 327 String className = childElement.getAttribute("class"); 328 329 parentContainer.addDecoratingPicoContainer(getClassLoader().loadClass(className)); 330 331 } 332 333 334 335 private Parameter[] createChildParameters(NanoContainer container, Element element) throws ClassNotFoundException , MalformedURLException { 336 List parametersList = new ArrayList (); 337 NodeList children = element.getChildNodes(); 338 for (int i = 0; i < children.getLength(); i++) { 339 if (children.item(i) instanceof Element) { 340 Element childElement = (Element) children.item(i); 341 if (PARAMETER.equals(childElement.getNodeName())) { 342 parametersList.add(createParameter(container.getPico(), childElement)); 343 } 344 } 345 } 346 347 Parameter[] parameters = null; 348 if (!parametersList.isEmpty()) { 349 parameters = (Parameter[]) parametersList.toArray(new Parameter[parametersList.size()]); 350 } 351 return parameters; 352 } 353 354 private Parameter createParameter(PicoContainer pico, Element element) throws ClassNotFoundException , MalformedURLException { 355 final Parameter parameter; 356 String key = element.getAttribute(KEY); 357 if (key != null && !EMPTY.equals(key)) { 358 parameter = new ComponentParameter(key); 359 } else if (getFirstChildElement(element, false) == null) { 360 parameter = new ComponentParameter(); 361 } else { 362 Object instance = createInstance(pico, element); 363 parameter = new ConstantParameter(instance); 364 } 365 return parameter; 366 } 367 368 private void registerComponentInstance(NanoContainer container, Element element) throws ClassNotFoundException , PicoCompositionException, MalformedURLException { 369 Object instance = createInstance(container.getPico(), element); 370 String key = element.getAttribute(KEY); 371 String classKey = element.getAttribute(CLASS_NAME_KEY); 372 if (notSet(key)) { 373 if (!notSet(classKey)) { 374 container.getPico().registerComponentInstance(getClassLoader().loadClass(classKey), instance); 375 } else { 376 container.getPico().registerComponentInstance(instance); 377 } 378 } else { 379 container.getPico().registerComponentInstance(key, instance); 380 } 381 } 382 383 private Object createInstance(PicoContainer pico, Element element) throws ClassNotFoundException , MalformedURLException { 384 XMLComponentInstanceFactory factory = createComponentInstanceFactory(element.getAttribute(FACTORY)); 385 Element instanceElement = getFirstChildElement(element, true); 386 return factory.makeInstance(pico, instanceElement, getClassLoader()); 387 } 388 389 private Element getFirstChildElement(Element parent, boolean fail) { 390 NodeList children = parent.getChildNodes(); 391 Element child = null; 392 for (int i = 0; i < children.getLength(); i++) { 393 if (children.item(i) instanceof Element) { 394 child = (Element) children.item(i); 395 break; 396 } 397 } 398 if (child == null && fail) { 399 throw new NanoContainerMarkupException(parent.getNodeName() + " needs a child element"); 400 } 401 return child; 402 } 403 404 private XMLComponentInstanceFactory createComponentInstanceFactory(String factoryClass) throws ClassNotFoundException { 405 if ( notSet(factoryClass)) { 406 if (componentInstanceFactory != null) { 409 return componentInstanceFactory; 410 } 411 factoryClass = DEFAULT_COMPONENT_INSTANCE_FACTORY; 412 } 413 414 NanoContainer adapter = new DefaultNanoContainer(getClassLoader()); 415 adapter.registerComponentImplementation(XMLComponentInstanceFactory.class.getName(), factoryClass); 416 return (XMLComponentInstanceFactory) adapter.getPico().getComponentInstances().get(0); 417 } 418 419 private void registerComponentAdapter(NanoContainer container, Element element, NanoContainer metaContainer) throws ClassNotFoundException , PicoCompositionException, MalformedURLException { 420 String className = element.getAttribute(CLASS); 421 if (notSet(className)) { 422 throw new NanoContainerMarkupException("'" + CLASS + "' attribute not specified for " + element.getNodeName()); 423 } 424 Class implementationClass = getClassLoader().loadClass(className); 425 Object key = element.getAttribute(KEY); 426 String classKey = element.getAttribute(CLASS_NAME_KEY); 427 if (notSet(key)) { 428 if (!notSet(classKey)) { 429 key = getClassLoader().loadClass(classKey); 430 } else { 431 key = implementationClass; 432 } 433 } 434 Parameter[] parameters = createChildParameters(container, element); 435 ComponentAdapterFactory componentAdapterFactory = createComponentAdapterFactory(element.getAttribute(FACTORY), metaContainer); 436 container.getPico().registerComponent(componentAdapterFactory.createComponentAdapter(key, implementationClass, parameters)); 437 } 438 439 private ComponentAdapterFactory createComponentAdapterFactory(String factoryName, NanoContainer metaContainer) throws ClassNotFoundException , PicoCompositionException { 440 if ( notSet(factoryName)) { 441 factoryName = DEFAULT_COMPONENT_ADAPTER_FACTORY; 442 } 443 final Object key; 444 if (metaContainer.getPico().getComponentAdapter(factoryName) != null) { 445 key = factoryName; 446 } else { 447 metaContainer.registerComponentImplementation(new ClassNameKey(ComponentAdapterFactory.class.getName()), factoryName); 448 key = ComponentAdapterFactory.class; 449 } 450 return (ComponentAdapterFactory) metaContainer.getPico().getComponentInstance(key); 451 } 452 453 private ComponentMonitor createComponentMonitor(String monitorName) throws ClassNotFoundException , PicoCompositionException { 454 if (notSet(monitorName)) { 455 monitorName = DEFAULT_COMPONENT_MONITOR; 456 } 457 Class monitorClass = getClassLoader().loadClass(monitorName); 458 try { 459 return (ComponentMonitor) monitorClass.newInstance(); 460 } catch (InstantiationException e) { 461 throw new NanoContainerMarkupException(e); 462 } catch (IllegalAccessException e) { 463 throw new NanoContainerMarkupException(e); 464 } 465 } 466 467 private boolean notSet(Object string) { 468 return string == null || string.equals(EMPTY); 469 } 470 471 } 472 | Popular Tags |