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