001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.tools.xjc.reader.dtd.bindinfo;
037:
038: import java.io.IOException;
039: import java.util.Collection;
040: import java.util.HashMap;
041: import java.util.Map;
042:
043: import javax.xml.parsers.ParserConfigurationException;
044: import javax.xml.parsers.SAXParserFactory;
045: import javax.xml.validation.ValidatorHandler;
046:
047: import com.sun.codemodel.ClassType;
048: import com.sun.codemodel.JClass;
049: import com.sun.codemodel.JClassAlreadyExistsException;
050: import com.sun.codemodel.JCodeModel;
051: import com.sun.codemodel.JDefinedClass;
052: import com.sun.codemodel.JPackage;
053: import com.sun.istack.SAXParseException2;
054: import com.sun.tools.xjc.AbortException;
055: import com.sun.tools.xjc.ErrorReceiver;
056: import com.sun.tools.xjc.SchemaCache;
057: import com.sun.tools.xjc.model.CCustomizations;
058: import com.sun.tools.xjc.model.CPluginCustomization;
059: import com.sun.tools.xjc.model.Model;
060: import com.sun.tools.xjc.reader.Const;
061: import com.sun.tools.xjc.util.CodeModelClassFactory;
062: import com.sun.tools.xjc.util.ErrorReceiverFilter;
063: import com.sun.tools.xjc.util.ForkContentHandler;
064:
065: import org.w3c.dom.Document;
066: import org.w3c.dom.Element;
067: import org.xml.sax.InputSource;
068: import org.xml.sax.SAXException;
069: import org.xml.sax.XMLReader;
070:
071: /**
072: * Root of the binding information.
073: */
074: public class BindInfo {
075: /** Controller object that can be used to report errors. */
076: protected final ErrorReceiver errorReceiver;
077:
078: /*package*/final Model model;
079:
080: /**
081: * The -p option that should control the default Java package that
082: * will contain the generated code. Null if unspecified. This takes
083: * precedence over the value specified in the binding file.
084: */
085: private final String defaultPackage;
086:
087: public BindInfo(Model model, InputSource source,
088: ErrorReceiver _errorReceiver) throws AbortException {
089: this (model, parse(model, source, _errorReceiver),
090: _errorReceiver);
091: }
092:
093: public BindInfo(Model model, Document _dom,
094: ErrorReceiver _errorReceiver) {
095: this .model = model;
096: this .dom = _dom.getDocumentElement();
097: this .codeModel = model.codeModel;
098: this .errorReceiver = _errorReceiver;
099: this .classFactory = new CodeModelClassFactory(_errorReceiver);
100: // TODO: decide name converter from the binding file
101:
102: this .defaultPackage = model.options.defaultPackage;
103:
104: // copy global customizations to the model
105: model.getCustomizations().addAll(getGlobalCustomizations());
106:
107: // process element declarations
108: for (Element ele : DOMUtil.getChildElements(dom, "element")) {
109: BIElement e = new BIElement(this , ele);
110: elements.put(e.name(), e);
111: }
112:
113: // add built-in conversions
114: BIUserConversion.addBuiltinConversions(this , conversions);
115:
116: // process conversion declarations
117: for (Element cnv : DOMUtil.getChildElements(dom, "conversion")) {
118: BIConversion c = new BIUserConversion(this , cnv);
119: conversions.put(c.name(), c);
120: }
121: for (Element en : DOMUtil.getChildElements(dom, "enumeration")) {
122: BIConversion c = BIEnumeration.create(en, this );
123: conversions.put(c.name(), c);
124: }
125: // TODO: check the uniquness of conversion name
126:
127: // process interface definitions
128: for (Element itf : DOMUtil.getChildElements(dom, "interface")) {
129: BIInterface c = new BIInterface(itf);
130: interfaces.put(c.name(), c);
131: }
132: }
133:
134: /** CodeModel object that is used by this binding file. */
135: final JCodeModel codeModel;
136:
137: /** Wrap the codeModel object and automate error reporting. */
138: final CodeModelClassFactory classFactory;
139:
140: /** DOM tree that represents binding info. */
141: private final Element dom;
142:
143: /** Conversion declarations. */
144: private final Map<String, BIConversion> conversions = new HashMap<String, BIConversion>();
145:
146: /** Element declarations keyed by names. */
147: private final Map<String, BIElement> elements = new HashMap<String, BIElement>();
148:
149: /** interface declarations keyed by names. */
150: private final Map<String, BIInterface> interfaces = new HashMap<String, BIInterface>();
151:
152: /** XJC extension namespace. */
153: private static final String XJC_NS = Const.XJC_EXTENSION_URI;
154:
155: //
156: //
157: // Exposed public methods
158: //
159: //
160: /** Gets the serialVersionUID if it's turned on. */
161: public Long getSerialVersionUID() {
162: Element serial = DOMUtil
163: .getElement(dom, XJC_NS, "serializable");
164: if (serial == null)
165: return null;
166:
167: String v = DOMUtil.getAttribute(serial, "uid");
168: if (v == null)
169: v = "1";
170: return new Long(v);
171: }
172:
173: /** Gets the xjc:superClass customization if it's turned on. */
174: public JClass getSuperClass() {
175: Element sc = DOMUtil.getElement(dom, XJC_NS, "superClass");
176: if (sc == null)
177: return null;
178:
179: JDefinedClass c;
180:
181: try {
182: String v = DOMUtil.getAttribute(sc, "name");
183: if (v == null)
184: return null;
185: c = codeModel._class(v);
186: c.hide();
187: } catch (JClassAlreadyExistsException e) {
188: c = e.getExistingClass();
189: }
190:
191: return c;
192: }
193:
194: /** Gets the xjc:superInterface customization if it's turned on. */
195: public JClass getSuperInterface() {
196: Element sc = DOMUtil.getElement(dom, XJC_NS, "superInterface");
197: if (sc == null)
198: return null;
199:
200: String name = DOMUtil.getAttribute(sc, "name");
201: if (name == null)
202: return null;
203:
204: JDefinedClass c;
205:
206: try {
207: c = codeModel._class(name, ClassType.INTERFACE);
208: c.hide();
209: } catch (JClassAlreadyExistsException e) {
210: c = e.getExistingClass();
211: }
212:
213: return c;
214: }
215:
216: /**
217: * Gets the specified package name (options/@package).
218: */
219: public JPackage getTargetPackage() {
220: if (model.options.defaultPackage != null)
221: // "-p" takes precedence over everything else
222: return codeModel._package(model.options.defaultPackage);
223:
224: String p;
225: if (defaultPackage != null)
226: p = defaultPackage;
227: else
228: p = getOption("package", "");
229: return codeModel._package(p);
230: }
231:
232: /**
233: * Gets the conversion declaration from the binding info.
234: *
235: * @return
236: * A non-null valid BIConversion object.
237: */
238: public BIConversion conversion(String name) {
239: BIConversion r = conversions.get(name);
240: if (r == null)
241: throw new AssertionError(
242: "undefined conversion name: this should be checked by the validator before we read it");
243: return r;
244: }
245:
246: /**
247: * Gets the element declaration from the binding info.
248: *
249: * @return
250: * If there is no declaration with a given name,
251: * this method returns null.
252: */
253: public BIElement element(String name) {
254: return elements.get(name);
255: }
256:
257: /** Iterates all {@link BIElement}s in a read-only set. */
258: public Collection<BIElement> elements() {
259: return elements.values();
260: }
261:
262: /** Returns all {@link BIInterface}s in a read-only set. */
263: public Collection<BIInterface> interfaces() {
264: return interfaces.values();
265: }
266:
267: /**
268: * Gets the list of top-level {@link CPluginCustomization}s.
269: */
270: private CCustomizations getGlobalCustomizations() {
271: CCustomizations r = null;
272: for (Element e : DOMUtil.getChildElements(dom)) {
273: if (!model.options.pluginURIs.contains(e.getNamespaceURI()))
274: continue; // this isn't a plugin customization
275: if (r == null)
276: r = new CCustomizations();
277: r.add(new CPluginCustomization(e, DOMLocator
278: .getLocationInfo(e)));
279: }
280:
281: if (r == null)
282: r = CCustomizations.EMPTY;
283: return new CCustomizations(r);
284: }
285:
286: //
287: //
288: // Internal utility methods
289: //
290: //
291:
292: /** Gets the value from the option element. */
293: private String getOption(String attName, String defaultValue) {
294: Element opt = DOMUtil.getElement(dom, "options");
295: if (opt != null) {
296: String s = DOMUtil.getAttribute(opt, attName);
297: if (s != null)
298: return s;
299: }
300: return defaultValue;
301: }
302:
303: /**
304: * Lazily parsed schema for the binding file.
305: */
306: private static SchemaCache bindingFileSchema = new SchemaCache(
307: BindInfo.class.getResource("bindingfile.xsd"));
308:
309: /**
310: * Parses an InputSource into dom4j Document.
311: * Returns null in case of an exception.
312: */
313: private static Document parse(Model model, InputSource is,
314: ErrorReceiver receiver) throws AbortException {
315: try {
316: ValidatorHandler validator = bindingFileSchema
317: .newValidator();
318:
319: // set up the pipe line as :
320: // /-> extensionChecker -> validator
321: // parser-> -<
322: // \-> DOM builder
323: SAXParserFactory pf = SAXParserFactory.newInstance();
324: pf.setNamespaceAware(true);
325: DOMBuilder builder = new DOMBuilder();
326:
327: ErrorReceiverFilter controller = new ErrorReceiverFilter(
328: receiver);
329: validator.setErrorHandler(controller);
330: XMLReader reader = pf.newSAXParser().getXMLReader();
331: reader.setErrorHandler(controller);
332:
333: DTDExtensionBindingChecker checker = new DTDExtensionBindingChecker(
334: "", model.options, controller);
335: checker.setContentHandler(validator);
336:
337: reader.setContentHandler(new ForkContentHandler(checker,
338: builder));
339:
340: reader.parse(is);
341:
342: if (controller.hadError())
343: throw new AbortException();
344: return (Document) builder.getDOM();
345: } catch (IOException e) {
346: receiver.error(new SAXParseException2(e.getMessage(), null,
347: e));
348: } catch (SAXException e) {
349: receiver.error(new SAXParseException2(e.getMessage(), null,
350: e));
351: } catch (ParserConfigurationException e) {
352: receiver.error(new SAXParseException2(e.getMessage(), null,
353: e));
354: }
355:
356: throw new AbortException();
357: }
358: }
|