1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.impl.enhancer.meta.model;
19
20 import java.io.IOException;
21 import java.io.PrintWriter;
22 import java.io.File;
23
24 import java.util.List;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27
28 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
29 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
30 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
31 import org.apache.jdo.impl.enhancer.meta.util.EnhancerMetaDataBaseModel;
32 import org.apache.jdo.impl.enhancer.util.CombinedResourceLocator;
33 import org.apache.jdo.impl.enhancer.util.ListResourceLocator;
34 import org.apache.jdo.impl.enhancer.util.PathResourceLocator;
35 import org.apache.jdo.impl.enhancer.util.ResourceLocator;
36 import org.apache.jdo.impl.model.jdo.caching.JDOModelFactoryImplCaching;
37 import org.apache.jdo.impl.model.jdo.util.TypeSupport;
38 import org.apache.jdo.model.ModelException;
39 import org.apache.jdo.model.ModelFatalException;
40 import org.apache.jdo.model.java.JavaField;
41 import org.apache.jdo.model.java.JavaModel;
42 import org.apache.jdo.model.java.JavaType;
43 import org.apache.jdo.model.jdo.JDOClass;
44 import org.apache.jdo.model.jdo.JDOField;
45 import org.apache.jdo.model.jdo.JDOModel;
46 import org.apache.jdo.model.jdo.JDOModelFactory;
47 import org.apache.jdo.model.jdo.PersistenceModifier;
48
49 /***
50 * Provides the JDO meta information based on a JDO meta model.
51 */
52 public class EnhancerMetaDataJDOModelImpl
53 extends EnhancerMetaDataBaseModel
54 implements EnhancerMetaData
55 {
56 /***
57 * The jdoModel instance.
58 */
59 private final JDOModel jdoModel;
60
61 /***
62 * The model instance.
63 */
64 private final EnhancerJavaModel javaModel;
65
66 /***
67 * The JavaType representation for java.io.Serializable.
68 */
69 private final JavaType serializableJavaType;
70
71 /***
72 * Creates an instance.
73 */
74 public EnhancerMetaDataJDOModelImpl(PrintWriter out,
75 boolean verbose,
76 List jdoFileNames,
77 List jarFileNames,
78 String sourcePath)
79 throws EnhancerMetaDataFatalError
80 {
81 super(out, verbose);
82
83 try {
84 final List locators = new ArrayList();
85 ClassLoader classLoader = null;
86
87
88 if (jdoFileNames != null && !jdoFileNames.isEmpty()) {
89 final StringBuffer s = new StringBuffer();
90 for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
91 s.append(" " + i.next());
92 }
93 final ResourceLocator jdos
94 = new ListResourceLocator(out, verbose, jdoFileNames);
95
96
97 locators.add(jdos);
98 }
99
100
101 if (jarFileNames != null && !jarFileNames.isEmpty()) {
102 final StringBuffer s = new StringBuffer();
103 final Iterator i = jarFileNames.iterator();
104 s.append(i.next());
105 while (i.hasNext()) {
106 s.append(File.pathSeparator + i.next());
107 }
108 final PathResourceLocator jars
109 = new PathResourceLocator(out, verbose, s.toString());
110
111
112 locators.add(jars);
113 classLoader = jars.getClassLoader();
114 }
115
116
117 if (sourcePath != null && sourcePath.length() > 0) {
118 final PathResourceLocator path
119 = new PathResourceLocator(out, verbose, sourcePath);
120
121
122 locators.add(path);
123 classLoader = path.getClassLoader();
124 }
125
126 if (classLoader == null) {
127
128
129 classLoader = EnhancerMetaDataJDOModelImpl.class.getClassLoader();
130 }
131
132
133 if (locators.isEmpty()) {
134 printWarning(getI18N("enhancer.metadata.using_no_metadata"));
135 }
136
137
138 final ResourceLocator locator
139 = new CombinedResourceLocator(out, verbose, locators);
140
141
142
143
144 javaModel = new EnhancerJavaModel(classLoader, locator);
145 final JDOModelFactory factory = JDOModelFactoryImplCaching.getInstance();
146 affirm(factory != null);
147 jdoModel = factory.getJDOModel(javaModel);
148 affirm(jdoModel != null);
149 javaModel.setJDOModel(jdoModel);
150 serializableJavaType = javaModel.getJavaType("java.io.Serializable");
151 } catch (IOException ex) {
152 final String msg
153 = getI18N("enhancer.metadata.io_error", ex.getMessage());
154 throw new EnhancerMetaDataFatalError(msg, ex);
155 } catch (ModelFatalException ex) {
156 final String msg
157 = getI18N("enhancer.metadata.jdomodel_error", ex.getMessage());
158 throw new EnhancerMetaDataFatalError(msg, ex);
159 } catch (ModelException ex) {
160 final String msg
161 = getI18N("enhancer.metadata.jdomodel_error", ex.getMessage());
162 throw new EnhancerMetaDataFatalError(msg, ex);
163 }
164 }
165
166
167
168 private JDOClass getJDOClass(String classPath)
169 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
170 {
171 final String className = classPath.replace('/', '.');
172 final JDOClass clazz = jdoModel.getJDOClass(className);
173 return clazz;
174 }
175
176 private JDOField getJDOField(String classPath,
177 String fieldName)
178 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
179 {
180 final JDOClass clazz = getJDOClass(classPath);
181 if (clazz == null) {
182 return null;
183 }
184 final JDOField field = clazz.getDeclaredField(fieldName);
185 affirm(field == null || field.getDeclaringClass() == clazz,
186 "field not declared in class: " + classPath + "." + fieldName);
187 return field;
188 }
189
190 private boolean hasFieldModifier(String classPath,
191 String fieldName,
192 int fieldModifier)
193 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
194 {
195 final JDOField field = getJDOField(classPath, fieldName);
196 if (field == null) {
197 return false;
198 }
199 final int pm = field.getPersistenceModifier();
200 affirm(pm != PersistenceModifier.UNSPECIFIED,
201 "field modifier 'UNSPECIFIED': " + classPath + "." + fieldName);
202 return (pm & fieldModifier) != 0;
203 }
204
205
206
207
208 /***
209 * Returns the JVM-qualified name of the specified field's declaring
210 * class. The method first checks whether the class of the specified
211 * classPath (the JVM-qualified name) declares such a field. If yes,
212 * classPath is returned. Otherwise, it checks its superclasses. The
213 * method returns <code>null</code> for an unkown field.
214 * @param classPath the non-null JVM-qualified name of the class
215 * @param fieldName the non-null name of the field
216 * @return the JVM-qualified name of the declararing class of the
217 * field, or <code>null</code> if there is no such field.
218 */
219 public String getDeclaringClass(String classPath, String fieldName)
220 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
221 {
222 affirm(classPath);
223 affirm(fieldName);
224 final String className = classPath.replace('/', '.');
225 try {
226 final JavaType javaType = javaModel.getJavaType(className);
227 final JavaField javaField = javaType.getJavaField(fieldName);
228 final JavaType declaringClass = javaField.getDeclaringClass();
229 return declaringClass.getName().replace('.', '/');
230 } catch (ModelFatalException ex) {
231 throw new EnhancerMetaDataUserException(ex);
232 }
233 }
234
235 /***
236 * Declares a field to the JDO model passing its type information.
237 * @see declareField(String, String, String)
238 */
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 /***
271 * Declares a field to the JDO model passing its type information.
272 */
273 public void declareField(String classPath,
274 String fieldName,
275 String fieldSig)
276 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
277 {
278 affirm(classPath);
279 affirm(fieldName);
280 try {
281 final JDOClass clazz = getJDOClass(classPath);
282 JavaType javaClass = clazz.getJavaType();
283 affirm(javaClass != null,
284 "cannot find class file for class: " + classPath);
285 JavaField javaField = javaClass.getJavaField(fieldName);
286 affirm(javaField != null,
287 "cannot find java field " + classPath + "." + fieldName);
288 JavaType fieldType = javaField.getType();
289 JDOField field = clazz.getField(fieldName);
290
291
292
293
294
295
296 if (field == null
297 && TypeSupport.isPersistenceFieldType(fieldType)) {
298 field = clazz.createJDOField(fieldName);
299 affirm(field != null,
300 "cannot create JDO field: "
301 + classPath + "." + fieldName);
302 }
303 field.setJavaField(javaField);
304 affirm(fieldType == field.getType());
305 affirm(field.getPersistenceModifier()
306 != PersistenceModifier.UNSPECIFIED,
307 "known, unspecified JDO field: " + classPath + "." + fieldName);
308 } catch (ModelFatalException ex) {
309 throw new EnhancerMetaDataUserException(ex);
310 } catch (ModelException ex) {
311 throw new EnhancerMetaDataUserException(ex);
312 }
313 }
314
315 /***
316 * Tests whether a class is known to be persistence-capable.
317 */
318 public boolean isPersistenceCapableClass(String classPath)
319 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
320 {
321 final JDOClass clazz = getJDOClass(classPath);
322 return (clazz != null);
323 }
324
325 /***
326 * Returns whether a class implements java.io.Serializable
327 * @param classPath the non-null JVM-qualified name of the class
328 * @return true if this class is serializable; otherwise false
329 */
330 public boolean isSerializableClass(String classPath)
331 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
332 {
333 final String className = classPath.replace('/', '.');
334 final JavaType javaType = javaModel.getJavaType(className);
335 return javaType.isCompatibleWith(serializableJavaType);
336 }
337
338 /***
339 * Returns the name of the persistence-capable root class of a class.
340 */
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 /***
360 * Returns the name of the persistence-capable superclass of a class.
361 */
362 public String getPersistenceCapableSuperClass(String classPath)
363 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
364 {
365 final JDOClass clazz = getJDOClass(classPath);
366 if (clazz == null) {
367 return null;
368 }
369 final String name = clazz.getPersistenceCapableSuperclassName();
370 return (name != null ? name.replace('.', '/') : null);
371 }
372
373 /***
374 * Returns the name of the key class of a persistence-capable class.
375 */
376 public String getKeyClass(String classPath)
377 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
378 {
379 final JDOClass clazz = getJDOClass(classPath);
380 if (clazz == null) {
381 return null;
382 }
383 final String name = clazz.getDeclaredObjectIdClassName();
384 return (name != null ? name.replace('.', '/') : null);
385 }
386
387 /***
388 * Returns an array of field names of all declared persistent and
389 * transactional fields of a class.
390 */
391 public String[] getManagedFields(String classPath)
392 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
393 {
394 final JDOClass clazz = getJDOClass(classPath);
395 if (clazz == null) {
396 return new String[]{};
397 }
398
399 final JDOField[] fields = clazz.getDeclaredManagedFields();
400 if (fields == null) {
401 return new String[]{};
402 }
403 affirm(fields.length == clazz.getDeclaredManagedFieldCount());
404
405 final int n = fields.length;
406 final String[] names = new String[n];
407 for (int i = 0; i < n; i++) {
408 affirm(fields[i] != null);
409 affirm(fields[i].getRelativeFieldNumber() == i);
410 affirm(fields[i].isManaged());
411 names[i] = fields[i].getName();
412 affirm(names[i] != null);
413 }
414 return names;
415 }
416
417 /***
418 * Returns whether a field of a class is known to be non-managed.
419 */
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438 /***
439 * Returns whether a field of a class is known to be non-managed.
440 */
441 public boolean isKnownNonManagedField(String classPath,
442 String fieldName,
443 String fieldSig)
444 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
445 {
446 affirm(classPath);
447 affirm(fieldName);
448 affirm(fieldSig);
449 try {
450 final JDOClass clazz = getJDOClass(classPath);
451 if (clazz == null) {
452
453 return true;
454 }
455
456
457
458 final JDOField field = clazz.getField(fieldName);
459 if (field != null && (field.getPersistenceModifier()
460 != PersistenceModifier.UNSPECIFIED)) {
461
462 return !field.isManaged();
463 }
464
465
466
467
468 JavaType fieldType = javaModel.getJavaType(javaModel.getTypeName(fieldSig));
469 affirm(fieldType != null,
470 "cannot get java type for: " + fieldSig);
471 return !TypeSupport.isPersistenceFieldType(fieldType);
472 } catch (ModelFatalException ex) {
473 throw new EnhancerMetaDataUserException(ex);
474 }
475 }
476
477 /***
478 * Tests whether a field of a class is transient transactional or
479 * persistent.
480 */
481 public boolean isManagedField(String classPath, String fieldName)
482 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
483 {
484 return hasFieldModifier(classPath, fieldName,
485 (PersistenceModifier.PERSISTENT
486 | PersistenceModifier.POSSIBLY_PERSISTENT
487 | PersistenceModifier.TRANSACTIONAL));
488 }
489
490 /***
491 * Tests whether a field of a class is persistent.
492 */
493 public boolean isPersistentField(String classPath, String fieldName)
494 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
495 {
496 return hasFieldModifier(classPath, fieldName,
497 (PersistenceModifier.PERSISTENT
498 | PersistenceModifier.POSSIBLY_PERSISTENT));
499 }
500
501 /***
502 * Tests whether a field of a class is transient transactional.
503 */
504 public boolean isTransactionalField(String classPath, String fieldName)
505 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
506 {
507 return hasFieldModifier(classPath, fieldName,
508 PersistenceModifier.TRANSACTIONAL);
509 }
510
511 /***
512 * Tests whether a field of a class is known to be Key.
513 */
514 public boolean isKeyField(String classPath, String fieldName)
515 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
516 {
517 final JDOField field = getJDOField(classPath, fieldName);
518 if (field == null) {
519 return false;
520 }
521 return field.isPrimaryKey();
522 }
523
524 /***
525 * Tests whether a field of a class is known to be part of the
526 * Default Fetch Group.
527 */
528 public boolean isDefaultFetchGroupField(String classPath, String fieldName)
529 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
530 {
531 final JDOField field = getJDOField(classPath, fieldName);
532 if (field == null) {
533 return false;
534 }
535 return field.isDefaultFetchGroup();
536 }
537
538 /***
539 * Returns the unique field index of a declared, persistent field of a
540 * class.
541 */
542 public int getFieldNumber(String classPath, String fieldName)
543 throws EnhancerMetaDataUserException, EnhancerMetaDataFatalError
544 {
545 final JDOField field = getJDOField(classPath, fieldName);
546 if (field == null) {
547 return -1;
548 }
549 return field.getRelativeFieldNumber();
550 }
551
552 }