1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.internal.xjc.reader.dtd.bindinfo;
  27 
  28 import java.util.ArrayList;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Map;
  32 
  33 import javax.xml.namespace.QName;
  34 
  35 import com.sun.tools.internal.xjc.model.CClassInfo;
  36 import com.sun.xml.internal.bind.api.impl.NameConverter;
  37 
  38 import org.w3c.dom.Element;
  39 import org.xml.sax.Locator;
  40 
  41 
  42 /**
  43  * {@code <element>} declaration in the binding file.
  44  */
  45 public final class BIElement
  46 {
  47     /**
  48      * Wraps a given {@code <element>} element in the binding file.
  49      *
  50      * <p>
  51      * Should be created only from {@link BindInfo}.
  52      */
  53     BIElement( BindInfo bi, Element _e ) {
  54         this.parent = bi;
  55         this.e = _e;
  56 
  57         {
  58             Element c = DOMUtil.getElement(e,"content");
  59             if(c!=null) {
  60                 if(DOMUtil.getAttribute(c,"property")!=null) {
  61                     // if @property is there, this is a general declaration
  62                     this.rest = BIContent.create(c,this);
  63                 } else {
  64                     // this must be a model-based declaration
  65                     for( Element p : DOMUtil.getChildElements(c) ) {
  66                         if(p.getLocalName().equals("rest"))
  67                             this.rest = BIContent.create(p,this);
  68                         else
  69                             this.contents.add(BIContent.create(p,this));
  70                     }
  71                 }
  72             }
  73         }
  74 
  75         // parse <attribute>s
  76         for( Element atr : DOMUtil.getChildElements(e,"attribute") ) {
  77             BIAttribute a = new BIAttribute( this, atr );
  78             attributes.put(a.name(),a);
  79         }
  80 
  81         if(isClass()) {
  82             // if this is a class-declaration, create JClass object now
  83             String className = DOMUtil.getAttribute(e,"class");
  84             if(className==null)
  85                 // none was specified. infer the name.
  86                 className = NameConverter.standard.toClassName(name());
  87             this.className = className;
  88         } else {
  89             // this is not an element-class declaration
  90             className = null;
  91         }
  92 
  93         // process conversion declarations
  94         for( Element conv : DOMUtil.getChildElements(e,"conversion") ) {
  95             BIConversion c = new BIUserConversion(bi,conv);
  96             conversions.put(c.name(),c);
  97         }
  98         for( Element en : DOMUtil.getChildElements(e,"enumeration") ) {
  99             BIConversion c = BIEnumeration.create(en,this);
 100             conversions.put(c.name(),c);
 101         }
 102 
 103         // parse <constructor>s
 104         for( Element c : DOMUtil.getChildElements(e,"constructor") ) {
 105             constructors.add( new BIConstructor(c) );
 106         }
 107 
 108         String name = name();
 109         QName tagName = new QName("",name);
 110 
 111         this.clazz = new CClassInfo(parent.model,parent.getTargetPackage(),className,getLocation(),null,tagName,null,null/*TODO*/);
 112     }
 113 
 114     /**
 115      * Gets the source location where this element is declared.
 116      */
 117     public Locator getLocation() {
 118         return DOMLocator.getLocationInfo(e);
 119     }
 120 
 121 
 122     /** The parent {@link BindInfo} object to which this object belongs. */
 123     final BindInfo parent;
 124 
 125     /** {@code <element>} element which this object is wrapping. */
 126     private final Element e;
 127 
 128     /**
 129      * The bean representation for this element.
 130      */
 131     public final CClassInfo clazz;
 132 
 133     /**
 134      * Content-property declarations.
 135      * <p>
 136      * This vector will be empty if no content-property declaration is made.
 137      */
 138     private final List<BIContent> contents = new ArrayList<BIContent>();
 139 
 140     /** Conversion declarations. */
 141     private final Map<String,BIConversion> conversions = new HashMap<String,BIConversion>();
 142 
 143     /**
 144      * The "rest" content-property declaration.
 145      * <p>
 146      * This field is null when there was no "rest" declaration.
 147      */
 148     private BIContent rest;
 149 
 150     /** Attribute-property declarations. */
 151     private final Map<String,BIAttribute> attributes = new HashMap<String,BIAttribute>();
 152 
 153     /** Constructor declarations. */
 154     private final List<BIConstructor> constructors = new ArrayList<BIConstructor>();
 155 
 156     /**
 157      * the class which is generated by this declaration.
 158      * This field will be null if this declaration is an element-property
 159      * declaration.
 160      */
 161     private final String className;
 162 
 163 
 164 
 165     /** Gets the element name. */
 166     public String name() { return DOMUtil.getAttribute(e,"name"); }
 167 
 168     /**
 169      * Checks if the element type is "class".
 170      * If false, that means this element will be a value.
 171      */
 172     public boolean isClass() {
 173         return "class".equals(e.getAttribute("type"));
 174     }
 175 
 176     /**
 177      * Checks if this element is designated as a root element.
 178      */
 179     public boolean isRoot() {
 180         return "true".equals(e.getAttribute("root"));
 181     }
 182 
 183     /**
 184      * Gets the JClass object that represents this declaration.
 185      *
 186      * <p>
 187      * This method returns null if this declaration
 188      * is an element-property declaration.
 189      */
 190     public String getClassName() {
 191         return className;
 192     }
 193 
 194     /**
 195      * Creates constructor declarations for this element.
 196      *
 197      * <p>
 198      * This method should only be called by DTDReader <b>after</b>
 199      * the normalization has completed.
 200      *
 201      * @param   src
 202      *      The ClassItem object that corresponds to this declaration
 203      */
 204     public void declareConstructors( CClassInfo src ) {
 205         for( BIConstructor c : constructors )
 206             c.createDeclaration(src);
 207     }
 208 
 209     /**
 210      * Gets the conversion method for this element.
 211      *
 212      * <p>
 213      * This method can be called only when this element
 214      * declaration is designated as element-value.
 215      *
 216      * @return
 217      *        If the convert attribute is not specified, this
 218      *        method returns null.
 219      */
 220     public BIConversion getConversion() {
 221           String cnv = DOMUtil.getAttribute(e,"convert");
 222           if(cnv==null)        return null;
 223 
 224           return conversion(cnv);
 225     }
 226 
 227     /**
 228      * Resolves the conversion name to the conversion declaration.
 229      *
 230      * <p>
 231      * Element-local declarations are checked first.
 232      *
 233      * @return
 234      *        A non-null valid BIConversion object.
 235      */
 236     public BIConversion conversion( String name ) {
 237         BIConversion r = conversions.get(name);
 238         if(r!=null)     return r;
 239 
 240         // check the global conversion declarations
 241         return parent.conversion(name);
 242     }
 243 
 244 
 245     /**
 246      * Iterates all content-property declarations (except 'rest').
 247      */
 248     public List<BIContent> getContents() {
 249         return contents;
 250     }
 251 
 252     /**
 253      * Gets the attribute-property declaration, if any.
 254      *
 255      * @return
 256      *      null if attribute declaration was not given by that name.
 257      */
 258     public BIAttribute attribute( String name ) {
 259         return attributes.get(name);
 260     }
 261 
 262     /**
 263      * Gets the 'rest' content-property declaration, if any.
 264      * @return
 265      *      if there is no 'rest' declaration, return null.
 266      */
 267     public BIContent getRest() { return this.rest; }
 268 
 269     /** Gets the location where this declaration is declared. */
 270     public Locator getSourceLocation() {
 271         return DOMLocator.getLocationInfo(e);
 272     }
 273 }