ohair@286: /* ohair@286: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo; ohair@286: ohair@286: import java.io.FilterWriter; ohair@286: import java.io.IOException; ohair@286: import java.io.StringWriter; ohair@286: import java.io.Writer; ohair@286: import java.util.ArrayList; ohair@286: import java.util.Iterator; ohair@286: import java.util.List; ohair@286: ohair@286: import javax.xml.bind.JAXBContext; ohair@286: import javax.xml.bind.JAXBException; alanb@368: import javax.xml.bind.Unmarshaller; ohair@286: import javax.xml.bind.annotation.XmlAnyElement; ohair@286: import javax.xml.bind.annotation.XmlElement; ohair@286: import javax.xml.bind.annotation.XmlMixed; ohair@286: import javax.xml.bind.annotation.XmlRootElement; ohair@286: import javax.xml.bind.annotation.XmlType; ohair@286: import javax.xml.transform.Transformer; ohair@286: import javax.xml.transform.TransformerException; ohair@286: import javax.xml.transform.dom.DOMSource; ohair@286: import javax.xml.transform.stream.StreamResult; ohair@286: ohair@286: import com.sun.codemodel.internal.JDocComment; alanb@368: import com.sun.xml.internal.bind.v2.WellKnownNamespace; ohair@286: import com.sun.tools.internal.xjc.SchemaCache; ohair@286: import com.sun.tools.internal.xjc.model.CCustomizations; ohair@286: import com.sun.tools.internal.xjc.model.CPluginCustomization; ohair@286: import com.sun.tools.internal.xjc.model.Model; ohair@286: import com.sun.tools.internal.xjc.reader.Ring; ohair@286: import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder; ohair@286: import com.sun.xml.internal.bind.annotation.XmlLocation; ohair@286: import com.sun.xml.internal.bind.marshaller.MinimumEscapeHandler; ohair@286: import com.sun.xml.internal.xsom.XSComponent; ohair@286: ohair@286: import org.w3c.dom.Element; ohair@286: import org.xml.sax.Locator; ohair@286: ohair@286: /** ohair@286: * Container for customization declarations. ohair@286: * ohair@286: * We use JAXB ourselves and parse this object from "xs:annotation". ohair@286: * ohair@286: * @author ohair@286: * Kohsuke Kawaguchi (kohsuke,kawaguchi@sun.com) ohair@286: */ alanb@368: @XmlRootElement(namespace= WellKnownNamespace.XML_SCHEMA,name="annotation") ohair@286: @XmlType(namespace=WellKnownNamespace.XML_SCHEMA,name="foobar") ohair@286: public final class BindInfo implements Iterable { ohair@286: ohair@286: private BGMBuilder builder; ohair@286: ohair@286: @XmlLocation ohair@286: private Locator location; ohair@286: ohair@286: /** ohair@286: * Documentation taken from <xs:documentation>s. ohair@286: */ ohair@286: @XmlElement(namespace=WellKnownNamespace.XML_SCHEMA) ohair@286: private Documentation documentation; ohair@286: ohair@286: /** ohair@286: * Returns true if this {@link BindInfo} doesn't contain any useful ohair@286: * information. ohair@286: * ohair@286: * This flag is used to discard unused {@link BindInfo}s early to save memory footprint. ohair@286: */ ohair@286: public boolean isPointless() { ohair@286: if(size()>0) return false; ohair@286: if(documentation!=null && !documentation.contents.isEmpty()) ohair@286: return false; ohair@286: ohair@286: return true; ohair@286: } ohair@286: ohair@286: private static final class Documentation { ohair@286: @XmlAnyElement ohair@286: @XmlMixed ohair@286: List contents = new ArrayList(); ohair@286: ohair@286: void addAll(Documentation rhs) { ohair@286: if(rhs==null) return; ohair@286: ohair@286: if(contents==null) ohair@286: contents = new ArrayList(); ohair@286: if(!contents.isEmpty()) ohair@286: contents.add("\n\n"); ohair@286: contents.addAll(rhs.contents); ohair@286: } ohair@286: } ohair@286: ohair@286: /** list of individual declarations. */ ohair@286: private final List decls = new ArrayList(); ohair@286: ohair@286: private static final class AppInfo { ohair@286: /** ohair@286: * Receives {@link BIDeclaration}s and other DOMs. ohair@286: */ ohair@286: @XmlAnyElement(lax=true,value=DomHandlerEx.class) ohair@286: List contents = new ArrayList(); ohair@286: ohair@286: public void addTo(BindInfo bi) { ohair@286: if(contents==null) return; ohair@286: ohair@286: for (Object o : contents) { ohair@286: if(o instanceof BIDeclaration) ohair@286: bi.addDecl((BIDeclaration)o); ohair@286: // this is really PITA! I can't get the source location ohair@286: if(o instanceof DomHandlerEx.DomAndLocation) { ohair@286: DomHandlerEx.DomAndLocation e = (DomHandlerEx.DomAndLocation)o; ohair@286: String nsUri = e.element.getNamespaceURI(); ohair@286: if(nsUri==null || nsUri.equals("") ohair@286: || nsUri.equals(WellKnownNamespace.XML_SCHEMA)) ohair@286: continue; // this is definitely not a customization ohair@286: bi.addDecl(new BIXPluginCustomization(e.element,e.loc)); ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: ohair@286: // only used by JAXB ohair@286: @XmlElement(namespace=WellKnownNamespace.XML_SCHEMA) ohair@286: void setAppinfo(AppInfo aib) { ohair@286: aib.addTo(this); ohair@286: } ohair@286: ohair@286: ohair@286: ohair@286: /** ohair@286: * Gets the location of this annotation in the source file. ohair@286: * ohair@286: * @return ohair@286: * If the declarations are in fact specified in the source ohair@286: * code, a non-null valid object will be returned. ohair@286: * If this BindInfo is generated internally by XJC, then ohair@286: * null will be returned. ohair@286: */ ohair@286: public Locator getSourceLocation() { return location; } ohair@286: ohair@286: ohair@286: private XSComponent owner; ohair@286: /** ohair@286: * Sets the owner schema component and a reference to BGMBuilder. ohair@286: * This method is called from the BGMBuilder before ohair@286: * any BIDeclaration inside it is used. ohair@286: */ ohair@286: public void setOwner( BGMBuilder _builder, XSComponent _owner ) { ohair@286: this.owner = _owner; ohair@286: this.builder = _builder; ohair@286: for (BIDeclaration d : decls) ohair@286: d.onSetOwner(); ohair@286: } ohair@286: public XSComponent getOwner() { return owner; } ohair@286: ohair@286: /** ohair@286: * Back pointer to the BGMBuilder which is building ohair@286: * a BGM from schema components including this customization. ohair@286: */ ohair@286: public BGMBuilder getBuilder() { return builder; } ohair@286: ohair@286: /** Adds a new declaration. */ ohair@286: public void addDecl( BIDeclaration decl ) { ohair@286: if(decl==null) throw new IllegalArgumentException(); ohair@286: decl.setParent(this); ohair@286: decls.add(decl); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets the first declaration with a given name, or null ohair@286: * if none is found. ohair@286: */ ohair@286: public ohair@286: T get( Class kind ) { ohair@286: for( BIDeclaration decl : decls ) { ohair@286: if( kind.isInstance(decl) ) ohair@286: return kind.cast(decl); ohair@286: } ohair@286: return null; // not found ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets all the declarations ohair@286: */ ohair@286: public BIDeclaration[] getDecls() { ohair@286: return decls.toArray(new BIDeclaration[decls.size()]); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets the documentation parsed from <xs:documentation>s. ohair@286: * The returned collection is to be added to {@link JDocComment#append(Object)}. ohair@286: * @return maybe null. ohair@286: */ ohair@286: public String getDocumentation() { ohair@286: // TODO: FIXME: correctly turn individual items to String including DOM ohair@286: if(documentation==null || documentation.contents==null) return null; ohair@286: ohair@286: StringBuilder buf = new StringBuilder(); ohair@286: for (Object c : documentation.contents) { ohair@286: if(c instanceof String) { ohair@286: buf.append(c.toString()); ohair@286: } ohair@286: if(c instanceof Element) { ohair@286: Transformer t = builder.getIdentityTransformer(); ohair@286: StringWriter w = new StringWriter(); ohair@286: try { ohair@286: Writer fw = new FilterWriter(w) { ohair@286: char[] buf = new char[1]; ohair@286: ohair@286: public void write(int c) throws IOException { ohair@286: buf[0] = (char)c; ohair@286: write(buf,0,1); ohair@286: } ohair@286: ohair@286: public void write(char[] cbuf, int off, int len) throws IOException { ohair@286: MinimumEscapeHandler.theInstance.escape(cbuf,off,len,false,out); ohair@286: } ohair@286: ohair@286: public void write(String str, int off, int len) throws IOException { ohair@286: write(str.toCharArray(),off,len); ohair@286: } ohair@286: }; ohair@286: t.transform(new DOMSource((Element)c),new StreamResult(fw)); ohair@286: } catch (TransformerException e) { ohair@286: throw new Error(e); // impossible ohair@286: } ohair@286: buf.append("\n
\n");
ohair@286:                 buf.append(w);
ohair@286:                 buf.append("\n
\n"); ohair@286: } ohair@286: } ohair@286: return buf.toString(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Merges all the declarations inside the given BindInfo ohair@286: * to this BindInfo. ohair@286: */ ohair@286: public void absorb( BindInfo bi ) { ohair@286: for( BIDeclaration d : bi ) ohair@286: d.setParent(this); ohair@286: this.decls.addAll( bi.decls ); ohair@286: ohair@286: if(this.documentation==null) ohair@286: this.documentation = bi.documentation; ohair@286: else ohair@286: this.documentation.addAll(bi.documentation); ohair@286: } ohair@286: ohair@286: /** Gets the number of declarations. */ ohair@286: public int size() { return decls.size(); } ohair@286: ohair@286: public BIDeclaration get( int idx ) { return decls.get(idx); } ohair@286: ohair@286: public Iterator iterator() { ohair@286: return decls.iterator(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets the list of {@link CPluginCustomization}s from this. ohair@286: * ohair@286: *

ohair@286: * Note that calling this method marks all those plug-in customizations ohair@286: * as 'used'. So call it only when it's really necessary. ohair@286: */ ohair@286: public CCustomizations toCustomizationList() { ohair@286: CCustomizations r=null; ohair@286: for( BIDeclaration d : this ) { ohair@286: if(d instanceof BIXPluginCustomization) { ohair@286: BIXPluginCustomization pc = (BIXPluginCustomization) d; ohair@286: pc.markAsAcknowledged(); ohair@286: if(!Ring.get(Model.class).options.pluginURIs.contains(pc.getName().getNamespaceURI())) ohair@286: continue; // this isn't a plugin customization ohair@286: if(r==null) ohair@286: r = new CCustomizations(); ohair@286: r.add(new CPluginCustomization(pc.element,pc.getLocation())); ohair@286: } ohair@286: } ohair@286: ohair@286: if(r==null) r = CCustomizations.EMPTY; ohair@286: return new CCustomizations(r); ohair@286: } ohair@286: /** An instance with the empty contents. */ ohair@286: public final static BindInfo empty = new BindInfo(); ohair@286: ohair@286: /** ohair@286: * Lazily prepared {@link JAXBContext}. ohair@286: */ alanb@368: private static volatile JAXBContext customizationContext; ohair@286: alanb@368: public static JAXBContext getCustomizationContext() { alanb@368: try { alanb@368: if (customizationContext == null) { alanb@368: synchronized (BindInfo.class) { alanb@368: if (customizationContext == null) { alanb@368: customizationContext = JAXBContext.newInstance( alanb@368: BindInfo.class, // for xs:annotation alanb@368: BIClass.class, alanb@368: BIConversion.User.class, alanb@368: BIConversion.UserAdapter.class, alanb@368: BIDom.class, alanb@368: BIFactoryMethod.class, alanb@368: BIInlineBinaryData.class, alanb@368: BIXDom.class, alanb@368: BIXSubstitutable.class, alanb@368: BIEnum.class, alanb@368: BIEnumMember.class, alanb@368: BIGlobalBinding.class, alanb@368: BIProperty.class, alanb@368: BISchemaBinding.class); alanb@368: } alanb@368: } ohair@286: } alanb@368: return customizationContext; alanb@368: } catch (JAXBException e) { alanb@368: throw new AssertionError(e); alanb@368: } alanb@368: } alanb@368: alanb@368: public static Unmarshaller getCustomizationUnmarshaller() { alanb@368: try { alanb@368: return getCustomizationContext().createUnmarshaller(); alanb@368: } catch (JAXBException e) { alanb@368: throw new AssertionError(e); ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Lazily parsed schema for the binding file. ohair@286: */ ohair@286: public static final SchemaCache bindingFileSchema = new SchemaCache(BindInfo.class.getResource("binding.xsd")); ohair@286: }