Clover coverage report - Ledge Container - SNAPSHOT
Coverage timestamp: Fri Nov 17 2006 05:16:03 CET
file stats: LOC: 764   Methods: 51
NCLOC: 580   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
CompositionContentHandler.java 80.8% 89.6% 92.2% 88.5%
coverage coverage
 1   
 2    package org.objectledge.pico.xml;
 3   
 4    import java.lang.reflect.Constructor;
 5    import java.util.ArrayList;
 6    import java.util.EnumSet;
 7    import java.util.HashMap;
 8    import java.util.LinkedList;
 9    import java.util.List;
 10    import java.util.Map;
 11    import java.util.Set;
 12   
 13    import org.objectledge.pico.AliasComponentAdapter;
 14    import org.objectledge.pico.SequenceParameter;
 15    import org.objectledge.pico.StringParameter;
 16    import org.objectledge.pico.customization.CustomizingComponentParameter;
 17    import org.picocontainer.ComponentAdapter;
 18    import org.picocontainer.MutablePicoContainer;
 19    import org.picocontainer.Parameter;
 20    import org.picocontainer.PicoContainer;
 21    import org.picocontainer.defaults.ComponentAdapterFactory;
 22    import org.picocontainer.defaults.DefaultComponentAdapterFactory;
 23    import org.picocontainer.defaults.DefaultPicoContainer;
 24    import org.xml.sax.Attributes;
 25    import org.xml.sax.Locator;
 26    import org.xml.sax.SAXException;
 27    import org.xml.sax.SAXParseException;
 28    import org.xml.sax.helpers.DefaultHandler;
 29   
 30    /**
 31    * SAX handler for the composition markup.
 32    */
 33    class CompositionContentHandler extends DefaultHandler
 34    {
 35    private static final Class[] NO_ARG = new Class[] { };
 36    private static final Class[] PICOCONTAINER_ARGS = new Class[] { ComponentAdapterFactory.class,
 37    PicoContainer.class };
 38    private static final Class[] COMPONENT_ADAPTER_FACTORY_ARG =
 39    new Class[] { ComponentAdapterFactory.class };
 40    private static final Class DEFAULT_CONTAINER_IMPL = DefaultPicoContainer.class;
 41    private static final Parameter[] NO_PARAMETERS = new Parameter[] { };
 42   
 43    private final PicoContainer topLevelParentContainer;
 44    private final ClassLoader classLoader;
 45   
 46    private PicoContainer result;
 47   
 48    private final LinkedList<State> stateStack =
 49    new LinkedList<State>();
 50    private final LinkedList<MutablePicoContainer> containerStack =
 51    new LinkedList<MutablePicoContainer>();
 52    private final LinkedList<ComponentAdapterFactory> factoryStack =
 53    new LinkedList<ComponentAdapterFactory>();
 54    private final LinkedList<ComponentInfo> componentStack =
 55    new LinkedList<ComponentInfo>();
 56    private final LinkedList<SequenceInfo> sequenceStack =
 57    new LinkedList<SequenceInfo>();
 58    private Locator locator;
 59   
 60    /**
 61    * Creates new LedgeCompositionContentHandler instance.
 62    *
 63    * @param parentContainer the top level parent container.
 64    * @param assemblyScope assembly scope.
 65    */
 66  1204 public CompositionContentHandler(final PicoContainer parentContainer,
 67    final ClassLoader classLoader, final Object assemblyScope)
 68    {
 69  1204 this.topLevelParentContainer = parentContainer;
 70  1204 this.classLoader = classLoader;
 71   
 72  1204 stateStack.add(State.TOP);
 73  1204 ComponentAdapterFactory factory = (ComponentAdapterFactory)parentContainer.
 74    getComponentInstance(ComponentAdapterFactory.class);
 75  1204 if(factory == null)
 76    {
 77  1032 factory = new DefaultComponentAdapterFactory();
 78    }
 79  1204 factoryStack.add(factory);
 80    }
 81   
 82    /**
 83    * Return the composed container.
 84    *
 85    * @return the composed container.
 86    */
 87  946 public PicoContainer getResult()
 88    {
 89  946 return result;
 90    }
 91   
 92    //////////////////////////////////////////////////////////////////////////////////////////////
 93   
 94    /**
 95    * {@inheritDoc}
 96    */
 97  14448 public void startElement(String uri, String localName, String qName, Attributes attributes)
 98    throws SAXException
 99    {
 100  14448 State current = stateStack.getLast();
 101  14448 State target = State.fromTag(localName);
 102  14448 if(target == null)
 103    {
 104  0 throw new SAXParseException("unknown tag " + localName, locator);
 105    }
 106  14448 if(State.allowedTransition(current, target))
 107    {
 108  14448 target.start(this, attributes);
 109  14448 stateStack.add(target);
 110    }
 111    else
 112    {
 113  0 throw new SAXParseException("unexpected opening tag " + target.getTag() + " inside " +
 114    current.getTag(), locator);
 115    }
 116    }
 117   
 118    /**
 119    * {@inheritDoc}
 120    */
 121  14448 public void endElement(String uri, String localName, String qName)
 122    throws SAXException
 123    {
 124  14448 State current = stateStack.removeLast();
 125  14448 if(State.fromTag(localName).equals(current))
 126    {
 127  14448 current.end(this);
 128    }
 129    else
 130    {
 131  0 throw new SAXParseException("expecting closing tag " + current.getTag(), locator);
 132    }
 133    }
 134   
 135    /**
 136    * {@inheritDoc}
 137    */
 138  1204 public void setDocumentLocator(final Locator locator)
 139    {
 140  1204 this.locator = locator;
 141    }
 142   
 143    //////////////////////////////////////////////////////////////////////////////////////////////
 144   
 145  1462 void startContainer(Attributes attributes)
 146    throws SAXException
 147    {
 148  1462 if(result != null)
 149    {
 150  0 throw new SAXParseException("top level container already defined", locator);
 151    }
 152  1462 MutablePicoContainer container;
 153  1462 if(containerStack.isEmpty())
 154    {
 155  1204 container = makeContainer(topLevelParentContainer, factoryStack.getLast(), attributes);
 156    }
 157    else
 158    {
 159  258 container = makeContainer(containerStack.getLast(), factoryStack.getLast(), attributes);
 160  258 containerStack.getLast().addChildContainer(container);
 161  258 Object key = makeKey(attributes, false);
 162  258 if(key != null)
 163    {
 164  172 containerStack.getLast().registerComponentInstance(key, container);
 165    }
 166    }
 167  1462 containerStack.add(container);
 168    }
 169   
 170  1462 void endContainer()
 171    throws SAXException
 172    {
 173  1462 PicoContainer container = containerStack.removeLast();
 174  1462 if(containerStack.isEmpty())
 175    {
 176  1204 result = container;
 177    }
 178    }
 179   
 180  688 void startFactory(Attributes attributes) throws SAXException
 181    {
 182  688 Object key = makeKey(attributes, false);
 183  688 Object factory = containerStack.getLast().getComponentInstance(key);
 184  688 if(factory == null)
 185    {
 186  0 new SAXParseException("component "+key+" not found", locator);
 187    }
 188  688 if(ComponentAdapterFactory.class.isAssignableFrom(factory.getClass()))
 189    {
 190  688 new SAXParseException(factory.getClass() + " does not implement " +
 191    ComponentAdapterFactory.class, locator);
 192    }
 193  688 factoryStack.add((ComponentAdapterFactory)factory);
 194    }
 195   
 196  688 void endFactory()
 197    throws SAXException
 198    {
 199  688 factoryStack.removeLast();
 200    }
 201   
 202  5762 void startComponent(Attributes attributes)
 203    throws SAXException
 204    {
 205  5762 Object key = makeKey(attributes, true);
 206  5762 Class implClass = loadClass(attributes, null);
 207  5762 if(implClass == null)
 208    {
 209  0 throw new SAXParseException("missing class attribute", locator);
 210    }
 211  5762 componentStack.add(new ComponentInfo(key, implClass));
 212    }
 213   
 214  5762 void endComponent()
 215    throws SAXException
 216    {
 217  5762 ComponentInfo info = componentStack.removeLast();
 218  5762 ComponentAdapter adapter = info.makeAdapter(factoryStack.getLast());
 219  5762 if(ComponentAdapter.class.isAssignableFrom(adapter.getComponentImplementation()))
 220    {
 221  344 adapter = (ComponentAdapter)adapter.getComponentInstance(containerStack.getLast());
 222    }
 223  5762 containerStack.getLast().registerComponent(adapter);
 224  5762 int i = stateStack.size() - 1;
 225  5762 while(true)
 226    {
 227  6278 switch(stateStack.get(i))
 228    {
 229  516 case FACTORY:
 230  516 i--;
 231  516 continue;
 232  4902 case CONTAINER:
 233  4902 break;
 234  344 case COMPONENT:
 235  344 componentStack.getLast().addParameter(makeComponentParameter(info.getKey()));
 236  344 break;
 237  516 case SEQUENCE:
 238  516 sequenceStack.getLast().addParameter(makeComponentParameter(info.getKey()));
 239  516 break;
 240  0 default:
 241  0 throw new SAXParseException("unexpected tag parent tag " +
 242    stateStack.get(i).getTag(), locator);
 243    }
 244  5762 return;
 245    }
 246    }
 247   
 248  5590 void startParameter(Attributes attributes)
 249    throws SAXException
 250    {
 251  5590 Parameter parameter;
 252  5590 String value = attributes.getValue("value");
 253  5590 if(value != null)
 254    {
 255  3440 Class valueClass = loadClass(attributes, null);
 256  3440 parameter = new StringParameter(value, valueClass);
 257    }
 258    else
 259    {
 260  2150 Object key = makeKey(attributes, false);
 261  2150 parameter = makeComponentParameter(key);
 262    }
 263  5590 switch(stateStack.getLast())
 264    {
 265  4472 case COMPONENT:
 266  4472 componentStack.getLast().addParameter(parameter);
 267  4472 break;
 268  1118 case SEQUENCE:
 269  1118 sequenceStack.getLast().addParameter(parameter);
 270  1118 break;
 271  0 default:
 272  0 throw new SAXParseException("unexpected parent tag "+stateStack.getLast().getTag(),
 273    locator);
 274    }
 275    }
 276   
 277  5590 void endParameter()
 278    {
 279    // nothing to do
 280    }
 281   
 282  774 void startSequence(Attributes attributes)
 283    throws SAXException
 284    {
 285  774 SequenceInfo info = new SequenceInfo(loadClass(attributes, null));
 286  774 sequenceStack.add(info);
 287    }
 288   
 289  774 void endSequence()
 290    throws SAXException
 291    {
 292  774 SequenceInfo info = sequenceStack.removeLast();
 293  774 Parameter sequence = info.makeSequence();
 294  774 switch(stateStack.getLast())
 295    {
 296  602 case COMPONENT:
 297  602 componentStack.getLast().addParameter(sequence);
 298  602 break;
 299  172 case SEQUENCE:
 300  172 sequenceStack.getLast().addParameter(sequence);
 301  172 break;
 302  0 default:
 303  0 throw new SAXParseException("unexpected parent tag "+stateStack.getLast().getTag(),
 304    locator);
 305    }
 306    }
 307   
 308  172 void startAlias(Attributes attributes)
 309    throws SAXException
 310    {
 311  172 Object key = makeKey(attributes, false);
 312  172 if(key == null)
 313    {
 314  0 throw new SAXParseException("class-key or key expected", locator);
 315    }
 316  172 Object ref = makeRef(attributes);
 317  172 ComponentAdapter adapter = containerStack.getLast().getComponentAdapter(ref);
 318  172 if(adapter == null)
 319    {
 320  0 throw new SAXParseException("missing component " + ref, locator);
 321    }
 322  172 ComponentAdapter alias = new AliasComponentAdapter(key, adapter);
 323  172 containerStack.getLast().registerComponent(alias);
 324    }
 325   
 326  172 void endAlias()
 327    {
 328    // nothing to do
 329    }
 330   
 331    /////////////////////////////////////////////////////////////////////////////////////////////
 332   
 333    /**
 334    * Instantiate a container.
 335    *
 336    * @param parent parent container.
 337    * @param attributes element attributes.
 338    * @return a MutablePicoContainer.
 339    * @throws SAXException if the input data is incorrect.
 340    */
 341  1462 private MutablePicoContainer makeContainer(PicoContainer parent,
 342    ComponentAdapterFactory factory, Attributes attributes)
 343    throws SAXException
 344    {
 345  1462 Class<? extends MutablePicoContainer> implClass = loadClass(attributes,
 346    DEFAULT_CONTAINER_IMPL);
 347  1462 Constructor<? extends MutablePicoContainer> ctor;
 348  1462 try
 349    {
 350  1462 ctor = implClass.getConstructor(PICOCONTAINER_ARGS);
 351    }
 352    catch(NoSuchMethodException e)
 353    {
 354  0 throw new SAXParseException("constructor " + implClass.getName()
 355    + ".<init>(PicoContainer) not found", locator, e);
 356    }
 357  1462 try
 358    {
 359  1462 return ctor.newInstance(factory, parent);
 360    }
 361    catch(Exception e)
 362    {
 363  0 throw new SAXParseException("constructor invocation failed", locator, e);
 364    }
 365    }
 366   
 367    /**
 368    * Prepare a key based on element attributes.
 369    *
 370    * @param attributes element attributes.
 371    * @param useClass true to use "class" attribute if "class-key" and "key" undefined.
 372    * @return component key.
 373    * @throws SAXException
 374    */
 375  9030 private Object makeKey(Attributes attributes, boolean useClass)
 376    throws SAXException
 377    {
 378  9030 String classKey = attributes.getValue("class-key");
 379  9030 if(classKey != null)
 380    {
 381  1720 return loadClass(classKey);
 382    }
 383  7310 String key = attributes.getValue("key");
 384  7310 if(key != null)
 385    {
 386  3010 return key;
 387    }
 388  4300 if(attributes.getValue("anon") != null)
 389    {
 390  860 return new AnonymousKey();
 391    }
 392  3440 String implicitClassKey = attributes.getValue("class");
 393  3440 if(useClass && implicitClassKey != null)
 394    {
 395  2666 return loadClass(implicitClassKey);
 396    }
 397  774 return null;
 398    }
 399   
 400  172 private Object makeRef(Attributes attributes)
 401    throws SAXException
 402    {
 403  172 String classRef = attributes.getValue("class-ref");
 404  172 if(classRef != null)
 405    {
 406  86 return loadClass(classRef);
 407    }
 408  86 String ref = attributes.getValue("ref");
 409  86 if(ref != null)
 410    {
 411  86 return ref;
 412    }
 413  0 throw new SAXParseException("class-ref or ref attribute expected", locator);
 414    }
 415   
 416    /**
 417    * Prepare a component parameter.
 418    *
 419    * @param key the key or null for wildcard component parameter.
 420    * @return a Parameter designating the component with the given key.
 421    */
 422  3010 private Parameter makeComponentParameter(Object key)
 423    {
 424  3010 if(key != null)
 425    {
 426  2322 return new CustomizingComponentParameter(key);
 427    }
 428    else
 429    {
 430  688 return new CustomizingComponentParameter();
 431    }
 432    }
 433   
 434    /**
 435    * Load a class.
 436    *
 437    * @param attributes element attributes.
 438    * @param defaultClass class name to return if "class" attribute is not defined.
 439    * @return the class.
 440    * @throws SAXException if the class could not be loaded.
 441    */
 442  11438 private Class loadClass(Attributes attributes, Class defaultClass)
 443    throws SAXException
 444    {
 445  11438 String className = attributes.getValue("class");
 446  11438 if(className == null)
 447    {
 448  4300 return defaultClass;
 449    }
 450  7138 return loadClass(className);
 451    }
 452   
 453    private static final Map<String,String> PRIMITIVE_TO_BOXED = new HashMap<String,String>();
 454    static
 455    {
 456  258 PRIMITIVE_TO_BOXED.put("int", Integer.class.getName());
 457  258 PRIMITIVE_TO_BOXED.put("byte", Byte.class.getName());
 458  258 PRIMITIVE_TO_BOXED.put("short", Short.class.getName());
 459  258 PRIMITIVE_TO_BOXED.put("long", Long.class.getName());
 460  258 PRIMITIVE_TO_BOXED.put("float", Float.class.getName());
 461  258