content: /*
   * ElementLabel.java July 2006
   *
   * Copyright (C) 2006, Niall Gallagher <niallg@users.sf.net>
   *
   * 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.aliyun.odps.simpleframework.xml.core;
  
  import com.aliyun.odps.simpleframework.xml.Element;
  import com.aliyun.odps.simpleframework.xml.strategy.Type;
  import com.aliyun.odps.simpleframework.xml.stream.Format;
  import com.aliyun.odps.simpleframework.xml.stream.Style;
  import java.lang.annotation.Annotation;
  
  /**
   * The <code>ElementLabel</code> represents a label that is used to
   * represent an XML element in a class schema. This element can be
   * used to convert an XML node into either a primitive value such as
   * a string or composite object value, which is itself a schema for
   * a section of XML within the XML document. 
   * 
   * @author Niall Gallagher
   * 
   *  @see Element
   */
  class ElementLabel extends TemplateLabel {
     
     /**
      * This is the decorator that is associated with the element.
      */
     private Decorator decorator;
     
     /**
      * The contact that this element label represents.
      */
     private Introspector detail;   
     
     /**
      * This is a cache of the expression for this element.
      */
     private Expression cache;
     
     /**
      * References the annotation that was used by the field.
      */
     private Element label;
     
     /**
      * This is the format used to style this element label.
      */
     private Format format;
     
     /**
      * This is the name of the element for this label instance.
      */
     private String override;
     
     /**
      * This is the path of the XML element from the annotation.
      */
     private String path;
     
     /**
      * This is the name of the XML element from the annotation.
      */
     private String name;
     
     /**
      * This is the expected type that has been declared for this.
      */
     private Class expect;
     
     /**
      * This is the type of the class that the field references.
      */
     private Class type;
     
     /**
      * This is used to determine if the element is required.
      */
     private boolean required;
     
     /**
      * This is used to determine if the element is data.
      */
     private boolean data;
     
     /**
      * Constructor for the <code>ElementLabel</code> object. This is
      * used to create a label that can convert a XML node into a 
      * composite object or a primitive type from an XML element. 
      * 
      * @param contact this is the field that this label represents
      * @param label this is the annotation for the contact 
      * @param format this is the format used to style this element
      */
     public ElementLabel(Contact contact, Element label, Format format) {
        this.detail = new Introspector(contact, this, format);
        this.decorator = new Qualifier(contact);
        this.required = label.required();
        this.type = contact.getType();
        this.override = label.name();     
        this.expect = label.type();
        this.data = label.data();
        this.format = format;
        this.label = label; 
     }
     
     /**
      * This is used to acquire the <code>Decorator</code> for this.
      * A decorator is an object that adds various details to the
      * node without changing the overall structure of the node. For
      * example comments and namespaces can be added to the node with
      * a decorator as they do not affect the deserialization.
      * 
      * @return this returns the decorator associated with this
      */
     public Decorator getDecorator() throws Exception {
        return decorator;
     }
     
     /**
      * This is used to acquire the <code>Type</code> that the type
      * provided is represented by. Typically this will return the
      * field or method represented by the label. However, in the 
      * case of unions this will provide an override type.
      * 
      * @param type this is the class to acquire the type for
      * 
      * @return this returns the type represented by this class
      */
     public Type getType(Class type){
        Type contact = getContact();
        
        if(expect == void.class) {
           return contact;
        }
        return new OverrideType(contact, expect);
     }
     
     /**
      * Creates a converter that can be used to transform an XML node to
      * an object and vice versa. The converter created will handles
      * only XML elements and requires the context object to be provided. 
      * 
      * @param context this is the context object used for serialization
      * 
      * @return this returns a converter for serializing XML elements
      */
     public Converter getConverter(Context context) throws Exception {
        Type type = getContact();
        
        if(context.isPrimitive(type)) {
           return new Primitive(context, type);
        }      
        if(expect == void.class) {
           return new Composite(context, type);
        }
        return new Composite(context, type, expect);
     }
     
     /**
      * This is used to provide a configured empty value used when the
      * annotated value is null. This ensures that XML can be created
      * with required details regardless of whether values are null or
      * not. It also provides a means for sensible default values.
      * 
      * @param context this is the context object for the serialization
      * 
      * @return this returns the string to use for default values
      */
     public Object getEmpty(Context context) {
        return null;
     }
     
     /**
      * This is used to acquire the name of the element or attribute
      * that is used by the class schema. The name is determined by
      * checking for an override within the annotation. If it contains
      * a name then that is used, if however the annotation does not
      * specify a name the the field or method name is used instead.
      * 
      * @return returns the name that is used for the XML property
      */
     public String getName() throws Exception{
        if(name == null) {
           Style style = format.getStyle();
           String value = detail.getName();
          
           name = style.getElement(value);
        }
        return name;
     }
     
     /**
      * This is used to acquire the path of the element or attribute
      * that is used by the class schema. The path is determined by
      * acquiring the XPath expression and appending the name of the
      * label to form a fully qualified path.
      * 
      * @return returns the path that is used for the XML property
      */
     public String getPath() throws Exception {
        if(path == null) {
           Expression expression = getExpression();
           String name = getName();
           
           path = expression.getElement(name);  
        }
        return path;
     }
     
     /**
      * This method is used to return an XPath expression that is 
      * used to represent the position of this label. If there is no
      * XPath expression associated with this then an empty path is
      * returned. This will never return a null expression.
      * 
      * @return the XPath expression identifying the location
      */
     public Expression getExpression() throws Exception {
        if(cache == null) {
           cache = detail.getExpression();
        }
        return cache;
     }
     
     /**
      * This acquires the annotation associated with this label. This
      * is typically the annotation acquired from the field or method.
      * However, in the case of unions this will return the actual
      * annotation within the union group that this represents.
      * 
      * @return this returns the annotation that this represents
      */
     public Annotation getAnnotation() {
        return label;
     }
     
     /**
      * This is used to acquire the contact object for this label. The 
      * contact retrieved can be used to set any object or primitive that
      * has been deserialized, and can also be used to acquire values to
      * be serialized in the case of object persistence. All contacts 
      * that are retrieved from this method will be accessible. 
      * 
      * @return returns the contact that this label is representing
      */
     public Contact getContact() {
        return detail.getContact();
     }
     
     /**
      * This is used to acquire the name of the element or attribute
      * as taken from the annotation. If the element or attribute
      * explicitly specifies a name then that name is used for the
      * XML element or attribute used. If however no overriding name
      * is provided then the method or field is used for the name. 
      * 
      * @return returns the name of the annotation for the contact
      */
     public String getOverride() {
        return override;
     }
     
     /**
      * This acts as a convenience method used to determine the type of
      * contact this represents. This is used when an object is written
      * to XML. It determines whether a <code>class</code> attribute
      * is required within the serialized XML element, that is, if the
      * class returned by this is different from the actual value of the
      * object to be serialized then that type needs to be remembered.
      *  
      * @return this returns the type of the contact class
      */  
     public Class getType() {
        if(expect == void.class) {
           return type;
        }
        return expect;
     }
     
     /**
      * This is used to determine whether the XML element is required. 
      * This ensures that if an XML element is missing from a document
      * that deserialization can continue. Also, in the process of
      * serialization, if a value is null it does not need to be 
      * written to the resulting XML document.
      * 
      * @return true if the label represents a some required data
      */   
     public boolean isRequired() {
        return required;
     }
     
     /**
      * This is used to determine whether the annotation requires it
      * and its children to be written as a CDATA block. This is done
      * when a primitive or other such element requires a text value
      * and that value needs to be encapsulated within a CDATA block.
      * 
      * @return this returns true if the element requires CDATA
      */
     public boolean isData() {
        return data;
     }
     
     /**
      * This is used to describe the annotation and method or field
      * that this label represents. This is used to provide error
      * messages that can be used to debug issues that occur when
      * processing a method. This will provide enough information
      * such that the problem can be isolated correctly. 
      * 
      * @return this returns a string representation of the label
      */
     public String toString() {
        return detail.toString();
     }
  }
  