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