001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo;
027:
028: import java.io.FilterWriter;
029: import java.io.IOException;
030: import java.io.StringWriter;
031: import java.io.Writer;
032: import java.util.ArrayList;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: import javax.xml.bind.annotation.XmlAnyElement;
037: import javax.xml.bind.annotation.XmlElement;
038: import javax.xml.bind.annotation.XmlMixed;
039: import javax.xml.bind.annotation.XmlRootElement;
040: import javax.xml.bind.annotation.XmlType;
041: import javax.xml.transform.Transformer;
042: import javax.xml.transform.TransformerException;
043: import javax.xml.transform.dom.DOMSource;
044: import javax.xml.transform.stream.StreamResult;
045:
046: import com.sun.codemodel.internal.JDocComment;
047: import com.sun.tools.internal.xjc.model.CCustomizations;
048: import com.sun.tools.internal.xjc.model.CPluginCustomization;
049: import com.sun.tools.internal.xjc.model.Model;
050: import com.sun.tools.internal.xjc.reader.Ring;
051: import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder;
052: import com.sun.xml.internal.bind.annotation.XmlLocation;
053: import com.sun.xml.internal.bind.marshaller.MinimumEscapeHandler;
054: import com.sun.xml.internal.bind.v2.WellKnownNamespace;
055: import com.sun.xml.internal.xsom.XSComponent;
056:
057: import org.w3c.dom.Element;
058: import org.xml.sax.Locator;
059:
060: /**
061: * Container for customization declarations.
062: *
063: * We use JAXB ourselves and parse this object from "xs:annotation".
064: *
065: * @author
066: * Kohsuke Kawaguchi (kohsuke,kawaguchi@sun.com)
067: */
068: @XmlRootElement(namespace=WellKnownNamespace.XML_SCHEMA,name="annotation")
069: @XmlType(namespace=WellKnownNamespace.XML_SCHEMA,name="foobar")
070: public final class BindInfo implements Iterable<BIDeclaration> {
071:
072: private BGMBuilder builder;
073:
074: @XmlLocation
075: private Locator location;
076:
077: /**
078: * Documentation taken from <xs:documentation>s.
079: */
080: @XmlElement
081: private Documentation documentation;
082:
083: /**
084: * Returns true if this {@link BindInfo} doesn't contain any useful
085: * information.
086: *
087: * This flag is used to discard unused {@link BindInfo}s early to save memory footprint.
088: */
089: public boolean isPointless() {
090: if (size() > 0)
091: return false;
092: if (documentation != null && !documentation.contents.isEmpty())
093: return false;
094:
095: return true;
096: }
097:
098: private static final class Documentation {
099: @XmlAnyElement
100: @XmlMixed
101: List<Object> contents = new ArrayList<Object>();
102:
103: void addAll(Documentation rhs) {
104: if (rhs == null)
105: return;
106:
107: if (contents == null)
108: contents = new ArrayList<Object>();
109: if (!contents.isEmpty())
110: contents.add("\n\n");
111: contents.addAll(rhs.contents);
112: }
113: }
114:
115: /** list of individual declarations. */
116: private final List<BIDeclaration> decls = new ArrayList<BIDeclaration>();
117:
118: private static final class AppInfo {
119: /**
120: * Receives {@link BIDeclaration}s and other DOMs.
121: */
122: @XmlAnyElement(lax=true,value=DomHandlerEx.class)
123: List<Object> contents = new ArrayList<Object>();
124:
125: public void addTo(BindInfo bi) {
126: if (contents == null)
127: return;
128:
129: for (Object o : contents) {
130: if (o instanceof BIDeclaration)
131: bi.addDecl((BIDeclaration) o);
132: // this is really PITA! I can't get the source location
133: if (o instanceof DomHandlerEx.DomAndLocation) {
134: DomHandlerEx.DomAndLocation e = (DomHandlerEx.DomAndLocation) o;
135: String nsUri = e.element.getNamespaceURI();
136: if (nsUri == null
137: || nsUri.equals("")
138: || nsUri
139: .equals(WellKnownNamespace.XML_SCHEMA))
140: continue; // this is definitely not a customization
141: bi.addDecl(new BIXPluginCustomization(e.element,
142: e.loc));
143: }
144: }
145: }
146: }
147:
148: // only used by JAXB
149: @XmlElement
150: void setAppinfo(AppInfo aib) {
151: aib.addTo(this );
152: }
153:
154: /**
155: * Gets the location of this annotation in the source file.
156: *
157: * @return
158: * If the declarations are in fact specified in the source
159: * code, a non-null valid object will be returned.
160: * If this BindInfo is generated internally by XJC, then
161: * null will be returned.
162: */
163: public Locator getSourceLocation() {
164: return location;
165: }
166:
167: private XSComponent owner;
168:
169: /**
170: * Sets the owner schema component and a reference to BGMBuilder.
171: * This method is called from the BGMBuilder before
172: * any BIDeclaration inside it is used.
173: */
174: public void setOwner(BGMBuilder _builder, XSComponent _owner) {
175: this .owner = _owner;
176: this .builder = _builder;
177: for (BIDeclaration d : decls)
178: d.onSetOwner();
179: }
180:
181: public XSComponent getOwner() {
182: return owner;
183: }
184:
185: /**
186: * Back pointer to the BGMBuilder which is building
187: * a BGM from schema components including this customization.
188: */
189: public BGMBuilder getBuilder() {
190: return builder;
191: }
192:
193: /** Adds a new declaration. */
194: public void addDecl(BIDeclaration decl) {
195: if (decl == null)
196: throw new IllegalArgumentException();
197: decl.setParent(this );
198: decls.add(decl);
199: }
200:
201: /**
202: * Gets the first declaration with a given name, or null
203: * if none is found.
204: */
205: public <T extends BIDeclaration> T get(Class<T> kind) {
206: for (BIDeclaration decl : decls) {
207: if (kind.isInstance(decl))
208: return kind.cast(decl);
209: }
210: return null; // not found
211: }
212:
213: /**
214: * Gets all the declarations
215: */
216: public BIDeclaration[] getDecls() {
217: return decls.toArray(new BIDeclaration[decls.size()]);
218: }
219:
220: /**
221: * Gets the documentation parsed from <xs:documentation>s.
222: * The returned collection is to be added to {@link JDocComment#append(Object)}.
223: * @return maybe null.
224: */
225: public String getDocumentation() {
226: // TODO: FIXME: correctly turn individual items to String including DOM
227: if (documentation == null || documentation.contents == null)
228: return null;
229:
230: StringBuilder buf = new StringBuilder();
231: for (Object c : documentation.contents) {
232: if (c instanceof String) {
233: buf.append(c.toString());
234: }
235: if (c instanceof Element) {
236: Transformer t = builder.getIdentityTransformer();
237: StringWriter w = new StringWriter();
238: try {
239: Writer fw = new FilterWriter(w) {
240: char[] buf = new char[1];
241:
242: public void write(int c) throws IOException {
243: buf[0] = (char) c;
244: write(buf, 0, 1);
245: }
246:
247: public void write(char[] cbuf, int off, int len)
248: throws IOException {
249: MinimumEscapeHandler.theInstance.escape(
250: cbuf, off, len, false, out);
251: }
252:
253: public void write(String str, int off, int len)
254: throws IOException {
255: write(str.toCharArray(), off, len);
256: }
257: };
258: t.transform(new DOMSource((Element) c),
259: new StreamResult(fw));
260: } catch (TransformerException e) {
261: throw new Error(e); // impossible
262: }
263: buf.append("\n<pre>\n");
264: buf.append(w);
265: buf.append("\n</pre>\n");
266: }
267: }
268: return buf.toString();
269: }
270:
271: /**
272: * Merges all the declarations inside the given BindInfo
273: * to this BindInfo.
274: */
275: public void absorb(BindInfo bi) {
276: for (BIDeclaration d : bi)
277: d.setParent(this );
278: this .decls.addAll(bi.decls);
279:
280: if (this .documentation == null)
281: this .documentation = bi.documentation;
282: else
283: this .documentation.addAll(bi.documentation);
284: }
285:
286: /** Gets the number of declarations. */
287: public int size() {
288: return decls.size();
289: }
290:
291: public BIDeclaration get(int idx) {
292: return decls.get(idx);
293: }
294:
295: public Iterator<BIDeclaration> iterator() {
296: return decls.iterator();
297: }
298:
299: /**
300: * Gets the list of {@link CPluginCustomization}s from this.
301: *
302: * <p>
303: * Note that calling this method marks all those plug-in customizations
304: * as 'used'. So call it only when it's really necessary.
305: */
306: public CCustomizations toCustomizationList() {
307: CCustomizations r = null;
308: for (BIDeclaration d : this ) {
309: if (d instanceof BIXPluginCustomization) {
310: BIXPluginCustomization pc = (BIXPluginCustomization) d;
311: pc.markAsAcknowledged();
312: if (!Ring.get(Model.class).options.pluginURIs
313: .contains(pc.getName().getNamespaceURI()))
314: continue; // this isn't a plugin customization
315: if (r == null)
316: r = new CCustomizations();
317: r.add(new CPluginCustomization(pc.element, pc
318: .getLocation()));
319: }
320: }
321:
322: if (r == null)
323: r = CCustomizations.EMPTY;
324: return new CCustomizations(r);
325: }
326:
327: /** An instance with the empty contents. */
328: public final static BindInfo empty = new BindInfo();
329:
330: }
|