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.generator.bean;
027:
028: import java.util.Collections;
029: import java.util.HashMap;
030: import java.util.HashSet;
031: import java.util.Map;
032: import java.util.Set;
033:
034: import javax.xml.bind.annotation.XmlNsForm;
035: import javax.xml.bind.annotation.XmlSchema;
036: import javax.xml.namespace.QName;
037:
038: import com.sun.codemodel.internal.JDefinedClass;
039: import com.sun.codemodel.internal.JPackage;
040: import com.sun.tools.internal.xjc.generator.annotation.spec.XmlSchemaWriter;
041: import com.sun.tools.internal.xjc.model.CAttributePropertyInfo;
042: import com.sun.tools.internal.xjc.model.CClassInfo;
043: import com.sun.tools.internal.xjc.model.CElement;
044: import com.sun.tools.internal.xjc.model.CElementPropertyInfo;
045: import com.sun.tools.internal.xjc.model.CPropertyInfo;
046: import com.sun.tools.internal.xjc.model.CPropertyVisitor;
047: import com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
048: import com.sun.tools.internal.xjc.model.CTypeRef;
049: import com.sun.tools.internal.xjc.model.CValuePropertyInfo;
050: import com.sun.tools.internal.xjc.model.Model;
051: import com.sun.tools.internal.xjc.outline.PackageOutline;
052:
053: /**
054: * {@link PackageOutline} enhanced with schema2java specific
055: * information.
056: *
057: * @author
058: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
059: */
060: final class PackageOutlineImpl implements PackageOutline {
061: private final Model _model;
062: private final JPackage _package;
063: private final ObjectFactoryGenerator objectFactoryGenerator;
064:
065: /*package*/final Set<ClassOutlineImpl> classes = new HashSet<ClassOutlineImpl>();
066: private final Set<ClassOutlineImpl> classesView = Collections
067: .unmodifiableSet(classes);
068:
069: private String mostUsedNamespaceURI;
070: private XmlNsForm elementFormDefault;
071:
072: /**
073: * The namespace URI most commonly used in classes in this package.
074: * This should be used as the namespace URI for {@link XmlSchema#namespace()}.
075: *
076: * <p>
077: * Null if no default
078: *
079: * @see #calcDefaultValues().
080: */
081: public String getMostUsedNamespaceURI() {
082: return mostUsedNamespaceURI;
083: }
084:
085: /**
086: * The element form default for this package.
087: * <p>
088: * The value is computed by examining what would yield the smallest generated code.
089: */
090: public XmlNsForm getElementFormDefault() {
091: assert elementFormDefault != null;
092: return elementFormDefault;
093: }
094:
095: public JPackage _package() {
096: return _package;
097: }
098:
099: public ObjectFactoryGenerator objectFactoryGenerator() {
100: return objectFactoryGenerator;
101: }
102:
103: public Set<ClassOutlineImpl> getClasses() {
104: return classesView;
105: }
106:
107: public JDefinedClass objectFactory() {
108: return objectFactoryGenerator.getObjectFactory();
109: }
110:
111: protected PackageOutlineImpl(BeanGenerator outline, Model model,
112: JPackage _pkg) {
113: this ._model = model;
114: this ._package = _pkg;
115: switch (model.strategy) {
116: case BEAN_ONLY:
117: objectFactoryGenerator = new PublicObjectFactoryGenerator(
118: outline, model, _pkg);
119: break;
120: case INTF_AND_IMPL:
121: objectFactoryGenerator = new DualObjectFactoryGenerator(
122: outline, model, _pkg);
123: break;
124: default:
125: throw new IllegalStateException();
126: }
127: }
128:
129: /**
130: * Compute the most common namespace URI in this package
131: * (to put into {@link XmlSchema#namespace()} and what value
132: * we should put into {@link XmlSchema#elementFormDefault()}.
133: *
134: * This method is called after {@link #classes} field is filled up.
135: */
136: public void calcDefaultValues() {
137: // short-circuit if xjc was told not to generate package level annotations in
138: // package-info.java
139: if (!_model.isPackageLevelAnnotations()) {
140: mostUsedNamespaceURI = "";
141: elementFormDefault = XmlNsForm.UNQUALIFIED;
142: return;
143: }
144:
145: // used to visit properties
146: CPropertyVisitor<Void> propVisitor = new CPropertyVisitor<Void>() {
147: public Void onElement(CElementPropertyInfo p) {
148: for (CTypeRef tr : p.getTypes()) {
149: countURI(propUriCountMap, tr.getTagName());
150: }
151: return null;
152: }
153:
154: public Void onReference(CReferencePropertyInfo p) {
155: for (CElement e : p.getElements()) {
156: countURI(propUriCountMap, e.getElementName());
157: }
158: return null;
159: }
160:
161: public Void onAttribute(CAttributePropertyInfo p) {
162: return null;
163: }
164:
165: public Void onValue(CValuePropertyInfo p) {
166: return null;
167: }
168: };
169:
170: for (ClassOutlineImpl co : classes) {
171: CClassInfo ci = co.target;
172: countURI(uriCountMap, ci.getTypeName());
173: countURI(uriCountMap, ci.getElementName());
174:
175: for (CPropertyInfo p : ci.getProperties())
176: p.accept(propVisitor);
177: }
178: mostUsedNamespaceURI = getMostUsedURI(uriCountMap);
179: elementFormDefault = getFormDefault();
180:
181: // generate package-info.java
182: // we won't get this far if the user specified -npa
183: if (!mostUsedNamespaceURI.equals("")
184: || elementFormDefault == XmlNsForm.QUALIFIED) {
185: XmlSchemaWriter w = _package
186: .annotate2(XmlSchemaWriter.class);
187: if (!mostUsedNamespaceURI.equals(""))
188: w.namespace(mostUsedNamespaceURI);
189: if (elementFormDefault == XmlNsForm.QUALIFIED)
190: w.elementFormDefault(elementFormDefault);
191: }
192: }
193:
194: // Map to keep track of how often each type or element uri is used in this package
195: // mostly used to calculate mostUsedNamespaceURI
196: private HashMap<String, Integer> uriCountMap = new HashMap<String, Integer>();
197:
198: // Map to keep track of how often each property uri is used in this package
199: // used to calculate elementFormDefault
200: private HashMap<String, Integer> propUriCountMap = new HashMap<String, Integer>();
201:
202: /**
203: * pull the uri out of the specified QName and keep track of it in the
204: * specified hash map
205: *
206: * @param qname
207: */
208: private void countURI(HashMap<String, Integer> map, QName qname) {
209: if (qname == null)
210: return;
211:
212: String uri = qname.getNamespaceURI();
213:
214: if (map.containsKey(uri)) {
215: map.put(uri, map.get(uri) + 1);
216: } else {
217: map.put(uri, 1);
218: }
219: }
220:
221: /**
222: * Iterate through the hash map looking for the namespace used
223: * most frequently. Ties are arbitrarily broken by the order
224: * in which the map keys are iterated over.
225: */
226: private String getMostUsedURI(HashMap<String, Integer> map) {
227: String mostPopular = null;
228: int count = 0;
229:
230: for (Map.Entry<String, Integer> e : map.entrySet()) {
231: String uri = e.getKey();
232: int uriCount = e.getValue();
233: if (mostPopular == null) {
234: mostPopular = uri;
235: count = uriCount;
236: } else {
237: if (uriCount > count) {
238: mostPopular = uri;
239: count = uriCount;
240: }
241: }
242: }
243:
244: if (mostPopular == null)
245: return "";
246: return mostPopular;
247: }
248:
249: /**
250: * Calculate the element form defaulting.
251: *
252: * Compare the most frequently used property URI to the most frequently used
253: * element/type URI. If they match, then return QUALIFIED
254: */
255: private XmlNsForm getFormDefault() {
256: if (getMostUsedURI(propUriCountMap).equals(""))
257: return XmlNsForm.UNQUALIFIED;
258: else
259: return XmlNsForm.QUALIFIED;
260: }
261: }
|