/** JNDI object factory so the proxy can be used as a resource. */
  public Object getObjectInstance(
      Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
    Reference ref = (Reference) obj;

    String api = null;
    String url = null;
    String user = null;
    String password = null;

    for (int i = 0; i < ref.size(); i++) {
      RefAddr addr = ref.get(i);

      String type = addr.getType();
      String value = (String) addr.getContent();

      if (type.equals("type")) api = value;
      else if (type.equals("url")) url = value;
      else if (type.equals("user")) setUser(value);
      else if (type.equals("password")) setPassword(value);
    }

    if (url == null) throw new NamingException("`url' must be configured for HessianProxyFactory.");
    // XXX: could use meta protocol to grab this
    if (api == null)
      throw new NamingException("`type' must be configured for HessianProxyFactory.");

    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    Class apiClass = Class.forName(api, false, loader);

    return create(apiClass, url);
  }
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }

    if (!(o instanceof Reference)) {
      return false;
    }
    Reference oref = (Reference) o;

    boolean idsEqual = (id == null ? oref.getId() == null : id.equals(oref.getId()));
    boolean urisEqual = (uri == null ? oref.getURI() == null : uri.equals(oref.getURI()));
    boolean typesEqual = (type == null ? oref.getType() == null : type.equals(oref.getType()));
    boolean digestValuesEqual = Arrays.equals(digestValue, oref.getDigestValue());

    return (digestMethod.equals(oref.getDigestMethod())
        && idsEqual
        && urisEqual
        && typesEqual
        && transforms.equals(oref.getTransforms()));
  }
  /**
   * Write the xml for a {@link Reference}.
   *
   * @param reference
   * @param contentHandler
   * @throws SAXException
   */
  protected static void generateXML(
      final String namespace,
      Reference reference,
      ContentHandler contentHandler,
      boolean isScrPrivateFile)
      throws SAXException {
    final AttributesImpl ai = new AttributesImpl();
    IOUtils.addAttribute(ai, "name", reference.getName());
    IOUtils.addAttribute(ai, "interface", reference.getInterfacename());
    IOUtils.addAttribute(ai, "cardinality", reference.getCardinality());
    IOUtils.addAttribute(ai, "policy", reference.getPolicy());
    IOUtils.addAttribute(ai, "target", reference.getTarget());
    IOUtils.addAttribute(ai, "bind", reference.getBind());
    IOUtils.addAttribute(ai, "unbind", reference.getUnbind());

    // attributes new in 1.1-felix (FELIX-1893)
    if (NAMESPACE_URI_1_1_FELIX.equals(namespace)) {
      IOUtils.addAttribute(ai, "updated", reference.getUpdated());
    }

    if (isScrPrivateFile) {
      IOUtils.addAttribute(ai, "checked", String.valueOf(reference.isChecked()));
      IOUtils.addAttribute(ai, "strategy", reference.getStrategy());
    }
    IOUtils.indent(contentHandler, 2);
    contentHandler.startElement(
        INNER_NAMESPACE_URI,
        ComponentDescriptorIO.REFERENCE,
        ComponentDescriptorIO.REFERENCE_QNAME,
        ai);
    contentHandler.endElement(
        INNER_NAMESPACE_URI,
        ComponentDescriptorIO.REFERENCE,
        ComponentDescriptorIO.REFERENCE_QNAME);
    IOUtils.newline(contentHandler);
  }
  public Reference createReference(Object bean) throws NamingException {
    try {
      BeanInfo bi = Introspector.getBeanInfo(bean.getClass());
      PropertyDescriptor[] pds = bi.getPropertyDescriptors();
      List refAddrs = new ArrayList();
      String factoryClassLocation = defaultFactoryClassLocation;

      boolean using_ref_props = referenceProperties.size() > 0;

      // we only include this so that on dereference we are not surprised to find some properties
      // missing
      if (using_ref_props)
        refAddrs.add(
            new BinaryRefAddr(REF_PROPS_KEY, SerializableUtils.toByteArray(referenceProperties)));

      for (int i = 0, len = pds.length; i < len; ++i) {
        PropertyDescriptor pd = pds[i];
        String propertyName = pd.getName();
        // System.err.println("Making Reference: " + propertyName);

        if (using_ref_props && !referenceProperties.contains(propertyName)) {
          // System.err.println("Not a ref_prop -- continuing.");
          continue;
        }

        Class propertyType = pd.getPropertyType();
        Method getter = pd.getReadMethod();
        Method setter = pd.getWriteMethod();
        if (getter != null
            && setter != null) // only use properties that are both readable and writable
        {
          Object val = getter.invoke(bean, EMPTY_ARGS);
          // System.err.println( "val: " + val );
          if (propertyName.equals("factoryClassLocation")) {
            if (String.class != propertyType)
              throw new NamingException(
                  this.getClass().getName()
                      + " requires a factoryClassLocation property to be a string, "
                      + propertyType.getName()
                      + " is not valid.");
            factoryClassLocation = (String) val;
          }

          if (val == null) {
            RefAddr addMe = new BinaryRefAddr(propertyName, NULL_TOKEN_BYTES);
            refAddrs.add(addMe);
          } else if (Coerce.canCoerce(propertyType)) {
            RefAddr addMe = new StringRefAddr(propertyName, String.valueOf(val));
            refAddrs.add(addMe);
          } else // other Object properties
          {
            RefAddr addMe = null;
            PropertyEditor pe = BeansUtils.findPropertyEditor(pd);
            if (pe != null) {
              pe.setValue(val);
              String textValue = pe.getAsText();
              if (textValue != null) addMe = new StringRefAddr(propertyName, textValue);
            }
            if (addMe == null) // property editor approach failed
            addMe =
                  new BinaryRefAddr(
                      propertyName,
                      SerializableUtils.toByteArray(
                          val, indirector, IndirectPolicy.INDIRECT_ON_EXCEPTION));
            refAddrs.add(addMe);
          }
        } else {
          // 				System.err.println(this.getClass().getName() +
          // 						   ": Skipping " + propertyName + " because it is " + (setter == null ?
          // "read-only." : "write-only."));

          if (logger.isLoggable(MLevel.WARNING))
            logger.warning(
                this.getClass().getName()
                    + ": Skipping "
                    + propertyName
                    + " because it is "
                    + (setter == null ? "read-only." : "write-only."));
        }
      }
      Reference out =
          new Reference(bean.getClass().getName(), factoryClassName, factoryClassLocation);
      for (Iterator ii = refAddrs.iterator(); ii.hasNext(); ) out.add((RefAddr) ii.next());
      return out;
    } catch (Exception e) {
      // e.printStackTrace();
      if (Debug.DEBUG && logger.isLoggable(MLevel.FINE))
        logger.log(MLevel.FINE, "Exception trying to create Reference.", e);

      throw new NamingException("Could not create reference from bean: " + e.toString());
    }
  }
    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);
        }
      }
    }