/**
   * Generate the xml top level element and start streaming the components.
   *
   * @param components
   * @param contentHandler
   * @throws SAXException
   */
  protected static void generateXML(
      Components components, ContentHandler contentHandler, boolean isScrPrivateFile)
      throws SAXException {
    // detect namespace to use
    final String namespace;
    if (components.getSpecVersion() == Constants.VERSION_1_0) {
      namespace = NAMESPACE_URI_1_0;
    } else if (components.getSpecVersion() == Constants.VERSION_1_1) {
      namespace = NAMESPACE_URI_1_1;
    } else {
      namespace = NAMESPACE_URI_1_1_FELIX;
    }
    contentHandler.startDocument();
    contentHandler.startPrefixMapping(PREFIX, namespace);

    // wrapper element to generate well formed xml
    contentHandler.startElement(
        "",
        ComponentDescriptorIO.COMPONENTS,
        ComponentDescriptorIO.COMPONENTS,
        new AttributesImpl());
    IOUtils.newline(contentHandler);

    for (final Component component : components.getComponents()) {
      if (component.isDs()) {
        generateXML(namespace, component, contentHandler, isScrPrivateFile);
      }
    }
    // end wrapper element
    contentHandler.endElement(
        "", ComponentDescriptorIO.COMPONENTS, ComponentDescriptorIO.COMPONENTS);
    IOUtils.newline(contentHandler);
    contentHandler.endPrefixMapping(PREFIX);
    contentHandler.endDocument();
  }
    public void startElement(String uri, String localName, String name, Attributes attributes)
        throws SAXException {
      // according to the spec, the elements should have the namespace,
      // except when the root element is the "component" element
      // So we check this for the first element, we receive.
      if (this.firstElement) {
        this.firstElement = false;
        if (localName.equals(COMPONENT) && "".equals(uri)) {
          this.overrideNamespace = NAMESPACE_URI_1_0;
        }
      }

      if (this.overrideNamespace != null && "".equals(uri)) {
        uri = this.overrideNamespace;
      }

      // however the spec also states that the inner elements
      // of a component are unqualified, so they don't have
      // the namespace - we allow both: with or without namespace!
      if (this.isComponent && "".equals(uri)) {
        uri = NAMESPACE_URI_1_0;
      }

      // from here on, uri has the namespace regardless of the used xml format
      if (NAMESPACE_URI_1_0.equals(uri)
          || NAMESPACE_URI_1_1.equals(uri)
          || NAMESPACE_URI_1_1_FELIX.equals(uri)) {

        if (NAMESPACE_URI_1_1.equals(uri)) {
          components.setSpecVersion(Constants.VERSION_1_1);
        } else if (NAMESPACE_URI_1_1_FELIX.equals(uri)) {
          components.setSpecVersion(Constants.VERSION_1_1_FELIX);
        }

        if (localName.equals(COMPONENT)) {
          this.isComponent = true;

          this.currentComponent = new Component();
          this.currentComponent.setName(attributes.getValue(COMPONENT_ATTR_NAME));

          // enabled attribute is optional
          if (attributes.getValue(COMPONENT_ATTR_ENABLED) != null) {
            this.currentComponent.setEnabled(
                Boolean.valueOf(attributes.getValue(COMPONENT_ATTR_ENABLED)));
          }

          // immediate attribute is optional
          if (attributes.getValue(COMPONENT_ATTR_IMMEDIATE) != null) {
            this.currentComponent.setImmediate(
                Boolean.valueOf(attributes.getValue(COMPONENT_ATTR_IMMEDIATE)));
          }

          this.currentComponent.setFactory(attributes.getValue(COMPONENT_ATTR_FACTORY));

          // check for version 1.1 attributes
          if (components.getSpecVersion() == Constants.VERSION_1_1) {
            this.currentComponent.setConfigurationPolicy(
                attributes.getValue(COMPONENT_ATTR_POLICY));
            this.currentComponent.setActivate(attributes.getValue(COMPONENT_ATTR_ACTIVATE));
            this.currentComponent.setDeactivate(attributes.getValue(COMPONENT_ATTR_DEACTIVATE));
            this.currentComponent.setModified(attributes.getValue(COMPONENT_ATTR_MODIFIED));
          }
        } else if (localName.equals(IMPLEMENTATION)) {
          // Set the implementation class name (mandatory)
          final Implementation impl = new Implementation();
          this.currentComponent.setImplementation(impl);
          impl.setClassname(attributes.getValue("class"));

        } else if (localName.equals(PROPERTY)) {

          // read the property, unless it is the service.pid
          // property which must not be inherited
          final String propName = attributes.getValue("name");
          if (!org.osgi.framework.Constants.SERVICE_PID.equals(propName)) {
            final Property prop = new Property();

            prop.setName(propName);
            prop.setType(attributes.getValue("type"));

            if (attributes.getValue("value") != null) {
              prop.setValue(attributes.getValue("value"));
              this.currentComponent.addProperty(prop);
            } else {
              // hold the property pending as we have a multi value
              this.pendingProperty = prop;
            }
            // check for abstract properties
            prop.setLabel(attributes.getValue("label"));
            prop.setDescription(attributes.getValue("description"));
            prop.setCardinality(attributes.getValue("cardinality"));
            final String pValue = attributes.getValue("private");
            if (pValue != null) {
              prop.setPrivate(Boolean.valueOf(pValue).booleanValue());
            }
          }

        } else if (localName.equals("properties")) {

          // TODO: implement the properties tag

        } else if (localName.equals(SERVICE)) {

          this.currentService = new Service();

          this.currentService.setServicefactory(attributes.getValue("servicefactory"));

          this.currentComponent.setService(this.currentService);

        } else if (localName.equals(INTERFACE)) {
          final Interface interf = new Interface();
          this.currentService.addInterface(interf);
          interf.setInterfacename(attributes.getValue("interface"));

        } else if (localName.equals(REFERENCE)) {
          final Reference ref = new Reference();

          ref.setName(attributes.getValue("name"));
          ref.setInterfacename(attributes.getValue("interface"));
          ref.setCardinality(attributes.getValue("cardinality"));
          ref.setPolicy(attributes.getValue("policy"));
          ref.setTarget(attributes.getValue("target"));
          ref.setBind(attributes.getValue("bind"));
          ref.setUnbind(attributes.getValue("unbind"));

          if (attributes.getValue("checked") != null) {
            ref.setChecked(Boolean.valueOf(attributes.getValue("checked")).booleanValue());
          }
          if (attributes.getValue("strategy") != null) {
            ref.setStrategy(attributes.getValue("strategy"));
          }

          this.currentComponent.addReference(ref);
        }
      }
    }