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.xml.internal.bind.v2.runtime.property;
027:
028: import java.lang.reflect.Constructor;
029: import java.lang.reflect.InvocationTargetException;
030: import java.util.Collection;
031:
032: import com.sun.xml.internal.bind.v2.model.core.ID;
033: import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
034: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeAttributePropertyInfo;
035: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementPropertyInfo;
036: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeNonElement;
037: import com.sun.xml.internal.bind.v2.model.runtime.RuntimePropertyInfo;
038: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeInfo;
039: import com.sun.xml.internal.bind.v2.model.runtime.RuntimeValuePropertyInfo;
040: import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl;
041:
042: /**
043: * Create {@link Property} objects.
044: *
045: * @author Kohsuke Kawaguchi (kk@kohsuke.org)
046: */
047: public abstract class PropertyFactory {
048: private PropertyFactory() {
049: }
050:
051: /**
052: * Constructors of the {@link Property} implementation.
053: */
054: private static final Constructor<? extends Property>[] propImpls;
055:
056: static {
057: Class<? extends Property>[] implClasses = new Class[] {
058: SingleElementLeafProperty.class,
059: null, // single reference leaf --- but there's no such thing as "reference leaf"
060: null, // no such thing as "map leaf"
061:
062: ArrayElementLeafProperty.class,
063: null, // array reference leaf --- but there's no such thing as "reference leaf"
064: null, // no such thing as "map leaf"
065:
066: SingleElementNodeProperty.class,
067: SingleReferenceNodeProperty.class,
068: SingleMapNodeProperty.class,
069:
070: ArrayElementNodeProperty.class,
071: ArrayReferenceNodeProperty.class, null, // map is always a single property (Map doesn't implement Collection)
072: };
073:
074: propImpls = new Constructor[implClasses.length];
075: for (int i = 0; i < propImpls.length; i++) {
076: if (implClasses[i] != null)
077: // this pointless casting necessary for Mustang
078: propImpls[i] = (Constructor) implClasses[i]
079: .getConstructors()[0];
080: }
081: }
082:
083: /**
084: * Creates/obtains a properly configured {@link Property}
085: * object from the given description.
086: */
087: public static Property create(JAXBContextImpl grammar,
088: RuntimePropertyInfo info) {
089:
090: PropertyKind kind = info.kind();
091:
092: switch (kind) {
093: case ATTRIBUTE:
094: return new AttributeProperty(grammar,
095: (RuntimeAttributePropertyInfo) info);
096: case VALUE:
097: return new ValueProperty(grammar,
098: (RuntimeValuePropertyInfo) info);
099: case ELEMENT:
100: if (((RuntimeElementPropertyInfo) info).isValueList())
101: return new ListElementProperty(grammar,
102: (RuntimeElementPropertyInfo) info);
103: break;
104: case REFERENCE:
105: case MAP:
106: break;
107: default:
108: assert false;
109: }
110:
111: boolean isCollection = info.isCollection();
112: boolean isLeaf = isLeaf(info);
113:
114: Constructor<? extends Property> c = propImpls[(isLeaf ? 0 : 6)
115: + (isCollection ? 3 : 0) + kind.propertyIndex];
116: try {
117: return c.newInstance(grammar, info);
118: } catch (InstantiationException e) {
119: throw new InstantiationError(e.getMessage());
120: } catch (IllegalAccessException e) {
121: throw new IllegalAccessError(e.getMessage());
122: } catch (InvocationTargetException e) {
123: Throwable t = e.getCause();
124: if (t instanceof Error)
125: throw (Error) t;
126: if (t instanceof RuntimeException)
127: throw (RuntimeException) t;
128:
129: throw new AssertionError(t);
130: }
131: }
132:
133: /**
134: * Look for the case that can be optimized as a leaf,
135: * which is a kind of type whose XML representation is just PCDATA.
136: */
137: static boolean isLeaf(RuntimePropertyInfo info) {
138: Collection<? extends RuntimeTypeInfo> types = info.ref();
139: if (types.size() != 1)
140: return false;
141:
142: RuntimeTypeInfo rti = types.iterator().next();
143: if (!(rti instanceof RuntimeNonElement))
144: return false;
145:
146: if (info.id() == ID.IDREF)
147: // IDREF is always handled as leaf -- Transducer maps IDREF String back to an object
148: return true;
149:
150: if (((RuntimeNonElement) rti).getTransducer() == null)
151: // Transducer!=null means definitely binds to PCDATA.
152: // even if transducer==null, a referene might be IDREF,
153: // in which case it will still produce PCDATA in this reference.
154: return false;
155:
156: if (!info.getIndividualType().equals(rti.getType()))
157: return false;
158:
159: return true;
160: }
161: }
|