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.xmlschema.bindinfo;
037:
038: import java.io.FilterWriter;
039: import java.io.IOException;
040: import java.io.StringWriter;
041: import java.io.Writer;
042: import java.util.ArrayList;
043: import java.util.Collections;
044: import java.util.Iterator;
045: import java.util.List;
046:
047: import javax.xml.bind.JAXBContext;
048: import javax.xml.bind.JAXBException;
049: import javax.xml.bind.annotation.XmlAnyElement;
050: import javax.xml.bind.annotation.XmlElement;
051: import javax.xml.bind.annotation.XmlMixed;
052: import javax.xml.bind.annotation.XmlRootElement;
053: import javax.xml.bind.annotation.XmlType;
054: import javax.xml.transform.Transformer;
055: import javax.xml.transform.TransformerException;
056: import javax.xml.transform.dom.DOMSource;
057: import javax.xml.transform.stream.StreamResult;
058:
059: import com.sun.codemodel.JDocComment;
060: import com.sun.tools.xjc.SchemaCache;
061: import com.sun.tools.xjc.model.CCustomizations;
062: import com.sun.tools.xjc.model.CPluginCustomization;
063: import com.sun.tools.xjc.model.Model;
064: import com.sun.tools.xjc.reader.Ring;
065: import com.sun.tools.xjc.reader.xmlschema.BGMBuilder;
066: import com.sun.xml.bind.annotation.XmlLocation;
067: import com.sun.xml.bind.api.TypeReference;
068: import com.sun.xml.bind.marshaller.MinimumEscapeHandler;
069: import com.sun.xml.bind.v2.WellKnownNamespace;
070: import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
071: import com.sun.xml.xsom.XSComponent;
072:
073: import org.w3c.dom.Element;
074: import org.xml.sax.Locator;
075:
076: /**
077: * Container for customization declarations.
078: *
079: * We use JAXB ourselves and parse this object from "xs:annotation".
080: *
081: * @author
082: * Kohsuke Kawaguchi (kohsuke,kawaguchi@sun.com)
083: */
084: @XmlRootElement(namespace=WellKnownNamespace.XML_SCHEMA,name="annotation")
085: @XmlType(namespace=WellKnownNamespace.XML_SCHEMA,name="foobar")
086: public final class BindInfo implements Iterable<BIDeclaration> {
087:
088: private BGMBuilder builder;
089:
090: @XmlLocation
091: private Locator location;
092:
093: /**
094: * Documentation taken from <xs:documentation>s.
095: */
096: @XmlElement(namespace=WellKnownNamespace.XML_SCHEMA)
097: private Documentation documentation;
098:
099: /**
100: * Returns true if this {@link BindInfo} doesn't contain any useful
101: * information.
102: *
103: * This flag is used to discard unused {@link BindInfo}s early to save memory footprint.
104: */
105: public boolean isPointless() {
106: if (size() > 0)
107: return false;
108: if (documentation != null && !documentation.contents.isEmpty())
109: return false;
110:
111: return true;
112: }
113:
114: private static final class Documentation {
115: @XmlAnyElement
116: @XmlMixed
117: List<Object> contents = new ArrayList<Object>();
118:
119: void addAll(Documentation rhs) {
120: if (rhs == null)
121: return;
122:
123: if (contents == null)
124: contents = new ArrayList<Object>();
125: if (!contents.isEmpty())
126: contents.add("\n\n");
127: contents.addAll(rhs.contents);
128: }
129: }
130:
131: /** list of individual declarations. */
132: private final List<BIDeclaration> decls = new ArrayList<BIDeclaration>();
133:
134: private static final class AppInfo {
135: /**
136: * Receives {@link BIDeclaration}s and other DOMs.
137: */
138: @XmlAnyElement(lax=true,value=DomHandlerEx.class)
139: List<Object> contents = new ArrayList<Object>();
140:
141: public void addTo(BindInfo bi) {
142: if (contents == null)
143: return;
144:
145: for (Object o : contents) {
146: if (o instanceof BIDeclaration)
147: bi.addDecl((BIDeclaration) o);
148: // this is really PITA! I can't get the source location
149: if (o instanceof DomHandlerEx.DomAndLocation) {
150: DomHandlerEx.DomAndLocation e = (DomHandlerEx.DomAndLocation) o;
151: String nsUri = e.element.getNamespaceURI();
152: if (nsUri == null
153: || nsUri.equals("")
154: || nsUri
155: .equals(WellKnownNamespace.XML_SCHEMA))
156: continue; // this is definitely not a customization
157: bi.addDecl(new BIXPluginCustomization(e.element,
158: e.loc));
159: }
160: }
161: }
162: }
163:
164: // only used by JAXB
165: @XmlElement(namespace=WellKnownNamespace.XML_SCHEMA)
166: void setAppinfo(AppInfo aib) {
167: aib.addTo(this );
168: }
169:
170: /**
171: * Gets the location of this annotation in the source file.
172: *
173: * @return
174: * If the declarations are in fact specified in the source
175: * code, a non-null valid object will be returned.
176: * If this BindInfo is generated internally by XJC, then
177: * null will be returned.
178: */
179: public Locator getSourceLocation() {
180: return location;
181: }
182:
183: private XSComponent owner;
184:
185: /**
186: * Sets the owner schema component and a reference to BGMBuilder.
187: * This method is called from the BGMBuilder before
188: * any BIDeclaration inside it is used.
189: */
190: public void setOwner(BGMBuilder _builder, XSComponent _owner) {
191: this .owner = _owner;
192: this .builder = _builder;
193: for (BIDeclaration d : decls)
194: d.onSetOwner();
195: }
196:
197: public XSComponent getOwner() {
198: return owner;
199: }
200:
201: /**
202: * Back pointer to the BGMBuilder which is building
203: * a BGM from schema components including this customization.
204: */
205: public BGMBuilder getBuilder() {
206: return builder;
207: }
208:
209: /** Adds a new declaration. */
210: public void addDecl(BIDeclaration decl) {
211: if (decl == null)
212: throw new IllegalArgumentException();
213: decl.setParent(this );
214: decls.add(decl);
215: }
216:
217: /**
218: * Gets the first declaration with a given name, or null
219: * if none is found.
220: */
221: public <T extends BIDeclaration> T get(Class<T> kind) {
222: for (BIDeclaration decl : decls) {
223: if (kind.isInstance(decl))
224: return kind.cast(decl);
225: }
226: return null; // not found
227: }
228:
229: /**
230: * Gets all the declarations
231: */
232: public BIDeclaration[] getDecls() {
233: return decls.toArray(new BIDeclaration[decls.size()]);
234: }
235:
236: /**
237: * Gets the documentation parsed from <xs:documentation>s.
238: * The returned collection is to be added to {@link JDocComment#append(Object)}.
239: * @return maybe null.
240: */
241: public String getDocumentation() {
242: // TODO: FIXME: correctly turn individual items to String including DOM
243: if (documentation == null || documentation.contents == null)
244: return null;
245:
246: StringBuilder buf = new StringBuilder();
247: for (Object c : documentation.contents) {
248: if (c instanceof String) {
249: buf.append(c.toString());
250: }
251: if (c instanceof Element) {
252: Transformer t = builder.getIdentityTransformer();
253: StringWriter w = new StringWriter();
254: try {
255: Writer fw = new FilterWriter(w) {
256: char[] buf = new char[1];
257:
258: public void write(int c) throws IOException {
259: buf[0] = (char) c;
260: write(buf, 0, 1);
261: }
262:
263: public void write(char[] cbuf, int off, int len)
264: throws IOException {
265: MinimumEscapeHandler.theInstance.escape(
266: cbuf, off, len, false, out);
267: }
268:
269: public void write(String str, int off, int len)
270: throws IOException {
271: write(str.toCharArray(), off, len);
272: }
273: };
274: t.transform(new DOMSource((Element) c),
275: new StreamResult(fw));
276: } catch (TransformerException e) {
277: throw new Error(e); // impossible
278: }
279: buf.append("\n<pre>\n");
280: buf.append(w);
281: buf.append("\n</pre>\n");
282: }
283: }
284: return buf.toString();
285: }
286:
287: /**
288: * Merges all the declarations inside the given BindInfo
289: * to this BindInfo.
290: */
291: public void absorb(BindInfo bi) {
292: for (BIDeclaration d : bi)
293: d.setParent(this );
294: this .decls.addAll(bi.decls);
295:
296: if (this .documentation == null)
297: this .documentation = bi.documentation;
298: else
299: this .documentation.addAll(bi.documentation);
300: }
301:
302: /** Gets the number of declarations. */
303: public int size() {
304: return decls.size();
305: }
306:
307: public BIDeclaration get(int idx) {
308: return decls.get(idx);
309: }
310:
311: public Iterator<BIDeclaration> iterator() {
312: return decls.iterator();
313: }
314:
315: /**
316: * Gets the list of {@link CPluginCustomization}s from this.
317: *
318: * <p>
319: * Note that calling this method marks all those plug-in customizations
320: * as 'used'. So call it only when it's really necessary.
321: */
322: public CCustomizations toCustomizationList() {
323: CCustomizations r = null;
324: for (BIDeclaration d : this ) {
325: if (d instanceof BIXPluginCustomization) {
326: BIXPluginCustomization pc = (BIXPluginCustomization) d;
327: pc.markAsAcknowledged();
328: if (!Ring.get(Model.class).options.pluginURIs
329: .contains(pc.getName().getNamespaceURI()))
330: continue; // this isn't a plugin customization
331: if (r == null)
332: r = new CCustomizations();
333: r.add(new CPluginCustomization(pc.element, pc
334: .getLocation()));
335: }
336: }
337:
338: if (r == null)
339: r = CCustomizations.EMPTY;
340: return new CCustomizations(r);
341: }
342:
343: /** An instance with the empty contents. */
344: public final static BindInfo empty = new BindInfo();
345:
346: /**
347: * Lazily prepared {@link JAXBContext}.
348: */
349: private static JAXBContextImpl customizationContext;
350:
351: public static JAXBContextImpl getJAXBContext() {
352: synchronized (AnnotationParserFactoryImpl.class) {
353: try {
354: if (customizationContext == null)
355: customizationContext = new JAXBContextImpl(
356: new Class[] {
357: BindInfo.class, // for xs:annotation
358: BIClass.class,
359: BIConversion.User.class,
360: BIConversion.UserAdapter.class,
361: BIDom.class, BIFactoryMethod.class,
362: BIInlineBinaryData.class,
363: BIXDom.class,
364: BIXSubstitutable.class,
365: BIEnum.class, BIEnumMember.class,
366: BIGlobalBinding.class,
367: BIProperty.class,
368: BISchemaBinding.class },
369: Collections.<TypeReference> emptyList(),
370: Collections.<Class, Class> emptyMap(),
371: null, false, null, false, false);
372: return customizationContext;
373: } catch (JAXBException e) {
374: throw new AssertionError(e);
375: }
376: }
377: }
378:
379: /**
380: * Lazily parsed schema for the binding file.
381: */
382: public static final SchemaCache bindingFileSchema = new SchemaCache(
383: BindInfo.class.getResource("binding.xsd"));
384: }
|