0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019: package org.apache.openjpa.persistence;
0020:
0021: import java.io.File;
0022: import java.lang.reflect.Field;
0023: import java.lang.reflect.Member;
0024: import java.lang.reflect.Method;
0025: import java.util.ArrayList;
0026: import java.util.Arrays;
0027: import java.util.Collection;
0028: import java.util.Collections;
0029: import java.util.Comparator;
0030: import java.util.HashMap;
0031: import java.util.Iterator;
0032: import java.util.List;
0033: import java.util.Map;
0034: import java.util.Properties;
0035:
0036: import org.apache.commons.lang.StringUtils;
0037: import org.apache.openjpa.conf.OpenJPAConfiguration;
0038: import org.apache.openjpa.kernel.QueryLanguages;
0039: import org.apache.openjpa.lib.conf.Configurations;
0040: import org.apache.openjpa.lib.log.Log;
0041: import org.apache.openjpa.lib.meta.CFMetaDataSerializer;
0042: import org.apache.openjpa.lib.meta.SourceTracker;
0043: import org.apache.openjpa.lib.util.JavaVersions;
0044: import org.apache.openjpa.lib.util.Localizer;
0045: import org.apache.openjpa.meta.ClassMetaData;
0046: import org.apache.openjpa.meta.FieldMetaData;
0047: import org.apache.openjpa.meta.JavaTypes;
0048: import org.apache.openjpa.meta.MetaDataInheritanceComparator;
0049: import static org.apache.openjpa.meta.MetaDataModes.*;
0050: import org.apache.openjpa.meta.MetaDataRepository;
0051: import org.apache.openjpa.meta.Order;
0052: import org.apache.openjpa.meta.QueryMetaData;
0053: import org.apache.openjpa.meta.SequenceMetaData;
0054: import org.apache.openjpa.meta.ValueMetaData;
0055: import org.apache.openjpa.util.InternalException;
0056: import org.xml.sax.SAXException;
0057: import serp.util.Strings;
0058:
0059: /**
0060: * Serializes persistence metadata back to XML.
0061: * This class processes all object level tags that are store-agnostic.
0062: * However, it provides hooks for the subclasses to include store-specific
0063: * tags to be serialized both at <entity-mappings> and
0064: * <entity> level.
0065: *
0066: * @since 0.4.0
0067: * @author Steve Kim
0068: * @nojavadoc
0069: */
0070: public class XMLPersistenceMetaDataSerializer extends
0071: CFMetaDataSerializer implements
0072: PersistenceMetaDataFactory.Serializer {
0073:
0074: // NOTE: order is important! these constants must be maintained in
0075: // serialization order. constants are spaced so that subclasses can
0076: // slip tags in-between
0077: protected static final int TYPE_SEQ = 10;
0078: protected static final int TYPE_QUERY = 20;
0079: protected static final int TYPE_META = 30;
0080: protected static final int TYPE_CLASS_SEQS = 40;
0081: protected static final int TYPE_CLASS_QUERIES = 50;
0082:
0083: private static final Localizer _loc = Localizer
0084: .forPackage(XMLPersistenceMetaDataSerializer.class);
0085:
0086: private final OpenJPAConfiguration _conf;
0087: private Map<String, ClassMetaData> _metas = null;
0088: private Map<String, List> _queries = null;
0089: private Map<String, List> _seqs = null;
0090: private int _mode = MODE_NONE;
0091: private boolean _annos = true;
0092: private SerializationComparator _comp = null;
0093:
0094: /**
0095: * Constructor. Supply configuration.
0096: */
0097: public XMLPersistenceMetaDataSerializer(OpenJPAConfiguration conf) {
0098: _conf = conf;
0099: setLog(conf.getLog(OpenJPAConfiguration.LOG_METADATA));
0100: setMode(MODE_META | MODE_MAPPING | MODE_QUERY);
0101: }
0102:
0103: /**
0104: * Configuration.
0105: */
0106: public OpenJPAConfiguration getConfiguration() {
0107: return _conf;
0108: }
0109:
0110: /**
0111: * Whether to serialize content originally specified in annotations.
0112: * Defaults to true.
0113: */
0114: public boolean getSerializeAnnotations() {
0115: return _annos;
0116: }
0117:
0118: /**
0119: * Whether to serialize content originally specified in annotations.
0120: * Defaults to true.
0121: */
0122: public void setSerializeAnnotations(boolean annos) {
0123: _annos = annos;
0124: }
0125:
0126: /**
0127: * The serialization mode according to the expected document type. The
0128: * mode constants act as bit flags, and therefore can be combined.
0129: */
0130: public int getMode() {
0131: return _mode;
0132: }
0133:
0134: /**
0135: * The serialization mode according to the expected document type. The
0136: * mode constants act as bit flags, and therefore can be combined.
0137: */
0138: public void setMode(int mode) {
0139: _mode = mode;
0140: }
0141:
0142: /**
0143: * The serialization mode according to the expected document type.
0144: */
0145: public void setMode(int mode, boolean on) {
0146: if (mode == MODE_NONE)
0147: setMode(MODE_NONE);
0148: else if (on)
0149: setMode(_mode | mode);
0150: else
0151: setMode(_mode & ~mode);
0152: }
0153:
0154: /**
0155: * Override to not overwrite annotations.
0156: */
0157: @Override
0158: protected File getSourceFile(Object obj) {
0159: File file = super .getSourceFile(obj);
0160: if (file == null || file.getName().endsWith(".java")
0161: || file.getName().endsWith(".class"))
0162: return null;
0163: return file;
0164: }
0165:
0166: /**
0167: * Convenience method for interpreting {@link #getMode}.
0168: */
0169: protected boolean isMetaDataMode() {
0170: return (_mode & MODE_META) != 0;
0171: }
0172:
0173: /**
0174: * Convenience method for interpreting {@link #getMode}.
0175: */
0176: protected boolean isQueryMode() {
0177: return (_mode & MODE_QUERY) != 0;
0178: }
0179:
0180: /**
0181: * Convenience method for interpreting {@link #getMode}.
0182: */
0183: protected boolean isMappingMode() {
0184: return (_mode & MODE_MAPPING) != 0;
0185: }
0186:
0187: /**
0188: * Convenience method for interpreting {@link #getMode}. Takes into
0189: * account whether mapping information is loaded for the given instance.
0190: */
0191: protected boolean isMappingMode(ClassMetaData meta) {
0192: return isMappingMode()
0193: && (meta.getSourceMode() & MODE_MAPPING) != 0
0194: && (meta.getEmbeddingMetaData() != null || !meta
0195: .isEmbeddedOnly())
0196: && (meta.getEmbeddingMetaData() == null || isMappingMode(meta
0197: .getEmbeddingMetaData()));
0198: }
0199:
0200: /**
0201: * Convenience method for interpreting {@link #getMode}. Takes into
0202: * account whether mapping information is loaded for the given instance.
0203: */
0204: protected boolean isMappingMode(ValueMetaData vmd) {
0205: return isMappingMode(vmd.getFieldMetaData()
0206: .getDefiningMetaData());
0207: }
0208:
0209: /**
0210: * Add a class meta data to the set to be serialized.
0211: */
0212: public void addMetaData(ClassMetaData meta) {
0213: if (meta == null)
0214: return;
0215:
0216: if (_metas == null)
0217: _metas = new HashMap<String, ClassMetaData>();
0218: _metas.put(meta.getDescribedType().getName(), meta);
0219: }
0220:
0221: /**
0222: * Add a sequence meta data to the set to be serialized.
0223: */
0224: public void addSequenceMetaData(SequenceMetaData meta) {
0225: if (meta == null)
0226: return;
0227:
0228: List seqs = null;
0229: String defName = null;
0230: if (meta.getSourceScope() instanceof Class)
0231: defName = ((Class) meta.getSourceScope()).getName();
0232: if (_seqs == null)
0233: _seqs = new HashMap<String, List>();
0234: else
0235: seqs = _seqs.get(defName);
0236:
0237: if (seqs == null) {
0238: seqs = new ArrayList(3); // don't expect many seqs / class
0239: seqs.add(meta);
0240: _seqs.put(defName, seqs);
0241: } else if (!seqs.contains(meta))
0242: seqs.add(meta);
0243: }
0244:
0245: /**
0246: * Add a query meta data to the set to be serialized.
0247: */
0248: public void addQueryMetaData(QueryMetaData meta) {
0249: if (meta == null)
0250: return;
0251:
0252: List queries = null;
0253: String defName = null;
0254: if (meta.getSourceScope() instanceof Class)
0255: defName = ((Class) meta.getSourceScope()).getName();
0256: if (_queries == null)
0257: _queries = new HashMap<String, List>();
0258: else
0259: queries = _queries.get(defName);
0260:
0261: if (queries == null) {
0262: queries = new ArrayList(3); // don't expect many queries / class
0263: queries.add(meta);
0264: _queries.put(defName, queries);
0265: } else if (!queries.contains(meta))
0266: queries.add(meta);
0267: }
0268:
0269: /**
0270: * Add all components in the given repository to the set to be serialized.
0271: */
0272: public void addAll(MetaDataRepository repos) {
0273: if (repos == null)
0274: return;
0275:
0276: for (ClassMetaData meta : repos.getMetaDatas())
0277: addMetaData(meta);
0278: for (SequenceMetaData seq : repos.getSequenceMetaDatas())
0279: addSequenceMetaData(seq);
0280: for (QueryMetaData query : repos.getQueryMetaDatas())
0281: addQueryMetaData(query);
0282: }
0283:
0284: /**
0285: * Remove a metadata from the set to be serialized.
0286: *
0287: * @return true if removed, false if not in set
0288: */
0289: public boolean removeMetaData(ClassMetaData meta) {
0290: return _metas != null
0291: && meta != null
0292: && _metas.remove(meta.getDescribedType().getName()) != null;
0293: }
0294:
0295: /**
0296: * Remove a sequence metadata from the set to be serialized.
0297: *
0298: * @return true if removed, false if not in set
0299: */
0300: public boolean removeSequenceMetaData(SequenceMetaData meta) {
0301: if (_seqs == null || meta == null)
0302: return false;
0303: String defName = null;
0304: if (meta.getSourceScope() instanceof Class)
0305: defName = ((Class) meta.getSourceScope()).getName();
0306: List seqs = _seqs.get(defName);
0307: if (seqs == null)
0308: return false;
0309: if (!seqs.remove(meta))
0310: return false;
0311: if (seqs.isEmpty())
0312: _seqs.remove(defName);
0313: return true;
0314: }
0315:
0316: /**
0317: * Remove a query metadata from the set to be serialized.
0318: *
0319: * @return true if removed, false if not in set
0320: */
0321: public boolean removeQueryMetaData(QueryMetaData meta) {
0322: if (_queries == null || meta == null)
0323: return false;
0324: String defName = null;
0325: if (meta.getSourceScope() instanceof Class)
0326: defName = ((Class) meta.getSourceScope()).getName();
0327: List queries = _queries.get(defName);
0328: if (queries == null)
0329: return false;
0330: if (!queries.remove(meta))
0331: return false;
0332: if (queries.isEmpty())
0333: _queries.remove(defName);
0334: return true;
0335: }
0336:
0337: /**
0338: * Remove all the components in the given repository from the set to be
0339: * serialized.
0340: *
0341: * @return true if any components removed, false if none in set
0342: */
0343: public boolean removeAll(MetaDataRepository repos) {
0344: if (repos == null)
0345: return false;
0346:
0347: boolean removed = false;
0348: ClassMetaData[] metas = repos.getMetaDatas();
0349: for (int i = 0; i < metas.length; i++)
0350: removed |= removeMetaData(metas[i]);
0351: SequenceMetaData[] seqs = repos.getSequenceMetaDatas();
0352: for (int i = 0; i < seqs.length; i++)
0353: removed |= removeSequenceMetaData(seqs[i]);
0354: QueryMetaData[] queries = repos.getQueryMetaDatas();
0355: for (int i = 0; i < queries.length; i++)
0356: removed |= removeQueryMetaData(queries[i]);
0357: return removed;
0358: }
0359:
0360: /**
0361: * Clear the set of metadatas to be serialized.
0362: */
0363: public void clear() {
0364: if (_metas != null)
0365: _metas.clear();
0366: if (_seqs != null)
0367: _seqs.clear();
0368: if (_queries != null)
0369: _queries.clear();
0370: }
0371:
0372: @Override
0373: protected Collection getObjects() {
0374: List all = new ArrayList();
0375: if (isQueryMode())
0376: addQueryMetaDatas(all);
0377: if (isMappingMode())
0378: addSequenceMetaDatas(all);
0379: if ((isMetaDataMode() || isMappingMode()) && _metas != null)
0380: all.addAll(_metas.values());
0381: if (isMappingMode())
0382: addSystemMappingElements(all);
0383: serializationSort(all);
0384: return all;
0385: }
0386:
0387: /**
0388: * Add system-level mapping elements to be serialized. Does nothing
0389: * by default.
0390: */
0391: protected void addSystemMappingElements(Collection toSerialize) {
0392: }
0393:
0394: /**
0395: * Sort the given collection of objects to be serialized.
0396: */
0397: private void serializationSort(List objs) {
0398: if (objs == null || objs.isEmpty())
0399: return;
0400: if (_comp == null)
0401: _comp = newSerializationComparator();
0402: Collections.sort(objs, _comp);
0403: }
0404:
0405: /**
0406: * Create a new comparator for ordering objects that are to be serialized.
0407: */
0408: protected SerializationComparator newSerializationComparator() {
0409: return _comp;
0410: }
0411:
0412: /**
0413: * Add sequence metadata to the given metadatas collection.
0414: */
0415: private void addSequenceMetaDatas(Collection all) {
0416: if (_seqs == null)
0417: return;
0418:
0419: for (Map.Entry entry : _seqs.entrySet()) {
0420: if (entry.getKey() == null)
0421: all.addAll((List) entry.getValue());
0422: else if (_metas == null
0423: || !_metas.containsKey(entry.getKey()))
0424: all.add(new ClassSeqs((List<SequenceMetaData>) entry
0425: .getValue()));
0426: }
0427: }
0428:
0429: /**
0430: * Add query metadata to the given metadatas collection.
0431: */
0432: private void addQueryMetaDatas(Collection all) {
0433: if (_queries == null)
0434: return;
0435:
0436: for (Map.Entry entry : _queries.entrySet()) {
0437: if (entry.getKey() == null)
0438: all.addAll((List) entry.getValue());
0439: else if (_mode == MODE_QUERY || _metas == null
0440: || !_metas.containsKey(entry.getKey()))
0441: all.add(new ClassQueries((List<QueryMetaData>) entry
0442: .getValue()));
0443: }
0444: }
0445:
0446: @Override
0447: protected void serialize(Collection objects) throws SAXException {
0448: // copy collection to avoid mutation
0449: Object meta;
0450: boolean unique = true;
0451: boolean fieldAccess = false;
0452: boolean propertyAccess = false;
0453: for (Iterator it = objects.iterator(); it.hasNext();) {
0454: meta = it.next();
0455: switch (type(meta)) {
0456: case TYPE_META:
0457: ClassMetaData cls = (ClassMetaData) meta;
0458: if (cls.getAccessType() == ClassMetaData.ACCESS_FIELD)
0459: fieldAccess = true;
0460: else
0461: propertyAccess = true;
0462: // no break
0463: default:
0464: if (unique && getPackage() == null)
0465: setPackage(getPackage(meta));
0466: else if (unique) {
0467: unique = getPackage().equals(getPackage(meta));
0468: if (!unique)
0469: setPackage(null);
0470: }
0471: }
0472: }
0473:
0474: serializeNamespaceAttributes();
0475: startElement("entity-mappings");
0476: if (getPackage() != null) {
0477: startElement("package");
0478: addText(getPackage());
0479: endElement("package");
0480: }
0481: if (fieldAccess != propertyAccess) // i.e. only one
0482: {
0483: int def = getConfiguration()
0484: .getMetaDataRepositoryInstance()
0485: .getMetaDataFactory().getDefaults()
0486: .getDefaultAccessType();
0487: String access = null;
0488: if (fieldAccess && def == ClassMetaData.ACCESS_PROPERTY)
0489: access = "FIELD";
0490: else if (propertyAccess
0491: && def == ClassMetaData.ACCESS_FIELD)
0492: access = "PROPERTY";
0493: if (access != null) {
0494: startElement("access");
0495: addText(access);
0496: endElement("access");
0497: }
0498: }
0499: for (Object obj : objects) {
0500: int type = type(obj);
0501: switch (type) {
0502: case TYPE_META:
0503: serializeClass((ClassMetaData) obj, fieldAccess
0504: && propertyAccess);
0505: break;
0506: case TYPE_SEQ:
0507: if (isMappingMode())
0508: serializeSequence((SequenceMetaData) obj);
0509: case TYPE_QUERY:
0510: serializeQuery((QueryMetaData) obj);
0511: break;
0512: case TYPE_CLASS_QUERIES:
0513: for (QueryMetaData query : ((ClassQueries) obj)
0514: .getQueries())
0515: serializeQuery(query);
0516: break;
0517: case TYPE_CLASS_SEQS:
0518: if (isMappingMode())
0519: for (SequenceMetaData seq : ((ClassSeqs) obj)
0520: .getSequences())
0521: serializeSequence(seq);
0522: break;
0523: default:
0524: if (isMappingMode())
0525: serializeSystemMappingElement(obj);
0526: break;
0527: }
0528: }
0529: endElement("entity-mappings");
0530: }
0531:
0532: @Override
0533: protected String getPackage(Object obj) {
0534: int type = type(obj);
0535: switch (type) {
0536: case TYPE_META:
0537: return Strings.getPackageName(((ClassMetaData) obj)
0538: .getDescribedType());
0539: case TYPE_QUERY:
0540: case TYPE_SEQ:
0541: case TYPE_CLASS_QUERIES:
0542: case TYPE_CLASS_SEQS:
0543: SourceTracker st = (SourceTracker) obj;
0544: if (st.getSourceScope() instanceof Class)
0545: return Strings.getPackageName((Class) st
0546: .getSourceScope());
0547: return null;
0548: default:
0549: return null;
0550: }
0551: }
0552:
0553: /**
0554: * Return the type constant for the given object based on its runtime
0555: * class. If the runtime class does not correspond to any of the known
0556: * types then returns -1. This can happen for tags
0557: * that are not handled at this store-agnostic level.
0558: */
0559: protected int type(Object o) {
0560: if (o instanceof ClassMetaData)
0561: return TYPE_META;
0562: if (o instanceof QueryMetaData)
0563: return TYPE_QUERY;
0564: if (o instanceof SequenceMetaData)
0565: return TYPE_SEQ;
0566: if (o instanceof ClassQueries)
0567: return TYPE_CLASS_QUERIES;
0568: if (o instanceof ClassSeqs)
0569: return TYPE_CLASS_SEQS;
0570: return -1;
0571: }
0572:
0573: /**
0574: * Serialize namespace attributes
0575: */
0576: private void serializeNamespaceAttributes() throws SAXException {
0577: addAttribute("xmlns",
0578: "http://java.sun.com/xml/ns/persistence/orm");
0579: addAttribute("xmlns:xsi",
0580: "http://www.w3.org/2001/XMLSchema-instance");
0581: addAttribute("xsi:schemaLocation",
0582: "http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd");
0583: addAttribute("version", "1.0");
0584: }
0585:
0586: /**
0587: * Serialize unknown mapping element at system level.
0588: */
0589: protected void serializeSystemMappingElement(Object obj)
0590: throws SAXException {
0591: }
0592:
0593: /**
0594: * Serialize query metadata.
0595: */
0596: private void serializeQuery(QueryMetaData meta) throws SAXException {
0597: if (!_annos && meta.getSourceType() == meta.SRC_ANNOTATIONS)
0598: return;
0599:
0600: Log log = getLog();
0601: if (log.isInfoEnabled()) {
0602: if (meta.getSourceScope() instanceof Class)
0603: log.info(_loc.get("ser-cls-query", meta
0604: .getSourceScope(), meta.getName()));
0605: else
0606: log.info(_loc.get("ser-query", meta.getName()));
0607: }
0608:
0609: addComments(meta);
0610: addAttribute("name", meta.getName());
0611: addAttribute("query", meta.getQueryString());
0612: if (QueryLanguages.LANG_SQL.equals(meta.getLanguage())) {
0613: if (meta.getResultType() != null)
0614: addAttribute("result-class", meta.getResultType()
0615: .getName());
0616: startElement("named-native-query");
0617: serializeQueryHints(meta);
0618: endElement("named-native-query");
0619: } else {
0620: startElement("named-query");
0621: serializeQueryHints(meta);
0622: endElement("named-query");
0623: }
0624: }
0625:
0626: /**
0627: * Serialize query hints.
0628: */
0629: private void serializeQueryHints(QueryMetaData meta)
0630: throws SAXException {
0631: String[] hints = meta.getHintKeys();
0632: Object[] values = meta.getHintValues();
0633: for (int i = 0; i < hints.length; i++) {
0634: addAttribute("name", hints[i]);
0635: addAttribute("value", String.valueOf(values[i]));
0636: startElement("query-hint");
0637: endElement("query-hint");
0638: }
0639: }
0640:
0641: /**
0642: * Serialize sequence metadata.
0643: */
0644: protected void serializeSequence(SequenceMetaData meta)
0645: throws SAXException {
0646: if (!_annos && meta.getSourceType() == meta.SRC_ANNOTATIONS)
0647: return;
0648:
0649: Log log = getLog();
0650: if (log.isInfoEnabled())
0651: log.info(_loc.get("ser-sequence", meta.getName()));
0652:
0653: addComments(meta);
0654: addAttribute("name", meta.getName());
0655:
0656: // parse out the datastore sequence name, if any
0657: String plugin = meta.getSequencePlugin();
0658: String clsName = Configurations.getClassName(plugin);
0659: String props = Configurations.getProperties(plugin);
0660: String ds = null;
0661: if (props != null) {
0662: Properties map = Configurations.parseProperties(props);
0663: ds = (String) map.remove("Sequence");
0664: if (ds != null) {
0665: props = Configurations.serializeProperties(map);
0666: plugin = Configurations.getPlugin(clsName, props);
0667: }
0668: }
0669:
0670: if (ds != null)
0671: addAttribute("sequence-name", ds);
0672: else if (plugin != null
0673: && !SequenceMetaData.IMPL_NATIVE.equals(plugin))
0674: addAttribute("sequence-name", plugin);
0675: if (meta.getInitialValue() != 0 && meta.getInitialValue() != -1)
0676: addAttribute("initial-value", String.valueOf(meta
0677: .getInitialValue()));
0678: if (meta.getAllocate() != 50 && meta.getAllocate() != -1)
0679: addAttribute("allocation-size", String.valueOf(meta
0680: .getAllocate()));
0681:
0682: startElement("sequence-generator");
0683: endElement("sequence-generator");
0684: }
0685:
0686: /**
0687: * Serialize class metadata.
0688: */
0689: protected void serializeClass(ClassMetaData meta, boolean access)
0690: throws SAXException {
0691: if (!_annos && meta.getSourceType() == meta.SRC_ANNOTATIONS)
0692: return;
0693:
0694: Log log = getLog();
0695: if (log.isInfoEnabled())
0696: log.info(_loc.get("ser-class", meta));
0697:
0698: addComments(meta);
0699: addAttribute("class", getClassName(meta.getDescribedType()
0700: .getName()));
0701:
0702: if (isMetaDataMode()
0703: && !meta.getTypeAlias().equals(
0704: Strings.getClassName(meta.getDescribedType())))
0705: addAttribute("name", meta.getTypeAlias());
0706:
0707: String name = getEntityElementName(meta);
0708: if (isMetaDataMode())
0709: addClassAttributes(meta, access);
0710: if (isMappingMode())
0711: addClassMappingAttributes(meta);
0712:
0713: startElement(name);
0714: if (isMappingMode())
0715: serializeClassMappingContent(meta);
0716: if (isMetaDataMode())
0717: serializeIdClass(meta);
0718: if (isMappingMode())
0719: serializeInheritanceContent(meta);
0720:
0721: if (isMappingMode()) {
0722: List seqs = (_seqs == null) ? null : _seqs.get(meta
0723: .getDescribedType().getName());
0724: if (seqs != null) {
0725: serializationSort(seqs);
0726: for (int i = 0; i < seqs.size(); i++)
0727: serializeSequence((SequenceMetaData) seqs.get(i));
0728: }
0729: }
0730:
0731: if (isQueryMode()) {
0732: List queries = (_queries == null) ? null : _queries
0733: .get(meta.getDescribedType().getName());
0734: if (queries != null) {
0735: serializationSort(queries);
0736: for (int i = 0; i < queries.size(); i++)
0737: serializeQuery((QueryMetaData) queries.get(i));
0738: }
0739: if (isMappingMode())
0740: serializeQueryMappings(meta);
0741: }
0742:
0743: List<FieldMetaData> fields = new ArrayList(Arrays.asList(meta
0744: .getDefinedFieldsInListingOrder()));
0745: Collections.sort(fields, new FieldComparator());
0746:
0747: // serialize attr-override
0748: if (isMappingMode()) {
0749: FieldMetaData fmd;
0750: FieldMetaData orig;
0751: for (Iterator<FieldMetaData> it = fields.iterator(); it
0752: .hasNext();) {
0753: fmd = it.next();
0754: if (meta.getDefinedSuperclassField(fmd.getName()) == null)
0755: continue;
0756: orig = meta.getPCSuperclassMetaData().getField(
0757: fmd.getName());
0758: if (serializeAttributeOverride(fmd, orig))
0759: serializeAttributeOverrideContent(fmd, orig);
0760: it.remove();
0761: }
0762: }
0763:
0764: if (fields.size() > 0 && (isMetaDataMode() || isMappingMode())) {
0765: startElement("attributes");
0766: FieldMetaData orig;
0767: for (FieldMetaData fmd : fields) {
0768: if (fmd.getDeclaringType() != fmd.getDefiningMetaData()
0769: .getDescribedType()) {
0770: orig = fmd.getDeclaringMetaData().getDeclaredField(
0771: fmd.getName());
0772: } else
0773: orig = null;
0774: serializeField(fmd, orig);
0775: }
0776: endElement("attributes");
0777: }
0778: endElement(name);
0779: }
0780:
0781: /**
0782: * Return the entity element name.
0783: */
0784: private static String getEntityElementName(ClassMetaData meta) {
0785: switch (getEntityTag(meta)) {
0786: case ENTITY:
0787: return "entity";
0788: case EMBEDDABLE:
0789: return "embeddable";
0790: case MAPPED_SUPERCLASS:
0791: return "mapped-superclass";
0792: default:
0793: throw new IllegalStateException();
0794: }
0795: }
0796:
0797: /**
0798: * Return the MetaDataTag for the given class meta data.
0799: */
0800: private static MetaDataTag getEntityTag(ClassMetaData meta) {
0801: // @Embeddable classes can't declare Id fields
0802: if (meta.isEmbeddedOnly()
0803: && meta.getPrimaryKeyFields().length == 0)
0804: return MetaDataTag.EMBEDDABLE;
0805: if (meta.isMapped())
0806: return MetaDataTag.ENTITY;
0807: return MetaDataTag.MAPPED_SUPERCLASS;
0808: }
0809:
0810: /**
0811: * Set class attributes.
0812: *
0813: * @param access whether to write access
0814: */
0815: private void addClassAttributes(ClassMetaData meta, boolean access) {
0816: if (!access)
0817: return;
0818: int def = getConfiguration().getMetaDataRepositoryInstance()
0819: .getMetaDataFactory().getDefaults()
0820: .getDefaultAccessType();
0821: if (meta.getAccessType() == ClassMetaData.ACCESS_FIELD
0822: && def == ClassMetaData.ACCESS_PROPERTY)
0823: addAttribute("access", "FIELD");
0824: else if (meta.getAccessType() == ClassMetaData.ACCESS_PROPERTY
0825: && def == ClassMetaData.ACCESS_FIELD)
0826: addAttribute("access", "PROPERTY");
0827: }
0828:
0829: /**
0830: * Add mapping attributes for the given class. Does nothing by default
0831: */
0832: protected void addClassMappingAttributes(ClassMetaData mapping)
0833: throws SAXException {
0834: }
0835:
0836: /**
0837: * Serialize id-class.
0838: */
0839: private void serializeIdClass(ClassMetaData meta)
0840: throws SAXException {
0841: if (meta.getIdentityType() != ClassMetaData.ID_APPLICATION
0842: || meta.isOpenJPAIdentity())
0843: return;
0844:
0845: ClassMetaData sup = meta.getPCSuperclassMetaData();
0846: Class oid = meta.getObjectIdType();
0847: if (oid != null
0848: && (sup == null || oid != sup.getObjectIdType())) {
0849: addAttribute("class", getClassName(oid.getName()));
0850: startElement("id-class");
0851: endElement("id-class");
0852: }
0853: }
0854:
0855: /**
0856: * Serialize class mapping content. Does nothing by default.
0857: */
0858: protected void serializeClassMappingContent(ClassMetaData mapping)
0859: throws SAXException {
0860: }
0861:
0862: /**
0863: * Serialize inheritance content. Does nothing by default.
0864: */
0865: protected void serializeInheritanceContent(ClassMetaData mapping)
0866: throws SAXException {
0867: }
0868:
0869: /**
0870: * Serialize query mappings. Does nothing by default.
0871: */
0872: protected void serializeQueryMappings(ClassMetaData meta)
0873: throws SAXException {
0874: }
0875:
0876: /**
0877: * Serialize the given field.
0878: */
0879: private void serializeField(FieldMetaData fmd, FieldMetaData orig)
0880: throws SAXException {
0881: if (fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT
0882: && !fmd.isExplicit())
0883: return;
0884:
0885: addComments(fmd);
0886: addAttribute("name", fmd.getName());
0887:
0888: String strategy = null;
0889: PersistenceStrategy strat = getStrategy(fmd);
0890: ValueMetaData cascades = null;
0891: if (fmd.isPrimaryKey() && strat == PersistenceStrategy.EMBEDDED)
0892: strategy = "embedded-id";
0893: else if (fmd.isPrimaryKey())
0894: strategy = "id";
0895: else if (fmd.isVersion())
0896: strategy = "version";
0897: else {
0898: switch (strat) {
0899: case TRANSIENT:
0900: strategy = "transient";
0901: break;
0902: case BASIC:
0903: if (isMetaDataMode())
0904: addBasicAttributes(fmd);
0905: strategy = "basic";
0906: break;
0907: case EMBEDDED:
0908: strategy = "embedded";
0909: break;
0910: case MANY_ONE:
0911: if (isMetaDataMode())
0912: addManyToOneAttributes(fmd);
0913: strategy = "many-to-one";
0914: cascades = fmd;
0915: break;
0916: case ONE_ONE:
0917: if (isMetaDataMode())
0918: addOneToOneAttributes(fmd);
0919: strategy = "one-to-one";
0920: cascades = fmd;
0921: break;
0922: case ONE_MANY:
0923: if (isMetaDataMode())
0924: addOneToManyAttributes(fmd);
0925: strategy = "one-to-many";
0926: cascades = fmd.getElement();
0927: break;
0928: case MANY_MANY:
0929: if (isMetaDataMode())
0930: addManyToManyAttributes(fmd);
0931: strategy = "many-to-many";
0932: cascades = fmd.getElement();
0933: break;
0934: }
0935: if (isMappingMode())
0936: addStrategyMappingAttributes(fmd);
0937: }
0938: if (isMappingMode(fmd))
0939: addFieldMappingAttributes(fmd, orig);
0940:
0941: startElement(strategy);
0942: if (fmd.getOrderDeclaration() != null) {
0943: startElement("order-by");
0944: if (!(Order.ELEMENT + " asc").equals(fmd
0945: .getOrderDeclaration()))
0946: addText(fmd.getOrderDeclaration());
0947: endElement("order-by");
0948: }
0949: if (isMappingMode() && fmd.getKey().getValueMappedBy() != null) {
0950: FieldMetaData mapBy = fmd.getKey()
0951: .getValueMappedByMetaData();
0952: if (!mapBy.isPrimaryKey()
0953: || mapBy.getDefiningMetaData()
0954: .getPrimaryKeyFields().length != 1) {
0955: addAttribute("name", fmd.getKey().getValueMappedBy());
0956: }
0957: startElement("map-key");
0958: endElement("map-key");
0959: }
0960: if (isMappingMode(fmd))
0961: serializeFieldMappingContent(fmd, strat);
0962: if (cascades != null && isMetaDataMode())
0963: serializeCascades(cascades);
0964: if (isMappingMode() && strat == PersistenceStrategy.EMBEDDED) {
0965: ClassMetaData meta = fmd.getEmbeddedMetaData();
0966: ClassMetaData owner = getConfiguration()
0967: .getMetaDataRepositoryInstance().getMetaData(
0968: meta.getDescribedType(),
0969: meta.getEnvClassLoader(), true);
0970: FieldMetaData eorig;
0971: for (FieldMetaData efmd : meta.getFields()) {
0972: eorig = owner.getField(efmd.getName());
0973: if (serializeAttributeOverride(efmd, eorig))
0974: serializeAttributeOverrideContent(efmd, eorig);
0975: }
0976: }
0977: endElement(strategy);
0978: }
0979:
0980: /**
0981: * Add mapping attributes for the given field. Does nothing by default.
0982: */
0983: protected void addFieldMappingAttributes(FieldMetaData fmd,
0984: FieldMetaData orig) throws SAXException {
0985: }
0986:
0987: /**
0988: * Always returns false by default.
0989: */
0990: protected boolean serializeAttributeOverride(FieldMetaData fmd,
0991: FieldMetaData orig) {
0992: return false;
0993: }
0994:
0995: /**
0996: * Serialize attribute override content.
0997: */
0998: private void serializeAttributeOverrideContent(FieldMetaData fmd,
0999: FieldMetaData orig) throws SAXException {
1000: addAttribute("name", fmd.getName());
1001: startElement("attribute-override");
1002: serializeAttributeOverrideMappingContent(fmd, orig);
1003: endElement("attribute-override");
1004: }
1005:
1006: /**
1007: * Serialize attribute override mapping content. Does nothing by default,
1008: */
1009: protected void serializeAttributeOverrideMappingContent(
1010: FieldMetaData fmd, FieldMetaData orig) throws SAXException {
1011: }
1012:
1013: /**
1014: * Serialize cascades.
1015: */
1016: private void serializeCascades(ValueMetaData vmd)
1017: throws SAXException {
1018: Collection<String> cascades = null;
1019: if (vmd.getCascadePersist() == ValueMetaData.CASCADE_IMMEDIATE) {
1020: if (cascades == null)
1021: cascades = new ArrayList<String>();
1022: cascades.add("cascade-persist");
1023: }
1024: if (vmd.getCascadeAttach() == ValueMetaData.CASCADE_IMMEDIATE) {
1025: if (cascades == null)
1026: cascades = new ArrayList<String>();
1027: cascades.add("cascade-merge");
1028: }
1029: if (vmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE) {
1030: if (cascades == null)
1031: cascades = new ArrayList<String>();
1032: cascades.add("cascade-remove");
1033: }
1034: if (vmd.getCascadeRefresh() == ValueMetaData.CASCADE_IMMEDIATE) {
1035: if (cascades == null)
1036: cascades = new ArrayList<String>();
1037: cascades.add("cascade-refresh");
1038: }
1039: if (cascades != null && cascades.size() == 4) // ALL
1040: {
1041: cascades.clear();
1042: cascades.add("cascade-all");
1043: }
1044: if (cascades != null) {
1045: startElement("cascade");
1046: for (String cascade : cascades) {
1047: startElement(cascade);
1048: endElement(cascade);
1049: }
1050: endElement("cascade");
1051: }
1052: }
1053:
1054: /**
1055: * Return the serialized strategy name.
1056: */
1057: protected PersistenceStrategy getStrategy(FieldMetaData fmd) {
1058: if (fmd.getManagement() == fmd.MANAGE_NONE)
1059: return PersistenceStrategy.TRANSIENT;
1060:
1061: if (fmd.isSerialized() || fmd.getDeclaredType() == byte[].class
1062: || fmd.getDeclaredType() == Byte[].class
1063: || fmd.getDeclaredType() == char[].class
1064: || fmd.getDeclaredType() == Character[].class)
1065: return PersistenceStrategy.BASIC;
1066:
1067: FieldMetaData mappedBy;
1068: switch (fmd.getDeclaredTypeCode()) {
1069: case JavaTypes.PC:
1070: if (fmd.isEmbedded())
1071: return PersistenceStrategy.EMBEDDED;
1072: if (fmd.getMappedBy() != null)
1073: return PersistenceStrategy.ONE_ONE;
1074: FieldMetaData[] inverses = fmd.getInverseMetaDatas();
1075: if (inverses.length == 1
1076: && inverses[0].getTypeCode() == JavaTypes.PC
1077: && inverses[0].getMappedByMetaData() == fmd) {
1078: return PersistenceStrategy.ONE_ONE;
1079: }
1080: return PersistenceStrategy.MANY_ONE;
1081: case JavaTypes.ARRAY:
1082: case JavaTypes.COLLECTION:
1083: case JavaTypes.MAP:
1084: mappedBy = fmd.getMappedByMetaData();
1085: if (mappedBy == null
1086: || mappedBy.getTypeCode() != JavaTypes.PC)
1087: return PersistenceStrategy.MANY_MANY;
1088: return PersistenceStrategy.ONE_MANY;
1089: case JavaTypes.OID:
1090: return PersistenceStrategy.EMBEDDED;
1091: default:
1092: return PersistenceStrategy.BASIC;
1093: }
1094: }
1095:
1096: /**
1097: * Add basic attributes.
1098: */
1099: private void addBasicAttributes(FieldMetaData fmd)
1100: throws SAXException {
1101: if (!fmd.isInDefaultFetchGroup())
1102: addAttribute("fetch", "LAZY");
1103: if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
1104: addAttribute("optional", "false");
1105: }
1106:
1107: /**
1108: * Add many-to-one attributes.
1109: */
1110: private void addManyToOneAttributes(FieldMetaData fmd)
1111: throws SAXException {
1112: if (!fmd.isInDefaultFetchGroup())
1113: addAttribute("fetch", "LAZY");
1114: if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
1115: addAttribute("optional", "false");
1116: }
1117:
1118: /**
1119: * Add one-to-one attributes.
1120: */
1121: private void addOneToOneAttributes(FieldMetaData fmd)
1122: throws SAXException {
1123: if (!fmd.isInDefaultFetchGroup())
1124: addAttribute("fetch", "LAZY");
1125: if (fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION)
1126: addAttribute("optional", "false");
1127: }
1128:
1129: /**
1130: * Add one-to-many attributes.
1131: */
1132: private void addOneToManyAttributes(FieldMetaData fmd)
1133: throws SAXException {
1134: if (fmd.isInDefaultFetchGroup())
1135: addAttribute("fetch", "EAGER");
1136: addTargetEntityAttribute(fmd);
1137: }
1138:
1139: /**
1140: * Add many-to-many attributes.
1141: */
1142: private void addManyToManyAttributes(FieldMetaData fmd)
1143: throws SAXException {
1144: if (fmd.isInDefaultFetchGroup())
1145: addAttribute("fetch", "EAGER");
1146: addTargetEntityAttribute(fmd);
1147: }
1148:
1149: /**
1150: * Add a target-entity attribute to collection and map fields that do
1151: * not use generics.
1152: */
1153: private void addTargetEntityAttribute(FieldMetaData fmd)
1154: throws SAXException {
1155: Member member = fmd.getBackingMember();
1156: Class[] types;
1157: if (member instanceof Field)
1158: types = JavaVersions.getParameterizedTypes((Field) member);
1159: else if (member instanceof Method)
1160: types = JavaVersions.getParameterizedTypes((Method) member);
1161: else
1162: types = new Class[0];
1163:
1164: switch (fmd.getDeclaredTypeCode()) {
1165: case JavaTypes.COLLECTION:
1166: if (types.length != 1)
1167: addAttribute("target-entity", fmd.getElement()
1168: .getDeclaredType().getName());
1169: break;
1170: case JavaTypes.MAP:
1171: if (types.length != 2)
1172: addAttribute("target-entity", fmd.getElement()
1173: .getDeclaredType().getName());
1174: break;
1175: }
1176: }
1177:
1178: /**
1179: * Serialize field mapping content; this will be called before
1180: * {@link #serializeValueMappingContent}. Does nothing by default.
1181: */
1182: protected void serializeFieldMappingContent(FieldMetaData fmd,
1183: PersistenceStrategy strategy) throws SAXException {
1184: }
1185:
1186: /**
1187: * Set mapping attributes for strategy. Sets mapped-by by default.
1188: */
1189: protected void addStrategyMappingAttributes(FieldMetaData fmd)
1190: throws SAXException {
1191: if (fmd.getMappedBy() != null)
1192: addAttribute("mapped-by", fmd.getMappedBy());
1193: }
1194:
1195: /**
1196: * Represents ordered set of {@link SequenceMetaData}s with a
1197: * common class scope.
1198: *
1199: * @author Stephen Kim
1200: * @author Pinaki Poddar
1201: */
1202: private static class ClassSeqs implements SourceTracker,
1203: Comparable<ClassSeqs>, Comparator<SequenceMetaData> {
1204:
1205: private final SequenceMetaData[] _seqs;
1206:
1207: public ClassSeqs(List<SequenceMetaData> seqs) {
1208: if (seqs == null || seqs.isEmpty())
1209: throw new InternalException();
1210:
1211: _seqs = (SequenceMetaData[]) seqs
1212: .toArray(new SequenceMetaData[seqs.size()]);
1213: Arrays.sort(_seqs, this );
1214: }
1215:
1216: public SequenceMetaData[] getSequences() {
1217: return _seqs;
1218: }
1219:
1220: /**
1221: * Compare sequence metadata on name.
1222: */
1223: public int compare(SequenceMetaData o1, SequenceMetaData o2) {
1224: return o1.getName().compareTo(o2.getName());
1225: }
1226:
1227: public File getSourceFile() {
1228: return _seqs[0].getSourceFile();
1229: }
1230:
1231: public Object getSourceScope() {
1232: return _seqs[0].getSourceScope();
1233: }
1234:
1235: public int getSourceType() {
1236: return _seqs[0].getSourceType();
1237: }
1238:
1239: public String getResourceName() {
1240: return _seqs[0].getResourceName();
1241: }
1242:
1243: public int compareTo(ClassSeqs other) {
1244: if (other == this )
1245: return 0;
1246: if (other == null)
1247: return -1;
1248: Class scope = (Class) getSourceScope();
1249: Class oscope = (Class) other.getSourceScope();
1250: return scope.getName().compareTo(oscope.getName());
1251: }
1252: }
1253:
1254: /**
1255: * Represents ordered set of {@link QueryMetaData}s with a
1256: * common class scope.
1257: *
1258: * @author Stephen Kim
1259: * @author Pinaki Poddar
1260: */
1261: private static class ClassQueries implements SourceTracker,
1262: Comparable<ClassQueries>, Comparator<QueryMetaData> {
1263:
1264: private final QueryMetaData[] _queries;
1265:
1266: public ClassQueries(List<QueryMetaData> queries) {
1267: if (queries == null || queries.isEmpty())
1268: throw new InternalException();
1269:
1270: _queries = (QueryMetaData[]) queries
1271: .toArray(new QueryMetaData[queries.size()]);
1272: Arrays.sort(_queries, this );
1273: }
1274:
1275: public QueryMetaData[] getQueries() {
1276: return _queries;
1277: }
1278:
1279: /**
1280: * Compare query metadata. Normal queries appear before native queries.
1281: * If the given queries use same language, then their names are
1282: * compared.
1283: */
1284: public int compare(QueryMetaData o1, QueryMetaData o2) {
1285: // normal queries before native
1286: if (!StringUtils.equals(o1.getLanguage(), o2.getLanguage())) {
1287: if (QueryLanguages.LANG_SQL.equals(o1.getLanguage()))
1288: return 1;
1289: else
1290: return -1;
1291: }
1292: return o1.getName().compareTo(o2.getName());
1293: }
1294:
1295: public File getSourceFile() {
1296: return _queries[0].getSourceFile();
1297: }
1298:
1299: public Object getSourceScope() {
1300: return _queries[0].getSourceScope();
1301: }
1302:
1303: public int getSourceType() {
1304: return _queries[0].getSourceType();
1305: }
1306:
1307: public String getResourceName() {
1308: return _queries[0].getResourceName();
1309: }
1310:
1311: public int compareTo(ClassQueries other) {
1312: if (other == this )
1313: return 0;
1314: if (other == null)
1315: return -1;
1316: Class scope = (Class) getSourceScope();
1317: Class oscope = (Class) other.getSourceScope();
1318: return scope.getName().compareTo(oscope.getName());
1319: }
1320: }
1321:
1322: /**
1323: * Compares clases, sequences, and queries to order them for serialization.
1324: * Places sequences first, then classes, then queries. Sequences and
1325: * queries are ordered alphabetically by name. Classes are placed in
1326: * listing order, in inheritance order within that, and in alphabetical
1327: * order within that.
1328: *
1329: * @author Stephen Kim
1330: */
1331: protected class SerializationComparator extends
1332: MetaDataInheritanceComparator {
1333:
1334: public int compare(Object o1, Object o2) {
1335: if (o1 == o2)
1336: return 0;
1337: if (o1 == null)
1338: return 1;
1339: if (o2 == null)
1340: return -1;
1341:
1342: int t1 = type(o1);
1343: int t2 = type(o2);
1344: if (t1 != t2)
1345: return t1 - t2;
1346:
1347: switch (t1) {
1348: case TYPE_META:
1349: return compare((ClassMetaData) o1, (ClassMetaData) o2);
1350: case TYPE_QUERY:
1351: return compare((QueryMetaData) o1, (QueryMetaData) o2);
1352: case TYPE_SEQ:
1353: return compare((SequenceMetaData) o1,
1354: (SequenceMetaData) o2);
1355: case TYPE_CLASS_QUERIES:
1356: return ((Comparable) o1).compareTo(o2);
1357: case TYPE_CLASS_SEQS:
1358: return ((Comparable) o1).compareTo(o2);
1359: default:
1360: return compareUnknown(o1, o2);
1361: }
1362: }
1363:
1364: /**
1365: * Compare two unrecognized elements of the same type. Throws
1366: * exception by default.
1367: */
1368: protected int compareUnknown(Object o1, Object o2) {
1369: throw new InternalException();
1370: }
1371:
1372: /**
1373: * Compare between two class metadata.
1374: */
1375: private int compare(ClassMetaData o1, ClassMetaData o2) {
1376: int li1 = o1.getListingIndex();
1377: int li2 = o2.getListingIndex();
1378: if (li1 == -1 && li2 == -1) {
1379: MetaDataTag t1 = getEntityTag(o1);
1380: MetaDataTag t2 = getEntityTag(o2);
1381: if (t1.compareTo(t2) != 0)
1382: return t1.compareTo(t2);
1383: int inher = super .compare(o1, o2);
1384: if (inher != 0)
1385: return inher;
1386: return o1.getDescribedType().getName().compareTo(
1387: o2.getDescribedType().getName());
1388: }
1389:
1390: if (li1 == -1)
1391: return 1;
1392: if (li2 == -1)
1393: return -1;
1394: return li1 - li2;
1395: }
1396:
1397: /**
1398: * Compare query metadata.
1399: */
1400: private int compare(QueryMetaData o1, QueryMetaData o2) {
1401: // normal queries before native
1402: if (!StringUtils.equals(o1.getLanguage(), o2.getLanguage())) {
1403: if (QueryLanguages.LANG_SQL.equals(o1.getLanguage()))
1404: return 1;
1405: else
1406: return -1;
1407: }
1408: return o1.getName().compareTo(o2.getName());
1409: }
1410:
1411: /**
1412: * Compare sequence metadata.
1413: */
1414: private int compare(SequenceMetaData o1, SequenceMetaData o2) {
1415: return o1.getName().compareTo(o2.getName());
1416: }
1417: }
1418:
1419: /**
1420: * Sorts fields according to listing order, then XSD strategy order,
1421: * then name order.
1422: */
1423: private class FieldComparator implements Comparator {
1424:
1425: public int compare(Object o1, Object o2) {
1426: FieldMetaData fmd1 = (FieldMetaData) o1;
1427: FieldMetaData fmd2 = (FieldMetaData) o2;
1428: if (fmd1.isPrimaryKey()) {
1429: if (fmd2.isPrimaryKey())
1430: return fmd1.compareTo(fmd2);
1431: return -1;
1432: }
1433: if (fmd2.isPrimaryKey())
1434: return 1;
1435:
1436: if (fmd1.isVersion()) {
1437: if (fmd2.isVersion())
1438: return compareListingOrder(fmd1, fmd2);
1439: return getStrategy(fmd2) == PersistenceStrategy.BASIC ? 1
1440: : -1;
1441: }
1442: if (fmd2.isVersion())
1443: return getStrategy(fmd1) == PersistenceStrategy.BASIC ? -1
1444: : 1;
1445:
1446: int stcmp = getStrategy(fmd1).compareTo(getStrategy(fmd2));
1447: if (stcmp != 0)
1448: return stcmp;
1449: return compareListingOrder(fmd1, fmd2);
1450: }
1451:
1452: private int compareListingOrder(FieldMetaData fmd1,
1453: FieldMetaData fmd2) {
1454: int lcmp = fmd1.getListingIndex() - fmd2.getListingIndex();
1455: if (lcmp != 0)
1456: return lcmp;
1457: return fmd1.compareTo(fmd2);
1458: }
1459: }
1460: }
|