0001: /*
0002: Copyright (c) 2003-2005, Dennis M. Sosnoski
0003: All rights reserved.
0004:
0005: Redistribution and use in source and binary forms, with or without modification,
0006: are permitted provided that the following conditions are met:
0007:
0008: * Redistributions of source code must retain the above copyright notice, this
0009: list of conditions and the following disclaimer.
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: this list of conditions and the following disclaimer in the documentation
0012: and/or other materials provided with the distribution.
0013: * Neither the name of JiBX nor the names of its contributors may be used
0014: to endorse or promote products derived from this software without specific
0015: prior written permission.
0016:
0017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027: */
0028:
0029: package org.jibx.binding.def;
0030:
0031: import java.io.File;
0032: import java.util.ArrayList;
0033:
0034: import org.apache.bcel.Constants;
0035: import org.apache.bcel.generic.ArrayType;
0036: import org.apache.bcel.generic.Type;
0037: import org.jibx.binding.classes.BoundClass;
0038: import org.jibx.binding.classes.BranchWrapper;
0039: import org.jibx.binding.classes.ClassCache;
0040: import org.jibx.binding.classes.ClassFile;
0041: import org.jibx.binding.classes.ClassItem;
0042: import org.jibx.binding.classes.ExceptionMethodBuilder;
0043: import org.jibx.binding.classes.MethodBuilder;
0044: import org.jibx.binding.classes.MungedClass;
0045: import org.jibx.binding.util.ArrayMap;
0046: import org.jibx.runtime.IBindingFactory;
0047: import org.jibx.runtime.JiBXException;
0048: import org.jibx.runtime.QName;
0049:
0050: /**
0051: * Binding definition. This is the root of the object graph for a binding.
0052: *
0053: * @author Dennis M. Sosnoski
0054: * @version 1.0
0055: */
0056:
0057: public class BindingDefinition extends BindingBuilder.ContainerBase
0058: implements IContainer {
0059: //
0060: // Miscellaneous static data.
0061:
0062: /** Current distribution file name. This is filled in by the Ant build
0063: process to match the current distribution. */
0064: public static final String CURRENT_VERSION_NAME = "jibx_1_1_5";
0065:
0066: /** Prefix used in all code generation for methods and classes. */
0067: public static final String GENERATE_PREFIX = "JiBX_";
0068:
0069: /** Default prefix for automatic ID generation. */
0070: /*package*/static final String DEFAULT_AUTOPREFIX = "id_";
0071:
0072: /** Minimum size to use map for index from type name. */
0073: private static final int TYPEMAP_MINIMUM_SIZE = 5;
0074:
0075: /** Table of defined bindings. */
0076: private static ArrayList s_bindings;
0077:
0078: /** Classes included in any binding. */
0079: private static ArrayMap s_mappedClasses;
0080:
0081: //
0082: // Static instances of predefined conversions.
0083: private static StringConversion s_byteConversion = new PrimitiveStringConversion(
0084: Byte.TYPE, new Byte((byte) 0), "B", "serializeByte",
0085: "parseByte", "attributeByte", "parseElementByte");
0086: private static StringConversion s_charConversion = new PrimitiveStringConversion(
0087: Character.TYPE, new Character((char) 0), "C",
0088: "serializeChar", "parseChar", "attributeChar",
0089: "parseElementChar");
0090: private static StringConversion s_doubleConversion = new PrimitiveStringConversion(
0091: Double.TYPE, new Double(0.0d), "D", "serializeDouble",
0092: "parseDouble", "attributeDouble", "parseElementDouble");
0093: private static StringConversion s_floatConversion = new PrimitiveStringConversion(
0094: Float.TYPE, new Float(0.0f), "F", "serializeFloat",
0095: "parseFloat", "attributeFloat", "parseElementFloat");
0096: private static StringConversion s_intConversion = new PrimitiveStringConversion(
0097: Integer.TYPE, new Integer(0), "I", "serializeInt",
0098: "parseInt", "attributeInt", "parseElementInt");
0099: private static StringConversion s_longConversion = new PrimitiveStringConversion(
0100: Long.TYPE, new Long(0L), "J", "serializeLong", "parseLong",
0101: "attributeLong", "parseElementLong");
0102: private static StringConversion s_shortConversion = new PrimitiveStringConversion(
0103: Short.TYPE, new Short((short) 0), "S", "serializeShort",
0104: "parseShort", "attributeShort", "parseElementShort");
0105: private static StringConversion s_booleanConversion = new PrimitiveStringConversion(
0106: Boolean.TYPE, Boolean.FALSE, "Z", "serializeBoolean",
0107: "parseBoolean", "attributeBoolean", "parseElementBoolean");
0108: private static StringConversion s_dateConversion = new ObjectStringConversion(
0109: null, "org.jibx.runtime.Utility.serializeDateTime",
0110: "org.jibx.runtime.Utility.deserializeDateTime",
0111: "java.util.Date");
0112: //#!j2me{
0113: private static StringConversion s_sqlDateConversion = new ObjectStringConversion(
0114: null, "org.jibx.runtime.Utility.serializeSqlDate",
0115: "org.jibx.runtime.Utility.deserializeSqlDate",
0116: "java.sql.Date");
0117: private static StringConversion s_sqlTimeConversion = new ObjectStringConversion(
0118: null, "org.jibx.runtime.Utility.serializeSqlTime",
0119: "org.jibx.runtime.Utility.deserializeSqlTime",
0120: "java.sql.Time");
0121: private static StringConversion s_timestampConversion = new ObjectStringConversion(
0122: null, "org.jibx.runtime.Utility.serializeTimestamp",
0123: "org.jibx.runtime.Utility.deserializeTimestamp",
0124: "java.sql.Timestamp");
0125: //#j2me}
0126: public static StringConversion s_base64Conversion = new ObjectStringConversion(
0127: null, "org.jibx.runtime.Utility.serializeBase64",
0128: "org.jibx.runtime.Utility.deserializeBase64", "byte[]");
0129:
0130: public static StringConversion s_stringConversion = new ObjectStringConversion(
0131: null, null, null, "java.lang.String");
0132: public static StringConversion s_objectConversion = new ObjectStringConversion(
0133: null, null, null, "java.lang.Object");
0134:
0135: //
0136: // Constants for code generation
0137:
0138: private static final String FACTORY_SUFFIX = "Factory";
0139: private static final String FACTORY_INTERFACE = "org.jibx.runtime.IBindingFactory";
0140: private static final String[] FACTORY_INTERFACES = { FACTORY_INTERFACE };
0141: private static final String FACTORY_INSTNAME = "m_inst";
0142: private static final int FACTORY_INSTACCESS = Constants.ACC_PRIVATE
0143: | Constants.ACC_STATIC;
0144: private static final String MARSHALLER_ARRAYNAME = "m_marshallers";
0145: private static final String UNMARSHALLER_ARRAYNAME = "m_unmarshallers";
0146: private static final String STRING_ARRAYTYPE = "java.lang.String[]";
0147: private static final String CLASSES_ARRAYNAME = "m_classes";
0148: private static final String URIS_ARRAYNAME = "m_uris";
0149: private static final String PREFIXES_ARRAYNAME = "m_prefixes";
0150: private static final String GNAMES_ARRAYNAME = "m_globalNames";
0151: private static final String GURIS_ARRAYNAME = "m_globalUris";
0152: private static final String IDNAMES_ARRAYNAME = "m_idNames";
0153: private static final String TYPEMAP_NAME = "m_typeMap";
0154: private static final String CREATEMARSHAL_METHODNAME = "createMarshallingContext";
0155: private static final String MARSHALCONTEXT_INTERFACE = "org.jibx.runtime.IMarshallingContext";
0156: private static final String MARSHALCONTEXT_IMPLEMENTATION = "org.jibx.runtime.impl.MarshallingContext";
0157: private static final String MARSHALCONTEXTINIT_SIGNATURE = "([Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;"
0158: + "Lorg/jibx/runtime/IBindingFactory;)V";
0159: private static final String CREATEUNMARSHAL_METHODNAME = "createUnmarshallingContext";
0160: private static final String UNMARSHALCONTEXT_INTERFACE = "org.jibx.runtime.IUnmarshallingContext";
0161: private static final String UNMARSHALCONTEXT_IMPLEMENTATION = "org.jibx.runtime.impl.UnmarshallingContext";
0162: private static final String UNMARSHALCONTEXTINIT_SIGNATURE = "(I[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;"
0163: + "[Ljava/lang/String;Lorg/jibx/runtime/IBindingFactory;)V";
0164: private static final String GETINST_METHODNAME = "getInstance";
0165: private static final String UNSUPPORTED_EXCEPTION_CLASS = "java.lang.UnsupportedOperationException";
0166: private static final String GETVERSION_METHODNAME = "getCompilerVersion";
0167: private static final String GETDISTRIB_METHODNAME = "getCompilerDistribution";
0168: private static final String GETDEFINEDNSS_METHODNAME = "getNamespaces";
0169: private static final String GETDEFINEDPREFS_METHODNAME = "getPrefixes";
0170: private static final String GETCLASSES_METHODNAME = "getMappedClasses";
0171: private static final String GETELEMENTNSS_METHODNAME = "getElementNamespaces";
0172: private static final String GETELEMENTNAMES_METHODNAME = "getElementNames";
0173: private static final String GETTYPEINDEX_METHODNAME = "getTypeIndex";
0174: private static final String STRINGINT_MAPTYPE = "org.jibx.runtime.impl.StringIntHashMap";
0175: private static final String STRINGINTINIT_SIGNATURE = "(I)V";
0176: private static final String STRINGINTADD_METHOD = "org.jibx.runtime.impl.StringIntHashMap.add";
0177: private static final String STRINGINTADD_SIGNATURE = "(Ljava/lang/String;I)I";
0178: private static final String STRINGINTGET_METHOD = "org.jibx.runtime.impl.StringIntHashMap.get";
0179: private static final String STRINGINTGET_SIGNATURE = "(Ljava/lang/String;)I";
0180:
0181: //
0182: // Actual instance data
0183:
0184: /** Binding name. */
0185: private final String m_name;
0186:
0187: /** Index number of this binding. */
0188: private final int m_index;
0189:
0190: /** Input binding flag. */
0191: private final boolean m_isInput;
0192:
0193: /** Output binding flag. */
0194: private final boolean m_isOutput;
0195:
0196: /** Use global ID values flag. */
0197: private final boolean m_isIdGlobal;
0198:
0199: /** Support forward references to IDs flag. */
0200: private final boolean m_isForwards;
0201:
0202: /** Generate souce tracking interface flag. */
0203: private final boolean m_isTrackSource;
0204:
0205: /** Generate marshaller/unmarshaller classes for top-level non-base abstract
0206: mappings flag. */
0207: private final boolean m_isForceClasses;
0208:
0209: /** Add default constructors where needed flag. */
0210: private boolean m_isAddConstructors;
0211:
0212: /** Package for generated context factory. */
0213: private String m_targetPackage;
0214:
0215: /** File root for generated context factory. */
0216: private File m_targetRoot;
0217:
0218: /** Classes using unique (per class) identifiers. This is <code>null</code>
0219: and unused when using global ID values. */
0220: private ArrayMap m_uniqueIds;
0221:
0222: /** Namespaces URIs included in binding. */
0223: private ArrayMap m_namespaceUris;
0224:
0225: /** Original prefixes for namespaces. */
0226: private ArrayList m_namespacePrefixes;
0227:
0228: /** Outer definition context with default definitions. */
0229: private DefinitionContext m_outerContext;
0230:
0231: /** Inner definition context constructed for binding. */
0232: private DefinitionContext m_activeContext;
0233:
0234: /** Flag for done assigning indexes to mapped classes. */
0235: private boolean m_isMappedDone;
0236:
0237: /** Flag for schema instance namespace used in binding. */
0238: private boolean m_isSchemaInstanceUsed;
0239:
0240: /** Next index number for marshaller/unmarshaller slots used in-line. */
0241: private int m_mumIndex;
0242:
0243: /** Classes handled by in-line marshaller/unmarshaller references. */
0244: private ArrayList m_extraClasses;
0245:
0246: /** Marshaller classes used in-line. */
0247: private ArrayList m_extraMarshallers;
0248:
0249: /** Unmarshaller classes used in-line. */
0250: private ArrayList m_extraUnmarshallers;
0251:
0252: /**
0253: * Constructor. Sets all defaults, including the default name provided, and
0254: * initializes the definition context for the outermost level of the
0255: * binding.
0256: *
0257: * @param name binding name
0258: * @param ibind input binding flag
0259: * @param obind output binding flag
0260: * @param tpack target package
0261: * @param glob global IDs flag
0262: * @param forward support forward referenced IDs flag
0263: * @param source add source tracking for unmarshalled objects flag
0264: * @param force create marshaller/unmarshaller classes for top-level
0265: * non-base mappings
0266: * @throws JiBXException if error in transformation
0267: */
0268:
0269: public BindingDefinition(String name, boolean ibind, boolean obind,
0270: String tpack, boolean glob, boolean forward,
0271: boolean source, boolean force) throws JiBXException {
0272:
0273: // handle basic initialization
0274: super (null);
0275: m_name = name;
0276: m_isInput = ibind;
0277: m_isOutput = obind;
0278: m_targetPackage = tpack;
0279: m_isIdGlobal = glob;
0280: m_isForwards = forward;
0281: m_isTrackSource = source;
0282: m_isForceClasses = force;
0283:
0284: // set base class defaults
0285: m_styleDefault = ValueChild.ELEMENT_STYLE;
0286: m_autoLink = BindingBuilder.LINK_FIELDS;
0287: m_accessLevel = BindingBuilder.ACC_PRIVATE;
0288: m_nameStyle = BindingBuilder.NAME_HYPHENS;
0289:
0290: // initialize the contexts
0291: m_outerContext = m_activeContext = new DefinitionContext(this );
0292: m_activeContext = new DefinitionContext(this );
0293: m_namespaceUris = new ArrayMap();
0294: m_namespaceUris.findOrAdd("");
0295: m_namespacePrefixes = new ArrayList();
0296: m_namespacePrefixes.add("");
0297: m_outerContext.addNamespace(NamespaceDefinition.buildNamespace(
0298: "http://www.w3.org/XML/1998/namespace", "xml"));
0299: getNamespaceUriIndex(
0300: "http://www.w3.org/2001/XMLSchema-instance", "xsi");
0301:
0302: // build the default converters in outer context
0303: m_outerContext.setDefaultConversion(new QName("byte.default"),
0304: s_byteConversion);
0305: m_outerContext.setDefaultConversion(new QName("char.default"),
0306: s_charConversion);
0307: StringConversion schar = s_charConversion.derive("char",
0308: "org.jibx.runtime.Utility.serializeCharString",
0309: "org.jibx.runtime.Utility.parseCharString", null);
0310: m_outerContext.setNamedConversion(new QName("char.string"),
0311: schar);
0312: m_outerContext.setDefaultConversion(
0313: new QName("double.default"), s_doubleConversion);
0314: m_outerContext.setDefaultConversion(new QName("float.default"),
0315: s_floatConversion);
0316: m_outerContext.setDefaultConversion(new QName("int.default"),
0317: s_intConversion);
0318: m_outerContext.setDefaultConversion(new QName("long.default"),
0319: s_longConversion);
0320: m_outerContext.setDefaultConversion(new QName("short.default"),
0321: s_shortConversion);
0322: m_outerContext.setDefaultConversion(
0323: new QName("boolean.default"), s_booleanConversion);
0324: m_outerContext.setDefaultConversion(new QName("Date.default"),
0325: s_dateConversion);
0326: //#!j2me{
0327: m_outerContext.setDefaultConversion(
0328: new QName("SqlDate.default"), s_sqlDateConversion);
0329: m_outerContext.setDefaultConversion(
0330: new QName("SqlTime.default"), s_sqlTimeConversion);
0331: m_outerContext.setDefaultConversion(new QName(
0332: "Timestamp.default"), s_timestampConversion);
0333: //#j2me}
0334: m_outerContext.setDefaultConversion(new QName(
0335: "byte-array.default"), s_base64Conversion);
0336: m_outerContext.setDefaultConversion(
0337: new QName("String.default"), s_stringConversion);
0338: m_outerContext.setDefaultConversion(
0339: new QName("Object.default"), s_objectConversion);
0340:
0341: // add this binding to list
0342: m_index = s_bindings.size();
0343: s_bindings.add(this );
0344: }
0345:
0346: /**
0347: * Get class linked to binding element. Implementation of
0348: * {@link org.jibx.binding.def.IContainer} interface, just returns
0349: * <code>null</code> in this case.
0350: *
0351: * @return information for class linked by binding
0352: */
0353:
0354: public BoundClass getBoundClass() {
0355: return null;
0356: }
0357:
0358: /**
0359: * Get default style for value expression. Implementation of
0360: * {@link org.jibx.binding.def.IContainer} interface.
0361: *
0362: * @return default style type for values
0363: */
0364:
0365: public int getStyleDefault() {
0366: return m_styleDefault;
0367: }
0368:
0369: /**
0370: * Set ID property. This parent binding component interface method should
0371: * never be called for the binding definition, and will throw a runtime
0372: * exception if it is called.
0373: *
0374: * @param child child defining the ID property
0375: * @return <code>false</code>
0376: */
0377:
0378: public boolean setIdChild(IComponent child) {
0379: throw new IllegalStateException(
0380: "Internal error - setIdChild for root");
0381: }
0382:
0383: /**
0384: * Get default package used for code generation.
0385: *
0386: * @return default code generation package
0387: */
0388:
0389: public String getDefaultPackage() {
0390: return m_targetPackage;
0391: }
0392:
0393: /**
0394: * Get root directory for default code generation package.
0395: *
0396: * @return root for default code generation
0397: */
0398:
0399: public File getDefaultRoot() {
0400: return m_targetRoot;
0401: }
0402:
0403: /**
0404: * Set location for binding factory class generation.
0405: *
0406: * @param tpack target package for generated context factory
0407: * @param root target root for generated context factory
0408: */
0409:
0410: public void setFactoryLocation(String tpack, File root) {
0411: m_targetPackage = tpack;
0412: m_targetRoot = root;
0413: }
0414:
0415: /**
0416: * Get index number of binding.
0417: *
0418: * @return index number for this binding definition
0419: */
0420:
0421: public int getIndex() {
0422: return m_index;
0423: }
0424:
0425: /**
0426: * Check if binding is defined for unmarshalling.
0427: *
0428: * @return <code>true</code> if defined, <code>false</code> if not
0429: */
0430:
0431: public boolean isInput() {
0432: return m_isInput;
0433: }
0434:
0435: /**
0436: * Check if binding is defined for marshalling.
0437: *
0438: * @return <code>true</code> if defined, <code>false</code> if not
0439: */
0440:
0441: public boolean isOutput() {
0442: return m_isOutput;
0443: }
0444:
0445: /**
0446: * Check if global ids are used by binding.
0447: *
0448: * @return <code>true</code> if defined, <code>false</code> if not
0449: */
0450:
0451: public boolean isIdGlobal() {
0452: return m_isIdGlobal;
0453: }
0454:
0455: /**
0456: * Check if forward ids are supported by unmarshalling binding.
0457: *
0458: * @return <code>true</code> if supported, <code>false</code> if not
0459: */
0460:
0461: public boolean isForwards() {
0462: return m_isForwards;
0463: }
0464:
0465: /**
0466: * Check if source tracking is supported by unmarshalling binding.
0467: *
0468: * @return <code>true</code> if defined, <code>false</code> if not
0469: */
0470:
0471: public boolean isTrackSource() {
0472: return m_isTrackSource;
0473: }
0474:
0475: /**
0476: * Check if default constructor generation is enabled.
0477: *
0478: * @return <code>true</code> if default constructor generation enabled,
0479: * <code>false</code> if not
0480: */
0481: public boolean isAddConstructors() {
0482: return m_isAddConstructors;
0483: }
0484:
0485: /**
0486: * Get prefix for method or class generation.
0487: *
0488: * @return prefix for names created by this binding
0489: */
0490:
0491: public String getPrefix() {
0492: return GENERATE_PREFIX + m_name;
0493: }
0494:
0495: /**
0496: * Get index for mapped class from binding. If the class is not already
0497: * included in any binding it is first added to the list of bound classes.
0498: * All bindings use the same index numbers to allow easy lookup of the
0499: * appropriate marshaller and unmarshaller within a particular binding, but
0500: * this does mean that all bindings dealing with a common set of classes
0501: * need to be compiled together. This uses the same sequence of values as
0502: * the {@link #getMarshallerUnmarshallerIndex} method but differs in that
0503: * the values returned by this method are unique per class. This method is
0504: * intended for use with <mapping> definitions. It is an error to call
0505: * this method after calling the {@link #getMarshallerUnmarshallerIndex}
0506: * method.
0507: *
0508: * @param name fully qualified name of mapped class
0509: * @return index number of class
0510: */
0511:
0512: public int getMappedClassIndex(String name) {
0513: if (m_isMappedDone) {
0514: throw new IllegalStateException(
0515: "Internal error: Call out of sequence");
0516: } else {
0517: return s_mappedClasses.findOrAdd(name);
0518: }
0519: }
0520:
0521: /**
0522: * Get marshaller/unmarshaller slot index in binding. This uses the same
0523: * sequence of values as the {@link #getMappedClassIndex} method but differs
0524: * in that the same class may have more than one marshaller/unmarshaller
0525: * slot defined. It's intended for user-defined marshallers/unmarshallers
0526: * where use is specific to a particular context. After the slot has been
0527: * assigned by this method, the {@link #setMarshallerUnmarshallerClasses}
0528: * method must be used to set the actual class names.
0529: *
0530: * @param clas fully qualified name of class handled by
0531: * marshaller/unmarshaller
0532: * @return slot number for marshaller/unmarshaller
0533: */
0534:
0535: public int getMarshallerUnmarshallerIndex(String clas) {
0536: if (!m_isMappedDone) {
0537: m_isMappedDone = true;
0538: m_mumIndex = s_mappedClasses.size();
0539: m_extraClasses = new ArrayList();
0540: m_extraMarshallers = new ArrayList();
0541: m_extraUnmarshallers = new ArrayList();
0542: }
0543: m_extraClasses.add(clas);
0544: m_extraMarshallers.add(null);
0545: m_extraUnmarshallers.add(null);
0546: return m_mumIndex++;
0547: }
0548:
0549: /**
0550: * Set marshaller and unmarshaller class names for slot.
0551: *
0552: * @param slot assigned marshaller/unmarshaller slot number
0553: * @param mclas fully qualified name of marshaller class
0554: * @param uclas fully qualified name of unmarshaller class
0555: */
0556:
0557: public void setMarshallerUnmarshallerClasses(int slot,
0558: String mclas, String uclas) {
0559: int index = slot - s_mappedClasses.size();
0560: m_extraMarshallers.set(index, mclas);
0561: m_extraUnmarshallers.set(index, uclas);
0562: }
0563:
0564: /**
0565: * Get index for ID'ed class from binding. If the class is not already
0566: * included it is first added to the binding. If globally unique IDs are
0567: * used this always returns <code>0</code>.
0568: *
0569: * @param name fully qualified name of ID'ed class
0570: * @return index number of class
0571: */
0572:
0573: public int getIdClassIndex(String name) {
0574: if (m_isIdGlobal) {
0575: return 0;
0576: } else {
0577: if (m_uniqueIds == null) {
0578: m_uniqueIds = new ArrayMap();
0579: }
0580: return m_uniqueIds.findOrAdd(name);
0581: }
0582: }
0583:
0584: /**
0585: * Get index for namespace URI in binding. If the URI is not already
0586: * included it is first added to the binding. The empty namespace URI
0587: * is always given index number <code>0</code>.
0588: *
0589: * @param uri namespace URI to be included in binding
0590: * @param prefix prefix used with namespace
0591: * @return index number of namespace
0592: */
0593:
0594: public int getNamespaceUriIndex(String uri, String prefix) {
0595: int index = m_namespaceUris.findOrAdd(uri);
0596: if (index > m_namespacePrefixes.size()) {
0597: m_namespacePrefixes.add(prefix);
0598: }
0599: return index;
0600: }
0601:
0602: /**
0603: * Set flag for schema instance namespace used in binding.
0604: */
0605: public void setSchemaInstanceUsed() {
0606: m_isSchemaInstanceUsed = true;
0607: }
0608:
0609: /**
0610: * Generate code. First sets linkages and executes code generation for
0611: * each top-level mapping defined in this binding, which in turn propagates
0612: * the code generation all the way down. Then generates the actual binding
0613: * factory for this binding.
0614: *
0615: * TODO: handle unidirectional bindings properly
0616: *
0617: * @param verbose flag for verbose output
0618: * @throws JiBXException if error in code generation
0619: */
0620:
0621: public void generateCode(boolean verbose) throws JiBXException {
0622:
0623: // check schema instance namespace usage
0624: if (m_isSchemaInstanceUsed) {
0625: NamespaceDefinition xsins = NamespaceDefinition
0626: .buildNamespace(
0627: "http://www.w3.org/2001/XMLSchema-instance",
0628: "xsi");
0629: ArrayList mappings = m_activeContext.getMappings();
0630: for (int i = 0; i < mappings.size(); i++) {
0631: Object mapping = mappings.get(i);
0632: if (mapping instanceof MappingDefinition) {
0633: ((MappingDefinition) mapping).addNamespace(xsins);
0634: }
0635: }
0636: }
0637:
0638: // handle basic linkage and child code generation
0639: BoundClass.setModify(m_targetRoot, m_targetPackage);
0640: m_activeContext.linkMappings();
0641: m_activeContext.setLinkages();
0642: m_activeContext.generateCode(verbose, m_isForceClasses);
0643: // disabled because of potential recursion issues
0644: if (verbose) {
0645: System.out.println("After linking view of binding "
0646: + m_name + ':');
0647: print();
0648: }
0649:
0650: // build the binding factory class
0651: String name;
0652: if (m_targetPackage.length() == 0) {
0653: name = getPrefix() + FACTORY_SUFFIX;
0654: } else {
0655: name = m_targetPackage + '.' + getPrefix() + FACTORY_SUFFIX;
0656: }
0657: ClassFile base = ClassCache.getClassFile("java.lang.Object");
0658: ClassFile cf = new ClassFile(name, m_targetRoot, base,
0659: Constants.ACC_PUBLIC, FACTORY_INTERFACES);
0660:
0661: // add static field for instance and member fields for data
0662: ClassItem inst = cf.addField(FACTORY_INTERFACE,
0663: FACTORY_INSTNAME, FACTORY_INSTACCESS);
0664: ClassItem marshs = cf.addPrivateField(STRING_ARRAYTYPE,
0665: MARSHALLER_ARRAYNAME);
0666: ClassItem umarshs = cf.addPrivateField(STRING_ARRAYTYPE,
0667: UNMARSHALLER_ARRAYNAME);
0668: ClassItem classes = cf.addPrivateField(STRING_ARRAYTYPE,
0669: CLASSES_ARRAYNAME);
0670: ClassItem uris = cf.addPrivateField(STRING_ARRAYTYPE,
0671: URIS_ARRAYNAME);
0672: ClassItem prefs = cf.addPrivateField(STRING_ARRAYTYPE,
0673: PREFIXES_ARRAYNAME);
0674: ClassItem gnames = cf.addPrivateField(STRING_ARRAYTYPE,
0675: GNAMES_ARRAYNAME);
0676: ClassItem guris = cf.addPrivateField(STRING_ARRAYTYPE,
0677: GURIS_ARRAYNAME);
0678: ClassItem idnames = cf.addPrivateField(STRING_ARRAYTYPE,
0679: IDNAMES_ARRAYNAME);
0680:
0681: // add the private constructor method
0682: MethodBuilder mb = new ExceptionMethodBuilder("<init>",
0683: Type.VOID, new Type[0], cf, Constants.ACC_PRIVATE);
0684:
0685: // call the superclass constructor
0686: mb.appendLoadLocal(0);
0687: mb.appendCallInit("java.lang.Object", "()V");
0688:
0689: // create and fill array of unmarshaller class names
0690: int count = s_mappedClasses.size();
0691: int mcnt = m_isMappedDone ? m_mumIndex : count;
0692: if (m_isInput) {
0693: mb.appendLoadLocal(0);
0694: mb.appendLoadConstant(mcnt);
0695: mb.appendCreateArray("java.lang.String");
0696: for (int i = 0; i < count; i++) {
0697: String cname = (String) s_mappedClasses.get(i);
0698: IMapping map = m_activeContext.getMappingAtLevel(cname);
0699: if (map != null && map.getUnmarshaller() != null) {
0700: mb.appendDUP();
0701: mb.appendLoadConstant(i);
0702: mb.appendLoadConstant(map.getUnmarshaller()
0703: .getName());
0704: mb.appendAASTORE();
0705: }
0706: }
0707: for (int i = count; i < mcnt; i++) {
0708: mb.appendDUP();
0709: mb.appendLoadConstant(i);
0710: mb.appendLoadConstant((String) m_extraUnmarshallers
0711: .get(i - count));
0712: mb.appendAASTORE();
0713: }
0714: mb.appendPutField(umarshs);
0715: }
0716:
0717: // create and fill array of marshaller class names
0718: if (m_isOutput) {
0719: mb.appendLoadLocal(0);
0720: mb.appendLoadConstant(mcnt);
0721: mb.appendCreateArray("java.lang.String");
0722: for (int i = 0; i < count; i++) {
0723: String cname = (String) s_mappedClasses.get(i);
0724: IMapping map = m_activeContext.getMappingAtLevel(cname);
0725: if (map != null && map.getMarshaller() != null) {
0726: mb.appendDUP();
0727: mb.appendLoadConstant(i);
0728: mb
0729: .appendLoadConstant(map.getMarshaller()
0730: .getName());
0731: mb.appendAASTORE();
0732: }
0733: }
0734: for (int i = count; i < mcnt; i++) {
0735: mb.appendDUP();
0736: mb.appendLoadConstant(i);
0737: mb.appendLoadConstant((String) m_extraMarshallers.get(i
0738: - count));
0739: mb.appendAASTORE();
0740: }
0741: mb.appendPutField(marshs);
0742: }
0743:
0744: // create and fill array of mapped class names
0745: mb.appendLoadLocal(0);
0746: mb.appendLoadConstant(mcnt);
0747: mb.appendCreateArray("java.lang.String");
0748: for (int i = 0; i < count; i++) {
0749: mb.appendDUP();
0750: mb.appendLoadConstant(i);
0751: mb.appendLoadConstant((String) s_mappedClasses.get(i));
0752: mb.appendAASTORE();
0753: }
0754: for (int i = count; i < mcnt; i++) {
0755: mb.appendDUP();
0756: mb.appendLoadConstant(i);
0757: mb.appendLoadConstant((String) m_extraClasses
0758: .get(i - count));
0759: mb.appendAASTORE();
0760: }
0761: mb.appendPutField(classes);
0762:
0763: // create and fill array of namespace URIs
0764: if (m_isOutput) {
0765: mb.appendLoadLocal(0);
0766: mb.appendLoadConstant(m_namespaceUris.size());
0767: mb.appendCreateArray("java.lang.String");
0768: for (int i = 0; i < m_namespaceUris.size(); i++) {
0769: mb.appendDUP();
0770: mb.appendLoadConstant(i);
0771: mb.appendLoadConstant((String) m_namespaceUris.get(i));
0772: mb.appendAASTORE();
0773: }
0774: mb.appendPutField(uris);
0775: }
0776:
0777: // create and fill array of namespace prefixes
0778: if (m_isOutput) {
0779: mb.appendLoadLocal(0);
0780: mb.appendLoadConstant(m_namespacePrefixes.size());
0781: mb.appendCreateArray("java.lang.String");
0782: for (int i = 0; i < m_namespacePrefixes.size(); i++) {
0783: mb.appendDUP();
0784: mb.appendLoadConstant(i);
0785: mb.appendLoadConstant((String) m_namespacePrefixes
0786: .get(i));
0787: mb.appendAASTORE();
0788: }
0789: mb.appendPutField(prefs);
0790: }
0791:
0792: // create and fill arrays of globally mapped element names and URIs
0793: mb.appendLoadLocal(0);
0794: mb.appendLoadConstant(count);
0795: mb.appendCreateArray("java.lang.String");
0796: for (int i = 0; i < count; i++) {
0797: String cname = (String) s_mappedClasses.get(i);
0798: IMapping map = m_activeContext.getMappingAtLevel(cname);
0799: if (map != null) {
0800: NameDefinition ndef = map.getName();
0801: if (ndef != null) {
0802: mb.appendDUP();
0803: mb.appendLoadConstant(i);
0804: ndef.genPushName(mb);
0805: mb.appendAASTORE();
0806: }
0807: }
0808: }
0809: mb.appendPutField(gnames);
0810: mb.appendLoadLocal(0);
0811: mb.appendLoadConstant(count);
0812: mb.appendCreateArray("java.lang.String");
0813: for (int i = 0; i < count; i++) {
0814: String cname = (String) s_mappedClasses.get(i);
0815: IMapping map = m_activeContext.getMappingAtLevel(cname);
0816: if (map != null) {
0817: NameDefinition ndef = map.getName();
0818: if (ndef != null) {
0819: mb.appendDUP();
0820: mb.appendLoadConstant(i);
0821: ndef.genPushUri(mb);
0822: mb.appendAASTORE();
0823: }
0824: }
0825: }
0826: mb.appendPutField(guris);
0827:
0828: // create and fill array of class names with unique IDs (null if none)
0829: mb.appendLoadLocal(0);
0830: if (m_uniqueIds != null && m_uniqueIds.size() > 0) {
0831: mb.appendLoadConstant(m_uniqueIds.size());
0832: mb.appendCreateArray("java.lang.String");
0833: for (int i = 0; i < m_uniqueIds.size(); i++) {
0834: mb.appendDUP();
0835: mb.appendLoadConstant(i);
0836: mb.appendLoadConstant((String) m_uniqueIds.get(i));
0837: mb.appendAASTORE();
0838: }
0839: } else {
0840: mb.appendACONST_NULL();
0841: }
0842: mb.appendPutField(idnames);
0843:
0844: // get class names for types (abstract non-base mappings)
0845: ArrayList tnames = new ArrayList();
0846: if (m_isForceClasses) {
0847: for (int i = 0; i < count; i++) {
0848: String cname = (String) s_mappedClasses.get(i);
0849: IMapping map = m_activeContext.getMappingAtLevel(cname);
0850: if (map != null && map.isAbstract() && !map.isBase()) {
0851: String tname = map.getTypeName();
0852: if (tname == null) {
0853: tname = cname;
0854: }
0855: tnames.add(tname);
0856: }
0857: }
0858: }
0859:
0860: // check if map needed for types
0861: ClassItem tmap = null;
0862: if (tnames.size() >= TYPEMAP_MINIMUM_SIZE) {
0863:
0864: // create field for map
0865: tmap = cf.addPrivateField(STRINGINT_MAPTYPE, TYPEMAP_NAME);
0866:
0867: // initialize with appropriate size
0868: mb.appendLoadLocal(0);
0869: mb.appendCreateNew(STRINGINT_MAPTYPE);
0870: mb.appendDUP();
0871: mb.appendLoadConstant(tnames.size());
0872: mb.appendCallInit(STRINGINT_MAPTYPE,
0873: STRINGINTINIT_SIGNATURE);
0874:
0875: // add all values to map
0876: for (int i = 0; i < tnames.size(); i++) {
0877: int index = s_mappedClasses.find(tnames.get(i));
0878: if (index >= 0) {
0879: mb.appendDUP();
0880: mb.appendLoadConstant((String) tnames.get(i));
0881: mb.appendLoadConstant(index);
0882: mb.appendCallVirtual(STRINGINTADD_METHOD,
0883: STRINGINTADD_SIGNATURE);
0884: mb.appendPOP();
0885: }
0886: }
0887: mb.appendPutField(tmap);
0888: }
0889:
0890: // finish with return from constructor
0891: mb.appendReturn();
0892: mb.codeComplete(false);
0893: mb.addMethod();
0894:
0895: // add the public marshalling context construction method
0896: mb = new ExceptionMethodBuilder(CREATEMARSHAL_METHODNAME,
0897: ClassItem.typeFromName(MARSHALCONTEXT_INTERFACE),
0898: new Type[0], cf, Constants.ACC_PUBLIC);
0899: if (m_isOutput) {
0900:
0901: // construct and return marshaller instance
0902: mb.appendCreateNew(MARSHALCONTEXT_IMPLEMENTATION);
0903: mb.appendDUP();
0904: mb.appendLoadLocal(0);
0905: mb.appendGetField(classes);
0906: mb.appendLoadLocal(0);
0907: mb.appendGetField(marshs);
0908: mb.appendLoadLocal(0);
0909: mb.appendGetField(uris);
0910: mb.appendLoadLocal(0);
0911: mb.appendCallInit(MARSHALCONTEXT_IMPLEMENTATION,
0912: MARSHALCONTEXTINIT_SIGNATURE);
0913: mb.appendReturn(MARSHALCONTEXT_IMPLEMENTATION);
0914:
0915: } else {
0916:
0917: // throw exception for unsupported operation
0918: mb.appendCreateNew(UNSUPPORTED_EXCEPTION_CLASS);
0919: mb.appendDUP();
0920: mb
0921: .appendLoadConstant("Binding is input only - cannot create unmarshaller");
0922: mb.appendCallInit(UNSUPPORTED_EXCEPTION_CLASS,
0923: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
0924: mb.appendThrow();
0925:
0926: }
0927: mb.codeComplete(false);
0928: mb.addMethod();
0929:
0930: // add the public unmarshalling context construction method
0931: mb = new ExceptionMethodBuilder(CREATEUNMARSHAL_METHODNAME,
0932: ClassItem.typeFromName(UNMARSHALCONTEXT_INTERFACE),
0933: new Type[0], cf, Constants.ACC_PUBLIC);
0934: if (m_isInput) {
0935:
0936: // construct and return unmarshaller instance
0937: mb.appendCreateNew(UNMARSHALCONTEXT_IMPLEMENTATION);
0938: mb.appendDUP();
0939: mb.appendLoadConstant(mcnt);
0940: mb.appendLoadLocal(0);
0941: mb.appendGetField(umarshs);
0942: mb.appendLoadLocal(0);
0943: mb.appendGetField(guris);
0944: mb.appendLoadLocal(0);
0945: mb.appendGetField(gnames);
0946: mb.appendLoadLocal(0);
0947: mb.appendGetField(idnames);
0948: mb.appendLoadLocal(0);
0949: mb.appendCallInit(UNMARSHALCONTEXT_IMPLEMENTATION,
0950: UNMARSHALCONTEXTINIT_SIGNATURE);
0951: mb.appendReturn(UNMARSHALCONTEXT_IMPLEMENTATION);
0952:
0953: } else {
0954:
0955: // throw exception for unsupported operation
0956: mb.appendCreateNew(UNSUPPORTED_EXCEPTION_CLASS);
0957: mb.appendDUP();
0958: mb
0959: .appendLoadConstant("Binding is output only - cannot create marshaller");
0960: mb.appendCallInit(UNSUPPORTED_EXCEPTION_CLASS,
0961: MethodBuilder.EXCEPTION_CONSTRUCTOR_SIGNATURE1);
0962: mb.appendThrow();
0963:
0964: }
0965: mb.codeComplete(false);
0966: mb.addMethod();
0967:
0968: // add the compiler version access method
0969: mb = new ExceptionMethodBuilder(GETVERSION_METHODNAME,
0970: Type.INT, new Type[0], cf, Constants.ACC_PUBLIC);
0971: mb.appendLoadConstant(IBindingFactory.CURRENT_VERSION_NUMBER);
0972: mb.appendReturn("int");
0973: mb.codeComplete(false);
0974: mb.addMethod();
0975:
0976: // add the compiler distribution access method
0977: mb = new ExceptionMethodBuilder(GETDISTRIB_METHODNAME,
0978: Type.STRING, new Type[0], cf, Constants.ACC_PUBLIC);
0979: mb.appendLoadConstant(CURRENT_VERSION_NAME);
0980: mb.appendReturn(Type.STRING);
0981: mb.codeComplete(false);
0982: mb.addMethod();
0983:
0984: // add the defined namespace URI array access method
0985: Type satype = new ArrayType(Type.STRING, 1);
0986: mb = new ExceptionMethodBuilder(GETDEFINEDNSS_METHODNAME,
0987: satype, new Type[0], cf, Constants.ACC_PUBLIC);
0988: mb.appendLoadLocal(0);
0989: mb.appendGetField(uris);
0990: mb.appendReturn(satype);
0991: mb.codeComplete(false);
0992: mb.addMethod();
0993:
0994: // add the defined namespace prefixes array access method
0995: mb = new ExceptionMethodBuilder(GETDEFINEDPREFS_METHODNAME,
0996: satype, new Type[0], cf, Constants.ACC_PUBLIC);
0997: mb.appendLoadLocal(0);
0998: mb.appendGetField(prefs);
0999: mb.appendReturn(satype);
1000: mb.codeComplete(false);
1001: mb.addMethod();
1002:
1003: // add the class name array access method
1004: mb = new ExceptionMethodBuilder(GETCLASSES_METHODNAME, satype,
1005: new Type[0], cf, Constants.ACC_PUBLIC);
1006: mb.appendLoadLocal(0);
1007: mb.appendGetField(classes);
1008: mb.appendReturn(satype);
1009: mb.codeComplete(false);
1010: mb.addMethod();
1011:
1012: // add the element namespace URI array access method
1013: mb = new ExceptionMethodBuilder(GETELEMENTNSS_METHODNAME,
1014: satype, new Type[0], cf, Constants.ACC_PUBLIC);
1015: mb.appendLoadLocal(0);
1016: mb.appendGetField(guris);
1017: mb.appendReturn(satype);
1018: mb.codeComplete(false);
1019: mb.addMethod();
1020:
1021: // add the element name array access method
1022: mb = new ExceptionMethodBuilder(GETELEMENTNAMES_METHODNAME,
1023: satype, new Type[0], cf, Constants.ACC_PUBLIC);
1024: mb.appendLoadLocal(0);
1025: mb.appendGetField(gnames);
1026: mb.appendReturn(satype);
1027: mb.codeComplete(false);
1028: mb.addMethod();
1029:
1030: // add the type mapping index lookup method
1031: mb = new ExceptionMethodBuilder(GETTYPEINDEX_METHODNAME,
1032: Type.INT, new Type[] { Type.STRING }, cf,
1033: Constants.ACC_PUBLIC);
1034: if (tnames.size() > 0) {
1035: if (tmap == null) {
1036:
1037: // generate in-line compares for mapping
1038: for (int i = 0; i < tnames.size(); i++) {
1039: int index = s_mappedClasses.find(tnames.get(i));
1040: if (index >= 0) {
1041: mb.appendLoadLocal(1);
1042: mb.appendLoadConstant((String) tnames.get(i));
1043: mb.appendCallVirtual("java.lang.String.equals",
1044: "(Ljava/lang/Object;)Z");
1045: BranchWrapper onfail = mb.appendIFEQ(this );
1046: mb.appendLoadConstant(index);
1047: mb.appendReturn(Type.INT);
1048: mb.targetNext(onfail);
1049: }
1050: }
1051: mb.appendLoadConstant(-1);
1052:
1053: } else {
1054:
1055: // use map constructed in initializer
1056: mb.appendLoadLocal(0);
1057: mb.appendGetField(tmap);
1058: mb.appendLoadLocal(1);
1059: mb.appendCallVirtual(STRINGINTGET_METHOD,
1060: STRINGINTGET_SIGNATURE);
1061:
1062: }
1063: } else {
1064:
1065: // no types to handle, just always return failure
1066: mb.appendLoadConstant(-1);
1067:
1068: }
1069: mb.appendReturn(Type.INT);
1070: mb.codeComplete(false);
1071: mb.addMethod();
1072:
1073: // finish with instance creation method
1074: mb = new ExceptionMethodBuilder(GETINST_METHODNAME, ClassItem
1075: .typeFromName(FACTORY_INTERFACE), new Type[0], cf,
1076: (short) (Constants.ACC_PUBLIC | Constants.ACC_STATIC));
1077: mb.appendGetStatic(inst);
1078: BranchWrapper ifdone = mb.appendIFNONNULL(this );
1079: mb.appendCreateNew(cf.getName());
1080: mb.appendDUP();
1081: mb.appendCallInit(cf.getName(), "()V");
1082: mb.appendPutStatic(inst);
1083: mb.targetNext(ifdone);
1084: mb.appendGetStatic(inst);
1085: mb.appendReturn(FACTORY_INTERFACE);
1086: mb.codeComplete(false);
1087: mb.addMethod();
1088:
1089: // add factory class to generated registry
1090: cf = MungedClass.getUniqueSupportClass(cf);
1091: String link = name;
1092: if (!name.equals(cf.getName())) {
1093: link = cf.getName() + '=' + name;
1094: }
1095:
1096: // record the binding factory in each top-level mapped class
1097: ArrayList maps = m_activeContext.getMappings();
1098: for (int i = 0; i < maps.size(); i++) {
1099: IMapping map = (IMapping) maps.get(i);
1100: if (map instanceof MappingBase) {
1101: BoundClass bound = ((MappingBase) map).getBoundClass();
1102: if (bound.getClassFile().isModifiable()) {
1103: bound.addFactory(link);
1104: }
1105: }
1106: }
1107: }
1108:
1109: /**
1110: * Get indexed binding.
1111: *
1112: * @param index number of binding to be returned
1113: * @return binding at the specified index
1114: */
1115:
1116: public static BindingDefinition getBinding(int index) {
1117: return (BindingDefinition) s_bindings.get(index);
1118: }
1119:
1120: /**
1121: * Discard cached information and reset in preparation for a new binding
1122: * run.
1123: */
1124:
1125: public static void reset() {
1126: s_bindings = new ArrayList();
1127: s_mappedClasses = new ArrayMap();
1128: }
1129:
1130: //
1131: // IContainer interface method definitions
1132:
1133: public boolean isContentOrdered() {
1134: return true;
1135: }
1136:
1137: public boolean hasNamespaces() {
1138: return false;
1139: }
1140:
1141: public BindingDefinition getBindingRoot() {
1142: return this ;
1143: }
1144:
1145: public DefinitionContext getDefinitionContext() {
1146: return m_activeContext;
1147: }
1148:
1149: // DEBUG
1150: private static byte[] s_blanks = " "
1151: .getBytes();
1152:
1153: public static void indent(int depth) {
1154: if (depth < s_blanks.length) {
1155: System.out.write(s_blanks, 0, depth);
1156: } else {
1157: System.out.print(s_blanks);
1158: }
1159: }
1160:
1161: public void print() {
1162: System.out.println("binding " + m_name + ":");
1163: m_activeContext.print(1);
1164: }
1165: }
|