001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.meta;
020:
021: import org.apache.openjpa.lib.util.Localizer;
022: import org.apache.openjpa.util.MetaDataException;
023: import org.apache.openjpa.util.UserException;
024:
025: /**
026: * Default {@link ValueMetaData} implementation.
027: *
028: * @author Abe White
029: * @nojavadoc
030: */
031: public class ValueMetaDataImpl implements ValueMetaData {
032:
033: private static final Localizer _loc = Localizer
034: .forPackage(ValueMetaDataImpl.class);
035:
036: ///////////////////////////////////////////////////////////////
037: // Note: if you add additional state that should be copied to
038: // embedded metadata, make sure to add it to the copy() method
039: ///////////////////////////////////////////////////////////////
040:
041: private FieldMetaData _owner;
042: private Class _decType = Object.class;
043: private int _decCode = JavaTypes.OBJECT;
044: private ClassMetaData _decTypeMeta = null;
045: private Class _type = null;
046: private int _code = JavaTypes.OBJECT;
047: private ClassMetaData _typeMeta = null;
048: private Class _typeOverride = null;
049: private int _delete = CASCADE_NONE;
050: private int _persist = CASCADE_AUTO;
051: private int _attach = CASCADE_IMMEDIATE;
052: private int _refresh = CASCADE_AUTO;
053: private boolean _serialized = false;
054: private Boolean _embedded = null;
055: private ClassMetaData _embeddedMeta = null;
056: private int _resMode = MODE_NONE;
057: private String _mappedBy = null;
058: private FieldMetaData _mappedByMeta = null;
059:
060: protected ValueMetaDataImpl(FieldMetaData owner) {
061: _owner = owner;
062: }
063:
064: /**
065: * Constructor for serialization.
066: */
067: protected ValueMetaDataImpl() {
068: }
069:
070: public FieldMetaData getFieldMetaData() {
071: return _owner;
072: }
073:
074: public MetaDataRepository getRepository() {
075: return _owner.getRepository();
076: }
077:
078: public Class getType() {
079: return (_type == null) ? _decType : _type;
080: }
081:
082: public void setType(Class type) {
083: _type = type;
084: _typeMeta = null;
085: if (type != null)
086: setTypeCode(JavaTypes.getTypeCode(type));
087: }
088:
089: public int getTypeCode() {
090: return (_type == null) ? _decCode : _code;
091: }
092:
093: public void setTypeCode(int code) {
094: _code = code;
095: }
096:
097: public boolean isTypePC() {
098: return getTypeCode() == JavaTypes.PC
099: || getTypeCode() == JavaTypes.PC_UNTYPED;
100: }
101:
102: public ClassMetaData getTypeMetaData() {
103: if (_type == null)
104: return getDeclaredTypeMetaData();
105: if (_typeMeta == null && _code == JavaTypes.PC) {
106: ClassMetaData meta = _owner.getDefiningMetaData();
107: _typeMeta = meta.getRepository().getMetaData(_type,
108: meta.getEnvClassLoader(), true);
109: }
110: return _typeMeta;
111: }
112:
113: public Class getDeclaredType() {
114: return _decType;
115: }
116:
117: public void setDeclaredType(Class type) {
118: _decType = type;
119: _decTypeMeta = null;
120: _decCode = JavaTypes.getTypeCode(type);
121: if (_embeddedMeta != null)
122: _embeddedMeta.setDescribedType(type);
123: }
124:
125: public int getDeclaredTypeCode() {
126: return _decCode;
127: }
128:
129: public void setDeclaredTypeCode(int code) {
130: _decCode = code;
131: }
132:
133: public boolean isDeclaredTypePC() {
134: return _decCode == JavaTypes.PC
135: || _decCode == JavaTypes.PC_UNTYPED;
136: }
137:
138: public ClassMetaData getDeclaredTypeMetaData() {
139: if (_decTypeMeta == null && _decCode == JavaTypes.PC) {
140: if (isEmbedded())
141: _decTypeMeta = getEmbeddedMetaData();
142: else {
143: ClassMetaData meta = _owner.getDefiningMetaData();
144: _decTypeMeta = meta.getRepository().getMetaData(
145: _decType, meta.getEnvClassLoader(), true);
146: }
147: }
148: return _decTypeMeta;
149: }
150:
151: public boolean isEmbedded() {
152: if (_owner.getManagement() != _owner.MANAGE_PERSISTENT)
153: return false;
154: if (_embedded == null) {
155: // field left as default; embedded setting depends on type
156: switch (_decCode) {
157: case JavaTypes.PC:
158: case JavaTypes.COLLECTION:
159: case JavaTypes.MAP:
160: case JavaTypes.PC_UNTYPED:
161: _embedded = Boolean.FALSE;
162: break;
163: default:
164: _embedded = Boolean.TRUE;
165: }
166: }
167: return _embedded.booleanValue();
168: }
169:
170: public void setEmbedded(boolean embedded) {
171: if (embedded && _embedded != Boolean.TRUE) {
172: _decTypeMeta = null;
173: _typeMeta = null;
174: }
175: _embedded = (embedded) ? Boolean.TRUE : Boolean.FALSE;
176: }
177:
178: public boolean isEmbeddedPC() {
179: return _decCode == JavaTypes.PC && isEmbedded();
180: }
181:
182: public ClassMetaData getEmbeddedMetaData() {
183: if (_embeddedMeta == null && isEmbeddedPC())
184: addEmbeddedMetaData();
185: return _embeddedMeta;
186: }
187:
188: public ClassMetaData addEmbeddedMetaData() {
189: MetaDataRepository repos = _owner.getRepository();
190: _embeddedMeta = repos.newEmbeddedClassMetaData(this );
191: _embeddedMeta.setDescribedType(_decType);
192: repos.getMetaDataFactory().getDefaults().populate(
193: _embeddedMeta, ClassMetaData.ACCESS_UNKNOWN);
194:
195: setEmbedded(true);
196: return _embeddedMeta;
197: }
198:
199: public int getCascadeDelete() {
200: if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
201: return CASCADE_NONE;
202: if (isEmbeddedPC())
203: return CASCADE_IMMEDIATE;
204:
205: switch (_delete) {
206: case CASCADE_NONE:
207: // if the user marks the owning field dependent and we
208: // externalize to a pc type, then become dependent
209: if (this != _owner.getValue()
210: && isTypePC()
211: && ((ValueMetaDataImpl) _owner.getValue())._delete == CASCADE_AUTO)
212: return CASCADE_AUTO;
213: break;
214: case CASCADE_AUTO:
215: if (isTypePC())
216: return CASCADE_AUTO;
217: break;
218: case CASCADE_IMMEDIATE:
219: if (isDeclaredTypePC())
220: return CASCADE_IMMEDIATE;
221: break;
222: }
223: return CASCADE_NONE;
224: }
225:
226: public void setCascadeDelete(int delete) {
227: _delete = delete;
228: }
229:
230: public int getCascadePersist() {
231: if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT)
232: return CASCADE_NONE;
233: if (isDeclaredTypePC())
234: return _persist;
235: if (!isTypePC())
236: return CASCADE_NONE;
237: // if only externalized type is pc, can't cascade immediate
238: return (_persist == CASCADE_IMMEDIATE) ? CASCADE_AUTO
239: : _persist;
240: }
241:
242: public void setCascadePersist(int persist) {
243: _persist = persist;
244: }
245:
246: public int getCascadeAttach() {
247: if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT
248: || !isDeclaredTypePC()) // attach acts on declared type
249: return CASCADE_NONE;
250: if (isEmbeddedPC())
251: return CASCADE_IMMEDIATE;
252: return _attach;
253: }
254:
255: public void setCascadeAttach(int attach) {
256: if (attach == CASCADE_AUTO)
257: throw new IllegalArgumentException("CASCADE_AUTO");
258: _attach = attach;
259: }
260:
261: public int getCascadeRefresh() {
262: if (_owner.getManagement() != FieldMetaData.MANAGE_PERSISTENT
263: || !isDeclaredTypePC()) // refresh acts on declared type
264: return CASCADE_NONE;
265: return _refresh;
266: }
267:
268: public void setCascadeRefresh(int refresh) {
269: _refresh = refresh;
270: }
271:
272: public boolean isSerialized() {
273: return _serialized;
274: }
275:
276: public void setSerialized(boolean serialized) {
277: _serialized = serialized;
278: }
279:
280: public String getValueMappedBy() {
281: if (_mappedBy == MAPPED_BY_PK) {
282: // use this instead of getting meta from element b/c that
283: // requires element to be resolved
284: ClassMetaData meta = getRepository().getMetaData(
285: _owner.getElement().getType(), null, false);
286: if (meta == null)
287: throw new MetaDataException(_loc.get("val-not-pc",
288: _owner));
289: if (meta.getPrimaryKeyFields().length != 1)
290: throw new MetaDataException(_loc.get("val-not-one-pk",
291: _owner));
292: _mappedByMeta = meta.getPrimaryKeyFields()[0];
293: _mappedBy = _mappedByMeta.getName();
294: }
295: return _mappedBy;
296: }
297:
298: public void setValueMappedBy(String mapped) {
299: if (_owner.getKey() != this && mapped != null)
300: throw new UserException(_loc.get("mapped-by-not-key", this ));
301: else {
302: _mappedBy = mapped;
303: _mappedByMeta = null;
304: }
305: }
306:
307: public FieldMetaData getValueMappedByMetaData() {
308: if (getValueMappedBy() != null && _mappedByMeta == null) {
309: ClassMetaData meta = _owner.getElement().getTypeMetaData();
310: FieldMetaData field = (meta == null) ? null : meta
311: .getField(getValueMappedBy());
312: if (field == null)
313: throw new MetaDataException(_loc.get("no-mapped-by",
314: this , getValueMappedBy()));
315: if (field.getMappedBy() != null)
316: throw new MetaDataException(_loc.get("circ-mapped-by",
317: this , getValueMappedBy()));
318: _mappedByMeta = field;
319: }
320: return _mappedByMeta;
321: }
322:
323: public Class getTypeOverride() {
324: return _typeOverride;
325: }
326:
327: public void setTypeOverride(Class val) {
328: _typeOverride = val;
329: }
330:
331: public String toString() {
332: String ret = _owner.getFullName(true);
333: if (this == _owner.getKey())
334: return ret + "<key:" + _decType + ">";
335: if (this == _owner.getElement()) {
336: if (_owner.getTypeCode() == JavaTypes.MAP)
337: return ret + "<value:" + _decType + ">";
338: return ret + "<element:" + _decType + ">";
339: }
340: return ret + "<" + _decType + ">";
341: }
342:
343: ////////////////////////
344: // Resolve and validate
345: ////////////////////////
346:
347: public int getResolve() {
348: return _resMode;
349: }
350:
351: public void setResolve(int mode) {
352: _resMode = mode;
353: }
354:
355: public void setResolve(int mode, boolean on) {
356: if (mode == MODE_NONE)
357: _resMode = mode;
358: else if (on)
359: _resMode |= mode;
360: else
361: _resMode &= ~mode;
362: }
363:
364: public boolean resolve(int mode) {
365: if ((_resMode & mode) == mode)
366: return true;
367: int cur = _resMode;
368: _resMode |= mode;
369:
370: // we only perform actions for meta mode
371: if ((mode & MODE_META) == 0 || (cur & MODE_META) != 0)
372: return false;
373:
374: // check for type extension
375: int codeOverride = JavaTypes.OBJECT;
376: if (_typeOverride != null) {
377: codeOverride = JavaTypes.getTypeCode(_typeOverride);
378:
379: // if there is no externalizer method or this value is a key or
380: // element, set our type to the type extension; otherwise, use the
381: // type extension as a hint to the actual type of the declared
382: // value (e.g. marking an interface as non-pc)
383: if (_owner.getExternalizerMethod() == null
384: || _owner.getValue() != this ) {
385: _type = _typeOverride;
386: _code = codeOverride;
387: } else {
388: _decCode = codeOverride;
389: if (JavaTypes.maybePC(codeOverride, _typeOverride))
390: resolveDeclaredType(_typeOverride);
391: }
392: }
393:
394: // see if actual type is pc
395: if (JavaTypes.maybePC(_code, _type)) {
396: _typeMeta = _owner.getRepository().getMetaData(_type,
397: _owner.getDefiningMetaData().getEnvClassLoader(),
398: false);
399: if (_typeMeta != null)
400: _code = JavaTypes.PC;
401: }
402:
403: // if there is no externalizer, set our declared type code to the
404: // actual type so that we treat the value correctly at runtime
405: // (pers by reach, etc)
406: if (_typeOverride != null
407: && _owner.getExternalizerMethod() == null
408: && _owner.getExternalValues() == null) {
409: // cache the metadata immediately since we won't be able to get
410: // it lazily, since we're not resetting _decType to _type
411: _decCode = _code;
412: _decTypeMeta = _typeMeta;
413: } else if (JavaTypes.maybePC(_decCode, _decType))
414: resolveDeclaredType(_decType);
415:
416: // resolves mapped by
417: getValueMappedBy();
418:
419: ClassMetaData embed = getEmbeddedMetaData();
420: if (embed != null)
421: embed.resolve(MODE_META);
422:
423: // oid as primary key field?
424: if (_decCode == JavaTypes.PC && isEmbedded()
425: && _owner.isPrimaryKey() && _owner.getValue() == this )
426: _code = _decCode = JavaTypes.OID;
427:
428: return false;
429: }
430:
431: /**
432: * Resolve the declared type.
433: */
434: private void resolveDeclaredType(Class type) {
435: ClassMetaData meta = _owner.getRepository()
436: .getMetaData(
437: type,
438: _owner.getDefiningMetaData()
439: .getEnvClassLoader(), false);
440: if (meta != null)
441: _decCode = JavaTypes.PC;
442: if (!isEmbedded())
443: _decTypeMeta = meta;
444: }
445:
446: public void copy(ValueMetaData vmd) {
447: // copy declared types, but if OID revert to PC until we resolve
448: // to OID ourselves
449: _decType = vmd.getDeclaredType();
450: _decCode = vmd.getDeclaredTypeCode();
451: if (_decCode == JavaTypes.OID)
452: _decCode = JavaTypes.PC;
453:
454: _delete = vmd.getCascadeDelete();
455: _persist = vmd.getCascadePersist();
456: _attach = vmd.getCascadeAttach();
457: _refresh = vmd.getCascadeRefresh();
458: _typeOverride = vmd.getTypeOverride();
459: _serialized = vmd.isSerialized();
460: if (_embeddedMeta != null)
461: _embeddedMeta.setDescribedType(vmd.getDeclaredType());
462:
463: // don't allow copy to override embedded
464: if (_embedded == null)
465: setEmbedded(vmd.isEmbedded());
466: }
467: }
|