Package com.google.gdata.data

Source Code of com.google.gdata.data.AbstractExtension$AttributesHandler

/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package com.google.gdata.data;

import com.google.gdata.util.common.xml.XmlNamespace;
import com.google.gdata.util.common.xml.XmlWriter;
import com.google.gdata.util.ParseException;
import com.google.gdata.util.XmlParser;

import org.xml.sax.Attributes;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* Common extension implementation for sharing code among implementers of
* {@link Extension}.  The information contained in this class is:
* <ol>
* <li>XML namespace of the extension</li>
* <li>XML local name of the extension</li>
* <li>if the extension is mutable</li>
* </ol>
*
*
*/
public abstract class AbstractExtension implements Extension {

  /** XML namespace for this extension or <code>null</code> if not defined */
  protected final XmlNamespace namespace;

  /** XML local name for this extension or <code>null</code> if not defined */
  protected final String localName;

  /**
   * Indicates that the extension is constant after construction ({@code false}
   * by default).
   */
  private boolean immutable;
  public final boolean isImmutable() { return immutable; }
  public final void setImmutable(boolean isImmutable) {
    this.immutable = isImmutable;
  }

  /**
   * Constructs an extension bound to a specific XML representation.  The
   * concrete subclass must have an {@link ExtensionDescription.Default}
   * attribute defined to use this constructor.
   */
  protected AbstractExtension() {
    Class<? extends AbstractExtension> extensionClass = this.getClass();
    ExtensionDescription.Default defAnnot = extensionClass
        .getAnnotation(ExtensionDescription.Default.class);
    if (defAnnot != null) {
      this.namespace = new XmlNamespace(defAnnot.nsAlias(),
          defAnnot.nsUri());
      this.localName = defAnnot.localName();
    } else {
      this.namespace = null;
      this.localName = null;
    }
  }

  /**
   * Constructs an extension bound to a specific XML representation.  Note: this
   * is here for backwards compatibility and may be removed at some point in the
   * future.
   *
   * @param namespace the namespace of the value element
   * @param localName the local name of the value element
   */
  protected AbstractExtension(XmlNamespace namespace, String localName) {
    this.namespace = namespace;
    this.localName = localName;
  }

  /**
   * Gets the extension's namespace.
   */
  public final XmlNamespace getExtensionNamespace() {
    return namespace;
  }

  /**
   * Gets the extension's localname.
   */
  public final String getExtensionLocalName() {
    return localName;
  }

  /**
   * Checks the attributes to see if there are any problems.  Default
   * implementation does nothing, though generally this is discouraged unless
   * there really are no restrictions.
   *
   * @throws IllegalStateException if any problems are found with the
   *                                       attributes
   */
  protected void validate() throws IllegalStateException {
  }

  /**
   * Puts attributes into the attribute generator.  Called from
   * {@link #generate(XmlWriter,ExtensionProfile)}.  Default implementation
   * does nothing, though generally this is discouraged unless there really are
   * no attributes.
   *
   * @param generator attribute generator
   */
  protected void putAttributes(AttributeGenerator generator) {
  }

  /**
   * Consumes attributes from the attribute helper.  May also use
   * {@link AttributeHelper#consumeContent} to consume the element's text
   * content.  Called from {@link #getHandler}.  Default implementation does
   * nothing, though generally this is discouraged unless there really are no
   * attributes.
   *
   * @param helper attribute helper
   * @throws ParseException any parsing exception
   */
  protected void consumeAttributes(AttributeHelper helper)
      throws ParseException {
  }

  /**
   * Generates the XML into the XML writer.  Default implementation generates a
   * "simple" element with the attributes and content found in the attribute
   * generator.
   *
   * @param w         XML writer
   * @param p         extension profile
   * @param namespace XML namespace for this extension
   * @param localName XML local name for this extension
   * @param attrs     list of XML attributes
   * @param generator attribute generator
   * @throws IOException any I/O exception
   */
  protected void generate(XmlWriter w, ExtensionProfile p,
      XmlNamespace namespace, String localName,
      List<XmlWriter.Attribute> attrs, AttributeGenerator generator)
      throws IOException {
    w.simpleElement(namespace, localName, attrs, generator.getContent());
  }

