001: package org.apache.ojb.broker.metadata;
002:
003: /* Copyright 2003-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.util.List;
019: import java.util.Map;
020: import java.util.HashMap;
021:
022: import org.apache.commons.lang.SystemUtils;
023: import org.apache.ojb.broker.metadata.fieldaccess.AnonymousPersistentField;
024: import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
025: import org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldFactory;
026: import org.apache.ojb.broker.util.ClassHelper;
027: import org.apache.ojb.broker.util.logging.Logger;
028: import org.apache.ojb.broker.util.logging.LoggerFactory;
029:
030: /**
031: * This class handle inheritance as 1-1 association based on a anonymous field
032: * (no field in persistent object needed).
033: *
034: * @version $Id: SuperReferenceDescriptor.java,v 1.1.2.6 2005/12/21 22:26:10 tomdz Exp $
035: */
036: public class SuperReferenceDescriptor extends ObjectReferenceDescriptor {
037: private transient Logger log;
038:
039: public static final String SUPER_FIELD_INTERNAL_NAME = "ojbSuperFieldInternal";
040: public static final String SUPER_FIELD_NAME = RepositoryElements.TAG_SUPER;
041:
042: private Boolean javaInheritance;
043: private Map declaredInheritanceFields = new HashMap();
044:
045: public SuperReferenceDescriptor(ClassDescriptor descriptor) {
046: super (descriptor);
047: // most important call, create new specific field for inheritance
048: super .setPersistentField(new SuperReferenceField(this ));
049: // needed immutable settings
050: super .setLazy(false);
051: super .setCascadeRetrieve(true);
052: super .setCascadingStore(CASCADE_OBJECT);
053: super .setCascadingDelete(CASCADE_OBJECT);
054: }
055:
056: public boolean isSuperReferenceDescriptor() {
057: return true;
058: }
059:
060: public void setItemClass(Class c) {
061: super .setItemClass(c);
062: getClassDescriptor().setBaseClass(c.getName());
063: }
064:
065: /**
066: * Noop, a specific {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} is
067: * used internal - {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor.SuperReferenceField}.
068: */
069: public void setPersistentField(Class c, String fieldname) {
070: // noop
071: }
072:
073: /**
074: * Noop, a specific {@link org.apache.ojb.broker.metadata.fieldaccess.PersistentField} is
075: * used internal - {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor.SuperReferenceField}.
076: */
077: public void setPersistentField(PersistentField pf) {
078: // noop
079: }
080:
081: public void setLazy(boolean lazy) {
082: getLog()
083: .info(
084: "Not allowed to change this property, will ignore setting");
085: }
086:
087: public void setCascadeRetrieve(boolean b) {
088: getLog()
089: .info(
090: "Not allowed to change this property, will ignore setting");
091: }
092:
093: public void setCascadingStore(int cascade) {
094: getLog()
095: .info(
096: "Not allowed to change this property, will ignore setting");
097: }
098:
099: public void setCascadingStore(String value) {
100: getLog()
101: .info(
102: "Not allowed to change this property, will ignore setting");
103: }
104:
105: public void setCascadingDelete(int cascade) {
106: getLog()
107: .info(
108: "Not allowed to change this property, will ignore setting");
109: }
110:
111: public void setCascadingDelete(String value) {
112: getLog()
113: .info(
114: "Not allowed to change this property, will ignore setting");
115: }
116:
117: public void setCascadeStore(boolean cascade) {
118: getLog()
119: .info(
120: "Not allowed to change this property, will ignore setting");
121: }
122:
123: public void setCascadeDelete(boolean cascade) {
124: getLog()
125: .info(
126: "Not allowed to change this property, will ignore setting");
127: }
128:
129: public SuperReferenceField getInheritanceField() {
130: return (SuperReferenceField) getPersistentField();
131: }
132:
133: /**
134: * If this method returns <em>true</em> the inheritance described by this object
135: * is a <em>normal</em> JAVA inheritance. If <em>false</em> the inheritance is only declared
136: * in the O/R mapping it's a <em>declarative inheritance</em>, the referenced "super class" in <strong>not</strong>
137: * a JAVA super class of the main class.
138: */
139: public boolean isJavaInheritance() {
140: if (javaInheritance == null) {
141: javaInheritance = getClassDescriptor()
142: .getSuperClassDescriptor().getClassOfObject()
143: .isAssignableFrom(
144: getClassDescriptor().getClassOfObject()) ? Boolean.TRUE
145: : Boolean.FALSE;
146: }
147: return javaInheritance.booleanValue();
148: }
149:
150: synchronized PersistentField getDeclaredInheritanceField(
151: Class target, String name) {
152: Map fields = (HashMap) declaredInheritanceFields.get(target);
153: if (fields == null) {
154: fields = new HashMap();
155: declaredInheritanceFields.put(target, fields);
156: }
157: PersistentField pf = (PersistentField) fields.get(name);
158: if (pf == null) {
159: pf = PersistentFieldFactory.createPersistentField(target,
160: name);
161: // System.out.println("## tmp field: " + target + ", name: " + name + ", field: " + pf);
162: fields.put(name, pf);
163: }
164: return pf;
165: }
166:
167: private Logger getLog() {
168: if (log == null) {
169: log = LoggerFactory.getLogger(SuperReferenceField.class);
170: }
171: return log;
172: }
173:
174: //====================================================
175: // inner class
176: //====================================================
177:
178: public static final class SuperReferenceField extends
179: AnonymousPersistentField {
180: private transient Logger log;
181:
182: private SuperReferenceDescriptor super Ref;
183:
184: public SuperReferenceField(SuperReferenceDescriptor super Ref) {
185: super (SUPER_FIELD_INTERNAL_NAME);
186: this .super Ref = super Ref;
187: }
188:
189: private Logger getLog() {
190: if (log == null) {
191: log = LoggerFactory
192: .getLogger(SuperReferenceField.class);
193: }
194: return log;
195: }
196:
197: /**
198: * Field values of 'value' (base object) are copied to 'obj' (derived object)
199: * then obj is saved in a map
200: *
201: * @param target - the base object instance
202: * @param value - the derived object instance
203: * @throws MetadataException
204: */
205: public synchronized void set(Object target, Object value)
206: throws MetadataException {
207: // System.out.println("target: " + target + " value: " + value);
208: ClassDescriptor super Cld = super Ref.getClassDescriptor()
209: .getSuperClassDescriptor();
210: if (super Ref.isJavaInheritance()) {
211: copyFields(super Cld, target, super Cld, value, true,
212: true);
213: } else {
214: copyFields(super Ref.getClassDescriptor(), target,
215: super Cld, value, false, false);
216: }
217: }
218:
219: /**
220: * Field values of specified 'obj' (the derived object) are copied to
221: * 'value' (base object) then value is returned as a referenced object.
222: * If the base object is the super class of the specified 'obj', then
223: * return the specified object.
224: * Else a base class instance will be created at runtime and the field values
225: * from the derived object are copied to the base class object.
226: *
227: * @param obj - the base object instance
228: * @throws MetadataException
229: */
230: public synchronized Object get(Object obj)
231: throws MetadataException {
232: if (obj == null)
233: return null;
234: if (super Ref.isJavaInheritance()) {
235: return obj;
236: } else {
237: return getObjectWithDeclaredSuperClass(obj);
238: }
239: }
240:
241: private Object getObjectWithDeclaredSuperClass(Object obj) {
242: Object value = getFromFieldCache(obj);
243: if (value == null) {
244: ClassDescriptor baseCld = null;
245: try {
246: baseCld = super Ref.getClassDescriptor()
247: .getSuperClassDescriptor();
248: value = ClassHelper.buildNewObjectInstance(baseCld);
249: } catch (Exception e) {
250: throw new MetadataException(
251: "Can't create new base class object for '"
252: + (baseCld != null ? baseCld
253: .getClassNameOfObject()
254: : null) + "'", e);
255: }
256: copyFields(baseCld, value, super Ref
257: .getClassDescriptor(), obj, true, false);
258: putToFieldCache(obj, value);
259: }
260: return value;
261: }
262:
263: void copyFields(ClassDescriptor targetCld, Object target,
264: ClassDescriptor sourceCld, Object source,
265: boolean targetIsSuper, boolean javaInheritance) {
266: if (getLog().isDebugEnabled()) {
267: String msg = ("Copy fields from "
268: + SystemUtils.LINE_SEPARATOR
269: + "source object '"
270: + (source != null ? source.getClass().getName()
271: : null)
272: + "'"
273: + SystemUtils.LINE_SEPARATOR
274: + "using source fields declared in '"
275: + sourceCld.getClassNameOfObject()
276: + "'"
277: + SystemUtils.LINE_SEPARATOR
278: + "to target object '"
279: + (target != null ? target.getClass().getName()
280: : null)
281: + "'"
282: + SystemUtils.LINE_SEPARATOR
283: + "using target fields declared in '"
284: + targetCld.getClassNameOfObject()
285: + "'"
286: + SystemUtils.LINE_SEPARATOR
287: + "the fields to copy are declared in '"
288: + (targetIsSuper ? targetCld
289: .getClassNameOfObject() : sourceCld
290: .getClassNameOfObject())
291: + "' class"
292: + SystemUtils.LINE_SEPARATOR
293: + "the used classes are associated by java inheritance: "
294: + javaInheritance + SystemUtils.LINE_SEPARATOR);
295: getLog().debug(msg);
296: }
297: /*
298: arminw:
299: If the target object is a super object of the source object, iterate all target object fields.
300: If the source object is a super object of the target object, iterate all source object fields
301:
302: If java inheritance is used (target is super class of source or vice versa) we can use the same
303: FieldDescriptor to copy the fields.
304: If only a "declarative inheritance" is used (no class inheritance, only identical field names of the super class)
305: we have to use the associated FieldDescriptor of target and source ClassDescriptor
306: */
307: FieldDescriptor[] fields = targetIsSuper ? targetCld
308: .getFieldDescriptions() : sourceCld
309: .getFieldDescriptions();
310: for (int i = 0; i < fields.length; i++) {
311: FieldDescriptor field = fields[i];
312: if (!field.isAnonymous()) {
313: performFieldCopy(target, targetCld, source,
314: sourceCld, field.getPersistentField(),
315: targetIsSuper, javaInheritance);
316: }
317: }
318: List refs = targetIsSuper ? targetCld
319: .getCollectionDescriptors() : sourceCld
320: .getCollectionDescriptors();
321: for (int i = 0; i < refs.size(); i++) {
322: CollectionDescriptor col = (CollectionDescriptor) refs
323: .get(i);
324: PersistentField pf = col.getPersistentField();
325: performFieldCopy(target, targetCld, source, sourceCld,
326: pf, targetIsSuper, javaInheritance);
327: }
328:
329: refs = targetIsSuper ? targetCld
330: .getObjectReferenceDescriptors() : sourceCld
331: .getObjectReferenceDescriptors();
332: for (int i = 0; i < refs.size(); i++) {
333: ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) refs
334: .get(i);
335: PersistentField pf = ord.getPersistentField();
336: performFieldCopy(target, targetCld, source, sourceCld,
337: pf, targetIsSuper, javaInheritance);
338: }
339: }
340:
341: private void performFieldCopy(Object target,
342: ClassDescriptor targetCld, Object source,
343: ClassDescriptor sourceCld, PersistentField pf,
344: boolean targetIsSuper, boolean javaInheritance) {
345: if (javaInheritance) {
346: pf.set(target, pf.get(source));
347: } else {
348: if (targetIsSuper) {
349: if (pf instanceof SuperReferenceField) {
350: log
351: .error("Declared inheritance doesn't support nested super references, target '"
352: + targetCld
353: .getClassNameOfObject()
354: + "' has super reference");
355: } else {
356: PersistentField tmp = super Ref
357: .getDeclaredInheritanceField(sourceCld
358: .getClassOfObject(), pf
359: .getName());
360: pf.set(target, tmp.get(source));
361: }
362: } else {
363: PersistentField tmp = superRef
364: .getDeclaredInheritanceField(targetCld
365: .getClassOfObject(), pf.getName());
366: tmp.set(target, pf.get(source));
367: }
368: }
369: }
370: }
371: }
|