001: /**********************************************************************
002: Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015:
016: Contributors:
017: 2004 Kikuchi Kousuke - org.jpox.enhancer.conf.JDOConfigCollection
018: 2004 Erik Bengtson - add dependent elements
019: ...
020: **********************************************************************/package org.jpox.metadata;
021:
022: import java.util.List;
023: import java.util.Set;
024:
025: import org.jpox.ClassLoaderResolver;
026: import org.jpox.api.ApiAdapter;
027: import org.jpox.exceptions.ClassNotResolvedException;
028: import org.jpox.util.ClassUtils;
029: import org.jpox.util.JPOXLogger;
030: import org.jpox.util.StringUtils;
031:
032: /**
033: * Representation of the MetaData of a collection.
034: *
035: * @since 1.1
036: * @version $Revision: 1.37 $
037: */
038: public class CollectionMetaData extends ContainerMetaData {
039: /** Representation of the element of the collection. */
040: protected ContainerComponent element;
041:
042: /**
043: * Constructor to create a copy of the passed metadata using the passed parent.
044: * @param parent The parent
045: * @param colmd The metadata to copy
046: */
047: public CollectionMetaData(AbstractMemberMetaData parent,
048: CollectionMetaData colmd) {
049: super (parent);
050: element = new ContainerComponent();
051: element.embedded = colmd.element.embedded;
052: element.serialized = colmd.element.serialized;
053: element.dependent = colmd.element.dependent;
054: element.type = colmd.element.type;
055: element.classMetaData = colmd.element.classMetaData;
056: }
057:
058: /**
059: * Constructor.
060: * @param parent The parent Field element
061: * @param elementType The type of element
062: * @param embeddedElement Whether elements are embedded
063: * @param dependentElement attribute dependent-element value
064: * @param serializedElement attribute serialized-element value
065: */
066: public CollectionMetaData(AbstractMemberMetaData parent,
067: String elementType, String embeddedElement,
068: String dependentElement, String serializedElement) {
069: super (parent);
070:
071: if (!StringUtils.isWhitespace(elementType)
072: && elementType.indexOf(',') > 0) {
073: throw new InvalidMetaDataException(LOCALISER, "044131",
074: parent.getName(), parent.getClassName());
075: }
076: element = new ContainerComponent(parent
077: .getAbstractClassMetaData().getPackageName(),
078: elementType, embeddedElement, serializedElement,
079: dependentElement);
080: }
081:
082: /**
083: * Method to populate any defaults, and check the validity of the MetaData.
084: * @param clr ClassLoaderResolver to use for any loading operations
085: * @param primary the primary ClassLoader to use (or null)
086: */
087: public void populate(ClassLoaderResolver clr, ClassLoader primary) {
088: ApiAdapter api = getMetaDataManager().getApiAdapter();
089:
090: // Check the field type and see if it is castable to a Collection
091: Class field_type = getMemberMetaData().getType();
092: if (!java.util.Collection.class.isAssignableFrom(field_type)) {
093: throw new InvalidMetaDataException(LOCALISER, "044132",
094: getFieldName(), getMemberMetaData().getClassName(
095: false));
096: }
097:
098: // "element-type"
099: if (element.type == null) {
100: throw new InvalidMetaDataException(LOCALISER, "044133",
101: getFieldName(), getMemberMetaData().getClassName(
102: false));
103: }
104:
105: // Check that the key type exists
106: Class elementTypeClass = null;
107: try {
108: elementTypeClass = clr.classForName(element.type, primary);
109: } catch (ClassNotResolvedException cnre) {
110: try {
111: // Maybe the user specified a java.lang class without fully-qualifying it
112: // This is beyond the scope of the JDO spec which expects java.lang cases to be fully-qualified
113: elementTypeClass = clr
114: .classForName(ClassUtils
115: .getJavaLangClassForType(element.type),
116: primary);
117: } catch (ClassNotResolvedException cnre2) {
118: throw new InvalidMetaDataException(LOCALISER, "044134",
119: getFieldName(), getMemberMetaData()
120: .getClassName(false), element.type);
121: }
122: }
123:
124: if (!elementTypeClass.getName().equals(element.type)) {
125: // The element-type has been resolved from what was specified in the MetaData - update to the fully-qualified name
126: JPOXLogger.METADATA.info(LOCALISER.msg("044135",
127: getFieldName(), getMemberMetaData().getClassName(
128: false), element.type, elementTypeClass
129: .getName()));
130: element.type = elementTypeClass.getName();
131: }
132:
133: // "embedded-element"
134: if (element.embedded == null) {
135: // Assign default for "embedded-element" based on 18.13.1 of JDO 2 spec
136: // Note : this fails when using in the enhancer since not yet PC
137: if (getMetaDataManager().getOMFContext().getTypeManager()
138: .isDefaultEmbeddedType(elementTypeClass)) {
139: element.embedded = Boolean.TRUE;
140: } else if (api.isPersistable(elementTypeClass)
141: || Object.class.isAssignableFrom(elementTypeClass)
142: || elementTypeClass.isInterface()) {
143: element.embedded = Boolean.FALSE;
144: } else {
145: element.embedded = Boolean.TRUE;
146: }
147: }
148: if (element.embedded == Boolean.FALSE) {
149: // If the user has set a non-PC/non-Interface as not embedded, correct it since not supported.
150: // Note : this fails when using in the enhancer since not yet PC
151: if (!api.isPersistable(elementTypeClass)
152: && !elementTypeClass.isInterface()
153: && elementTypeClass != java.lang.Object.class) {
154: element.embedded = Boolean.TRUE;
155: }
156: }
157:
158: ElementMetaData elemmd = ((AbstractMemberMetaData) parent)
159: .getElementMetaData();
160: if (elemmd != null && elemmd.getEmbeddedMetaData() != null) {
161: element.embedded = Boolean.TRUE;
162: }
163:
164: if (element.dependent == Boolean.TRUE) {
165: // If the user has set a non-PC/non-reference as dependent, correct it since not valid.
166: // Note : this fails when using in the enhancer since not yet PC
167: if (!api.isPersistable(elementTypeClass)
168: && !elementTypeClass.isInterface()
169: && elementTypeClass != java.lang.Object.class) {
170: element.dependent = Boolean.FALSE;
171: }
172: }
173:
174: // Keep a reference to the MetaData for the element
175: element.classMetaData = getMemberMetaData()
176: .getAbstractClassMetaData().getMetaDataManager()
177: .getMetaDataForClassInternal(elementTypeClass, clr);
178:
179: setPopulated();
180: }
181:
182: // ------------------------------ Accessors --------------------------------
183:
184: /**
185: * Accessor for the element-type tag value.
186: * This can contain comma-separated values.
187: * @return element-type tag value
188: */
189: public String getElementType() {
190: return element.type;
191: }
192:
193: /**
194: * Accessor for the Element ClassMetaData
195: * @return element ClassMetaData
196: */
197: public AbstractClassMetaData getElementClassMetaData() {
198: if (element.classMetaData != null
199: && !element.classMetaData.isInitialised()) {
200: element.classMetaData.initialise();
201: }
202: return element.classMetaData;
203: }
204:
205: /**
206: * Accessor for the embedded-element tag value
207: * @return embedded-element tag value
208: */
209: public boolean isEmbeddedElement() {
210: if (element.embedded == null) {
211: return false;
212: } else {
213: return element.embedded.booleanValue();
214: }
215: }
216:
217: /**
218: * Accessor for The dependent-element attribute indicates that the
219: * collection's element contains a reference that is to be deleted if the
220: * referring instance is deleted.
221: *
222: * @return dependent-element tag value
223: */
224: public boolean isDependentElement() {
225: if (element.dependent == null) {
226: return false;
227: } else if (element.classMetaData == null) {
228: return false;
229: } else {
230: return element.dependent.booleanValue();
231: }
232: }
233:
234: /**
235: * Accessor for the serialized-element tag value
236: * @return serialized-element tag value
237: */
238: public boolean isSerializedElement() {
239: if (element.serialized == null) {
240: return false;
241: } else {
242: return element.serialized.booleanValue();
243: }
244: }
245:
246: // ------------------------------- Utilities -------------------------------
247:
248: /**
249: * Accessor for all ClassMetaData referenced by this array.
250: * @param orderedCMDs List of ordered ClassMetaData objects (added to).
251: * @param referencedCMDs Set of all ClassMetaData objects (added to).
252: * @param dba_vendor_id Vendor ID of the DBA. Used for view addition.
253: * @param clr the ClassLoaderResolver
254: **/
255: void getReferencedClassMetaData(final List orderedCMDs,
256: final Set referencedCMDs, final String dba_vendor_id,
257: final ClassLoaderResolver clr) {
258: AbstractClassMetaData element_cmd = getMetaDataManager()
259: .getMetaDataForClass(element.type, clr);
260: if (element_cmd != null) {
261: element_cmd.getReferencedClassMetaData(orderedCMDs,
262: referencedCMDs, dba_vendor_id, clr);
263: }
264: }
265:
266: /**
267: * Returns a string representation of the object.
268: * @param prefix prefix string
269: * @param indent indent string
270: * @return a string representation of the object.
271: */
272: public String toString(String prefix, String indent) {
273: StringBuffer sb = new StringBuffer();
274: sb.append(prefix).append("<collection element-type=\"").append(
275: element.type).append("\"");
276: if (element.embedded != null) {
277: sb.append(" embedded-element=\"").append(element.embedded)
278: .append("\"");
279: }
280: if (element.dependent != null) {
281: sb.append(" dependent-element=\"")
282: .append(element.dependent).append("\"");
283: }
284: if (element.serialized != null) {
285: sb.append(" serialized-element=\"").append(
286: element.serialized).append("\"");
287: }
288: sb.append(">\n");
289:
290: // Add extensions
291: sb.append(super .toString(prefix + indent, indent));
292:
293: sb.append(prefix).append("</collection>\n");
294: return sb.toString();
295: }
296: }
|