  public void generate(XmlWriter w, ExtensionProfile p)
      throws IOException {

    // validate
    if (namespace == null) {
      String name = this.getClass().getName();
      throw new IllegalStateException(
          "No @ExtensionDescription.Default annotation found on subclass "
              + name.substring(name.lastIndexOf('.') + 1));
    }
    validate();

    // generate attributes
    AttributeGenerator generator = new AttributeGenerator();
    putAttributes(generator);
   
    List<XmlWriter.Attribute> attrs = new ArrayList<XmlWriter.Attribute>();
    generateAttributes(attrs, generator);

    // generate XML
    generate(w, p, namespace, localName, attrs, generator);
  }
 
  /**
   * Generates the attributes in the generator into the list of attributes.
   */
  protected void generateAttributes(List<XmlWriter.Attribute> attrs,
      AttributeGenerator generator) {
    for (Map.Entry<String, String> entry : generator.entrySet()) {
      String value = entry.getValue();
      if (value != null) {
        attrs.add(new XmlWriter.Attribute(entry.getKey(), value));
      }
    }
  }

  /**
   * The default implementation uses the {@link AttributesHandler} to handle
   * parsing the extension.
   *
   * @throws ParseException when an unexpected tag or badly-formatted
   *     XML is detected
   */
  public XmlParser.ElementHandler getHandler(ExtensionProfile p,
      String namespace, String localName, Attributes attrs)
      throws ParseException {
    return new AttributesHandler(attrs);
  }

  /**
   * Base class for custom element handlers that uses {@link AttributeHelper}
   * to consume the attributes and the element's text content.
   *
   *
   */
  protected class AttributesHandler extends XmlParser.ElementHandler {

    /** attribute helper or <code>null</code> to suppress its use */
    private final AttributeHelper helper;

    /**
     * Constructor.
     *
     * @param attrs XML attributes or <code>null</code> to suppress the use of
     *              {@link AttributeHelper}
     */
    public AttributesHandler(Attributes attrs) {
      helper = attrs == null ? null : new AttributeHelper(attrs);
      if (immutable) {
        throw new IllegalStateException("Cannot parse into immutable instance");
      }
    }

    @Override
    public void processEndElement() throws ParseException {
      /* don't call super.processEndElement() because it doesn't allow text()
      data */

      // consume attributes
      if (helper != null) {
        helper.setContent(value);
        consumeAttributes(helper);
        helper.assertAllConsumed();
      }

      // validate
      try {
        validate();
      } catch (IllegalStateException e) {
        throw new ParseException(e.getMessage(), e);
      }
    }
  }

  /**
  * Throws an {@link IllegalStateException} if this instance is immutable.
  * Should only be used in a value-setter method.
  */
  protected final void throwExceptionIfImmutable() {
    if (immutable) {
      throw new IllegalStateException(localName + " instance is read only");
    }
  }

  /**
   * Throws an {@link IllegalStateException} if the value is required
   * and it is missing.
   *
   * @param attrName attribute name
   * @throws IllegalStateException to indicate that there are problems with the
   *                                       attributes
   */
  protected static final void throwExceptionForMissingAttribute(
      String attrName) {
    throw new IllegalStateException("Missing attribute: " + attrName);
  }

  /**
   * @param o given object
   * @return true if the given object is not null and is the same concrete class
   *         as this one
   */
  protected boolean sameClassAs(Object o) {
    return o != null && getClass().equals(o.getClass());
  }

  /**
   * @param o1 object 1 or <code>null</code>
   * @param o2 object 2 or <code>null</code>
   * @return true if the specified arguments are equal, or both null
   */
  protected static boolean eq(Object o1, Object o2) {
    return o1 == null ? o2 == null : o1.equals(o2);
  }
}
TOP

Related Classes of com.google.gdata.data.AbstractExtension$AttributesHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.