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