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
26package com.sun.tools.internal.xjc.reader.dtd.bindinfo;
27
28import java.util.ArrayList;
29import java.util.HashMap;
30import java.util.List;
31import java.util.Map;
32
33import javax.xml.namespace.QName;
34
35import com.sun.tools.internal.xjc.model.CClassInfo;
36import com.sun.xml.internal.bind.api.impl.NameConverter;
37
38import org.w3c.dom.Element;
39import org.xml.sax.Locator;
40
41
42/**
43 * {@code <element>} declaration in the binding file.
44 */
45public 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}
274