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.prop;
19
20 import java.lang.reflect.Modifier;
21
22 import java.util.Iterator;
23 import java.util.Enumeration;
24 import java.util.Map;
25 import java.util.List;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.HashMap;
29 import java.util.ArrayList;
30 import java.util.Properties;
31 import java.util.StringTokenizer;
32
33 import java.text.MessageFormat;
34
35 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataFatalError;
36 import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
37
38
39
40 /***
41 * This class parses properties containing meta data information
42 * about classes. The syntax of the properties is the following:
43 * <ul>
44 * <li> the keys in the properties file are fully qualified classnames or
45 * fully qualified fieldnames </li>
46 * <li> a fields is separated by a classname with a hash mark ('#')
47 * (e.g. "test.Test#test1") </li>
48 * <li> all classnames are given in a natural form (e.g.
49 * "java.lang.Integer", "java.lang.Integer[][]", "int",
50 * "test.Test$Test1") </li>
51 * <li> property keys are classnames and fieldnames
52 * (e.g. "test.Test=...", "test.Test#field1=...") <br> </li>
53 * <li> Classnames can have the following attributes:
54 * <ul>
55 * <li> jdo:{persistent|transactional} </li>
56 * <li> super: <classname> </li>
57 * <li> oid: <classname> </li>
58 * <li> access: {public|protected|package|private} </li>
59 * </ul> </li>
60 * <li> Fieldnames can have the following attributes:
61 * <ul>
62 * <li> type:<type> </li>
63 * <li> access: {public|protected|package|private} </li>
64 * <li> jdo:{persistent|transactional|transient} </li>
65 * <li> annotation:{key|dfg|mediated} </li>
66 * </ul> </li>
67 * <li> the names of the attributes can be ommitted: you can say <br>
68 * test.Test1#field1=jdo:persistent,type:java.lang.String,key,... <br>
69 * or <br>
70 * test.Test1#field1=persistent,java.lang.String,key,... <br>
71 * or <br>
72 * test.Test1#field1=jdo:persistent,java.lang.String,key,... <br> </li>
73 * <li> in order to find fields of a class, a line for the class has to be
74 * specified in the properties: To find the field
75 * <code>test.Test1#field</code>, the keys <code>test.Test1</code> and
76 * <code>test.Test1#Field</code> have to be present. </li>
77 * </ul>
78 * This class is not thread safe.
79 */
80 final class MetaDataProperties
81 {
82 /***
83 * The delimiter of a property key between the class- and fieldname.
84 */
85 static final char FIELD_DELIMITER = '#';
86
87 /***
88 * A string of delimiter characters between attributes.
89 */
90 static final String PROPERTY_DELIMITERS = " \t,;";
91
92 /***
93 * A delimiter character between attribute name and attribute value
94 */
95 static final char PROPERTY_ASSIGNER = ':';
96
97
98 static final String PROPERTY_ACCESS_MODIFIER = "access";
99 static final String PROPERTY_JDO_MODIFIER = "jdo";
100 static final String PROPERTY_SUPER_CLASSNAME = "super";
101 static final String PROPERTY_OID_CLASSNAME = "oid";
102 static final String PROPERTY_TYPE = "type";
103 static final String PROPERTY_ANNOTATION_TYPE = "annotation";
104
105
106 static final String ACCESS_PRIVATE = "private";
107 static final String ACCESS_PACKAGE_LOCAL = "package";
108 static final String ACCESS_PROTECTED = "protected";
109 static final String ACCESS_PUBLIC = "public";
110
111
112 static final String JDO_TRANSIENT = "transient";
113 static final String JDO_PERSISTENT = "persistent";
114 static final String JDO_TRANSACTIONAL = "transactional";
115
116
117 static final String ANNOTATION_TYPE_KEY = "key";
118 static final String ANNOTATION_TYPE_DFG = "dfg";
119 static final String ANNOTATION_TYPE_MEDIATED = "mediated";
120
121 /***
122 * The properties to parse.
123 */
124 private Properties properties;
125
126 /***
127 * A map of already read class properties. The keys are the
128 * classnames, the values are the appropriate
129 * <code>JDOClass</code>-object.
130 */
131 private final Map cachedJDOClasses = new HashMap();
132
133 /***
134 * A constant for the cache indicating that a given classname
135 * if not specified in the properties.
136 */
137 static private final JDOClass NULL = new JDOClass(null);
138
139 /***
140 * A temporary vector (this is the reason why the implementation is not
141 * thread safe).
142 */
143 private final List tmpTokens = new ArrayList();
144
145 /***
146 * Creates a new object with the given properties.
147 *
148 * @param props The properties.
149 */
150 public MetaDataProperties(Properties props)
151 {
152 this.properties = props;
153 }
154
155 /***
156 * Get the information about the class with the given name.
157 *
158 * @param classname The classname.
159 * @return The information about the class or <code>null</code> if no
160 * information is given.
161 * @throws EnhancerMetaDataUserException If something went wrong parsing
162 * the properties.
163 */
164 public final JDOClass getJDOClass(String classname)
165 throws EnhancerMetaDataUserException
166 {
167 classname = NameHelper.toCanonicalClassName(classname);
168 JDOClass clazz = (JDOClass)cachedJDOClasses.get(classname);
169 if (clazz == NULL) {
170 return null;
171 }
172 if (clazz != null) {
173 return clazz;
174 }
175
176
177 String s = properties.getProperty(classname);
178 if (s == null) {
179 cachedJDOClasses.put(classname, NULL);
180 return null;
181 }
182
183
184 clazz = parseJDOClass(classname, s);
185 parseJDOFields(clazz);
186 validateDependencies(clazz);
187 cachedJDOClasses.put(clazz.getName(), clazz);
188
189 return clazz;
190 }
191
192 /***
193 * Gets the information about the specified field.
194 *
195 * @param classname The name of the class.
196 * @param fieldname The name of the field of the class.
197 * @return The information about the field or <code>null</code> if
198 * no information could be found.
199 * @throws EnhancerMetaDataUserException If something went wrong parsing
200 * the properties.
201 */
202 public final JDOField getJDOField(String fieldname,
203 String classname)
204 throws EnhancerMetaDataUserException
205 {
206 JDOClass clazz = getJDOClass(classname);
207 return (clazz != null ? clazz.getField(fieldname) : null);
208 }
209
210 /***
211 * Gets all classnames in the properties.
212 *
213 * @return All classnames in the properties.
214 */
215 public final String[] getKnownClassNames()
216 {
217 Collection classnames = new HashSet();
218 for (Enumeration names = properties.propertyNames();
219 names.hasMoreElements();) {
220 String name = (String)names.nextElement();
221 if (name.indexOf(FIELD_DELIMITER) < 0) {
222 classnames.add(NameHelper.fromCanonicalClassName(name));
223 }
224 }
225
226 return (String[])classnames.toArray(new String[classnames.size()]);
227 }
228
229 /***
230 * Parses the attributes-string of a class and puts them into a
231 * <code>JDOClass</code>-object.
232 *
233 * @param classname The name of the class.
234 * @param attributes The attribute-string as specified in the properties.
235 * @return The create <code>JDOClass</code>-object.
236 * @throws EnhancerMetaDataUserException If something went wrong parsing
237 * the attributes.
238 */
239 private final JDOClass parseJDOClass(String classname,
240 String attributes)
241 throws EnhancerMetaDataUserException
242 {
243 List props = parseProperties(attributes);
244
245
246 for (int i = 0; i < props.size(); i++) {
247 final Property prop = (Property)props.get(i);
248 validateClassProperty(prop, classname);
249 }
250
251
252 checkForDuplicateProperties(props, classname);
253
254
255 JDOClass clazz = new JDOClass(classname);
256 for (int i = 0; i < props.size(); i++) {
257 Property prop = (Property)props.get(i);
258 if (prop.name.equals(PROPERTY_ACCESS_MODIFIER)) {
259 clazz.setModifiers(getModifiers(prop.value));
260 } else if (prop.name.equals(PROPERTY_JDO_MODIFIER)) {
261 clazz.setPersistent(prop.value.equals(JDO_PERSISTENT));
262 } else if (prop.name.equals(PROPERTY_SUPER_CLASSNAME)) {
263 clazz.setSuperClassName(prop.value);
264 } else if (prop.name.equals(PROPERTY_OID_CLASSNAME)) {
265 clazz.setOidClassName(prop.value);
266 }
267 }
268
269 return clazz;
270 }
271
272 /***
273 * Checks if the given attribute-property of a class is valid.
274 *
275 * @param prop The attribute-property.
276 * @param classname The classname.
277 * @throws EnhancerMetaDataUserException If the validation failed.
278 */
279 static private void validateClassProperty(Property prop,
280 String classname)
281 throws EnhancerMetaDataUserException
282 {
283 String value = prop.value;
284 if (prop.name == null) {
285
286 if (value.equals(ACCESS_PUBLIC)
287 || value.equals(ACCESS_PROTECTED)
288 || value.equals(ACCESS_PACKAGE_LOCAL)
289 || value.equals(ACCESS_PRIVATE)) {
290
291 prop.name = PROPERTY_ACCESS_MODIFIER;
292 } else if (value.equals(JDO_PERSISTENT)
293 || value.equals(JDO_TRANSIENT)) {
294
295 prop.name = PROPERTY_JDO_MODIFIER;
296 }
297
298
299
300
301
302 } else {
303
304 String name = prop.name;
305 checkPropertyName(prop.name,
306 new String[]{
307 PROPERTY_ACCESS_MODIFIER,
308 PROPERTY_JDO_MODIFIER,
309 PROPERTY_SUPER_CLASSNAME,
310 PROPERTY_OID_CLASSNAME
311 },
312 classname);
313
314
315 checkPropertyValue(prop,
316 new String[]{
317 ACCESS_PUBLIC,
318 ACCESS_PROTECTED,
319 ACCESS_PACKAGE_LOCAL,
320 ACCESS_PRIVATE
321 },
322 PROPERTY_ACCESS_MODIFIER,
323 classname);
324 checkPropertyValue(prop,
325 new String[]{
326 JDO_TRANSIENT,
327 JDO_PERSISTENT
328 },
329 PROPERTY_JDO_MODIFIER,
330 classname);
331 }
332 }
333
334 /***
335 * Parses all fields of a given class.
336 *
337 * @param clazz the representation of the class
338 * @throws EnhancerMetaDataUserException on parse errors
339 */
340 private final void parseJDOFields(JDOClass clazz)
341 throws EnhancerMetaDataUserException
342 {
343
344 for (Enumeration names = properties.propertyNames();
345 names.hasMoreElements();) {
346 String name = (String)names.nextElement();
347 if (name.startsWith(clazz.getName() + FIELD_DELIMITER)) {
348
349 String fieldname
350 = name.substring(name.indexOf(FIELD_DELIMITER) + 1,
351 name.length());
352 validateFieldName(fieldname, clazz.getName());
353 clazz.addField(parseJDOField(properties.getProperty(name),
354 fieldname, clazz));
355 }
356 }
357 clazz.sortFields();
358 }
359
360 /***
361 * Parses the attribute-string of a field.
362 *
363 * @param attributes The attribute-string.
364 * @param fieldname The fieldname.
365 * @param clazz The class to field belongs to.
366 * @throws EnhancerMetaDataUserException on parse errors
367 */
368 private final JDOField parseJDOField(String attributes,
369 String fieldname,
370 JDOClass clazz)
371 throws EnhancerMetaDataUserException
372 {
373 List props = parseProperties(attributes);
374
375
376 for (int i = 0; i < props.size(); i++) {
377 Property prop = (Property)props.get(i);
378 validateFieldProperty(prop, fieldname, clazz.getName());
379 }
380
381
382 checkForDuplicateProperties(props,
383 clazz.getName() + FIELD_DELIMITER
384 + fieldname);
385
386
387 JDOField field = new JDOField(fieldname);
388 for (int i = 0; i < props.size(); i++) {
389 Property prop = (Property)props.get(i);
390 if (prop.name.equals(PROPERTY_ACCESS_MODIFIER)) {
391 field.setModifiers(getModifiers(prop.value));
392 } else if (prop.name.equals(PROPERTY_JDO_MODIFIER)) {
393 field.setJdoModifier(prop.value);
394 } else if (prop.name.equals(PROPERTY_TYPE)) {
395 field.setType(prop.value);
396 } else if (prop.name.equals(PROPERTY_ANNOTATION_TYPE)) {
397 field.setAnnotationType(prop.value);
398 }
399 }
400
401 return field;
402 }
403
404 /***
405 * Checks if the given attribute-property if valid for a field.
406 *
407 * @param prop The attribute-property.
408 * @param fieldname The fieldname.
409 * @param classname The classname.
410 * @throws EnhancerMetaDataUserException If the check fails.
411 */
412 private final void validateFieldProperty(Property prop,
413 String fieldname,
414 String classname)
415 throws EnhancerMetaDataUserException
416 {
417
418 String value = prop.value;
419 if (prop.name == null) {
420 if (value.equals(ACCESS_PUBLIC) ||
421 value.equals(ACCESS_PROTECTED) ||
422 value.equals(ACCESS_PACKAGE_LOCAL) ||
423 value.equals(ACCESS_PRIVATE)) {
424
425 prop.name = PROPERTY_ACCESS_MODIFIER;
426 } else if (value.equals(JDO_PERSISTENT) ||
427 value.equals(JDO_TRANSIENT) ||
428 value.equals(JDO_TRANSACTIONAL)) {
429
430 prop.name = PROPERTY_JDO_MODIFIER;
431 } else if (value.equals(ANNOTATION_TYPE_KEY) ||
432 value.equals(ANNOTATION_TYPE_DFG) ||
433 value.equals(ANNOTATION_TYPE_MEDIATED)) {
434
435 prop.name = PROPERTY_ANNOTATION_TYPE;
436 } else {
437
438 prop.name = PROPERTY_TYPE;
439 }
440 } else {
441 String entry = classname + FIELD_DELIMITER + fieldname;
442
443
444 checkPropertyName(prop.name,
445 new String[]{
446 PROPERTY_ACCESS_MODIFIER,
447 PROPERTY_JDO_MODIFIER,
448 PROPERTY_TYPE,
449 PROPERTY_ANNOTATION_TYPE
450 },
451 entry);
452
453
454 checkPropertyValue(prop,
455 new String[]{
456 ACCESS_PUBLIC,
457 ACCESS_PROTECTED,
458 ACCESS_PACKAGE_LOCAL,
459 ACCESS_PRIVATE
460 },
461 PROPERTY_ACCESS_MODIFIER,
462 entry);
463 checkPropertyValue(prop,
464 new String[]{
465 JDO_PERSISTENT,
466 JDO_TRANSIENT,
467 JDO_TRANSACTIONAL
468 },
469 PROPERTY_JDO_MODIFIER,
470 entry);
471 checkPropertyValue(prop,
472 new String[]{
473 ANNOTATION_TYPE_KEY,
474 ANNOTATION_TYPE_DFG,
475 ANNOTATION_TYPE_MEDIATED
476 },
477 PROPERTY_ANNOTATION_TYPE,
478 entry);
479 }
480 }
481
482 /***
483 * Validates dependencies between a class and its fields and between.
484 *
485 * @param clazz the class
486 * @throws EnhancerMetaDataUserException if the validation fails
487 */
488 private final void validateDependencies(JDOClass clazz)
489 throws EnhancerMetaDataUserException
490 {
491 final List fields = clazz.getFields();
492 for (Iterator i = fields.iterator(); i.hasNext();) {
493 JDOField field = (JDOField)i.next();
494
495
496 if (field.isPersistent() && clazz.isTransient()) {
497
498 final String msg
499 = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD,
500 new String[]{
501 clazz.getName(),
502 field.getName() });
503 throw new EnhancerMetaDataUserException(msg);
504 }
505 if (field.isTransactional() && clazz.isTransient()) {
506
507 final String msg
508 = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD,
509 new String[]{
510 clazz.getName(),
511 field.getName() });
512 throw new EnhancerMetaDataUserException(msg);
513 }
514 if (!field.isKnownTransient() && !field.isManaged()) {
515
516 final String msg
517 = getMsg(Msg.ERR_UNSPECIFIED_FIELD_PERSISTENCE_MODIFIER,
518 new String[]{
519 clazz.getName(),
520 field.getName() });
521 throw new EnhancerMetaDataUserException(msg);
522 }
523
524
525 if (!field.isAnnotated() && field.isManaged()) {
526
527 final String msg
528 = getMsg(Msg.ERR_UNSPECIFIED_FIELD_ANNOTATION_TYPE,
529 new String[]{
530 clazz.getName(),
531 field.getName() });
532 throw new EnhancerMetaDataUserException(msg);
533 }
534 if (field.isAnnotated() && !field.isManaged()) {
535
536 final String msg
537 = getMsg(Msg.ERR_NON_MANAGED_ANNOTATED_FIELD,
538 new String[]{
539 clazz.getName(),
540 field.getName() });
541 throw new EnhancerMetaDataUserException(msg);
542 }
543 if (field.isAnnotated() && clazz.isTransient()) {
544
545 final String msg
546 = getMsg(Msg.ERR_TRANSIENT_CLASS_WITH_ANNOTATED_FIELD,
547 new String[]{
548 clazz.getName(),
549 field.getName() });
550 throw new EnhancerMetaDataUserException(msg);
551 }
552 }
553 }
554
555 /***
556 * Checks if a given fieldname is a valid Java identifier.
557 *
558 * @param fieldname The fieldname.
559 * @param classname The corresponding classname.
560 * @throws EnhancerMetaDataUserException If the check fails.
561 */
562 static private void validateFieldName(String fieldname,
563 String classname)
564 throws EnhancerMetaDataUserException
565 {
566 if (fieldname.length() == 0) {
567 final String msg
568 = getMsg(Msg.ERR_EMPTY_FIELDNAME,
569 new String[]{ classname });
570 throw new EnhancerMetaDataUserException(msg);
571 }
572
573 if (!Character.isJavaIdentifierStart(fieldname.charAt(0))) {
574 final String msg
575 = getMsg(Msg.ERR_INVALID_FIELDNAME,
576 new String[]{ classname, fieldname });
577 throw new EnhancerMetaDataUserException(msg);
578 }
579
580 for (int i = fieldname.length() - 1; i >= 0; i--) {
581 final char c = fieldname.charAt(i);
582 if (!Character.isJavaIdentifierPart(c)) {
583 final String msg
584 = getMsg(Msg.ERR_INVALID_FIELDNAME,
585 new String[]{ classname, fieldname });
586 throw new EnhancerMetaDataUserException(msg);
587 }
588 }
589 }
590
591 /***
592 * Checks if an attribute-property was entered twice for a class or field.
593 *
594 * @param props The properties.
595 * @param entry The class- or fieldname.
596 * @throws EnhancerMetaDataUserException If the check fails.
597 */
598 static private void checkForDuplicateProperties(List props,
599 String entry)
600 throws EnhancerMetaDataUserException
601 {
602 for (int i = 0; i < props.size(); i++) {
603 for (int j = i + 1; j < props.size(); j++) {
604 Property p1 = (Property)props.get(i);
605 Property p2 = (Property)props.get(j);
606 if (p1.name.equals(p2.name) && !p1.value.equals(p2.value)) {
607 final String msg
608 = getMsg(Msg.ERR_DUPLICATE_PROPERTY_NAME,
609 new String[]{
610 entry,
611 p1.name,
612 p1.value,
613 p2.value });
614 throw new EnhancerMetaDataUserException(msg);
615 }
616 }
617 }
618 }
619
620 /***
621 * Checks if an attribute name is recognized by the parser.
622 *
623 * @param name The name of the attribute.
624 * @param validnames A list of valid names(the attribute name has to
625 * be in this list).
626 * @param entry The class- or fieldname.
627 * @throws EnhancerMetaDataUserException If the check fails.
628 */
629 static private void checkPropertyName(String name,
630 String[] validnames,
631 String entry)
632 throws EnhancerMetaDataUserException
633 {
634 for (int i = 0; i < validnames.length; i++) {
635 if (name.equals(validnames[i])) {
636 return;
637 }
638 }
639
640 final String msg
641 = getMsg(Msg.ERR_INVALID_PROPERTY_NAME,
642 new String[]{ entry, name });
643 throw new EnhancerMetaDataUserException(msg);
644 }
645
646 /***
647 * Checks if the given value of an attribute-property is recognized by
648 * by the parser if that value belongs to a given attribute name.
649 *
650 * @param prop The attribute-property(with name and value).
651 * @param validvalues A list of valid values.
652 * @param name The name of the attribute-property to check.
653 * @param entry The class- or fieldname.
654 * @throws EnhancerMetaDataUserException If the check fails.
655 */
656 static private void checkPropertyValue(Property prop,
657 String[] validvalues,
658 String name,
659 String entry)
660 throws EnhancerMetaDataUserException
661 {
662 if ( !prop.name.equals(name)) {
663 return;
664 }
665
666 for (int i = 0; i < validvalues.length; i++) {
667 if (prop.value.equals(validvalues[i])) {
668 return;
669 }
670 }
671
672 final String msg
673 = getMsg(Msg.ERR_INVALID_PROPERTY_VALUE,
674 new String[]{ entry, name, prop.value });
675 throw new EnhancerMetaDataUserException(msg);
676 }
677
678 /***
679 * Formats an error message with the given parameters.
680 *
681 * @param msg The message with format strings.
682 * @param params The params to format the message with.
683 * @return The formatted error message.
684 */
685 static final String getMsg(String msg,
686 String[] params)
687 {
688 return MessageFormat.format(msg, params);
689 }
690
691 /***
692 * Parses the attribute-string of a class- or fieldname.
693 *
694 * @param attributes The attribute-string.
695 * @return A list of <code>Propert<</code>-objects for the attributes.
696 * @exception EnhancerMetaDataUserException If the parsing fails.
697 */
698 final List parseProperties(String attributes)
699 throws EnhancerMetaDataUserException
700 {
701 tmpTokens.clear();
702 for (StringTokenizer t
703 = new StringTokenizer(attributes, PROPERTY_DELIMITERS);
704 t.hasMoreTokens();) {
705 tmpTokens.add(parseProperty(t.nextToken()));
706 }
707
708 return tmpTokens;
709 }
710
711 /***
712 * Parses the given attribute and splits it into name and value.
713 *
714 * @param attribute The attribute-string.
715 * @return The <code>Propert</code>-object.
716 * @exception EnhancerMetaDataUserException If the parsing fails.
717 */
718 private final Property parseProperty(String attribute)
719 throws EnhancerMetaDataUserException
720 {
721 Property prop = new Property();
722 int idx = attribute.indexOf(PROPERTY_ASSIGNER);
723 if (idx < 0) {
724 prop.value = attribute;
725 } else {
726 prop.name = attribute.substring(0, idx);
727 prop.value = attribute.substring(idx + 1, attribute.length());
728 if (prop.name.length() == 0 || prop.value.length() == 0) {
729 final String msg
730 = getMsg(Msg.ERR_EMPTY_PROPERTY_NAME_OR_VALUE,
731 new String[]{ attribute });
732 throw new EnhancerMetaDataUserException(msg);
733 }
734 }
735
736 return prop;
737 }
738
739 /***
740 * Returns the modifier value for a Java modifier name.
741 */
742 static private int getModifiers(String modifier)
743 {
744 if (modifier.equals(ACCESS_PUBLIC)) {
745 return Modifier.PUBLIC;
746 }
747 if (modifier.equals(ACCESS_PRIVATE)) {
748 return Modifier.PRIVATE;
749 }
750 if (modifier.equals(ACCESS_PROTECTED)) {
751 return Modifier.PROTECTED;
752 }
753 return 0;
754 }
755
756 /***
757 * A simple test to run from the command line.
758 *
759 * @param argv The command line arguments.
760 */
761 public static void main(String[] argv)
762 {
763 if (argv.length != 1) {
764 System.err.println("Error: no property filename specified");
765 return;
766 }
767 final Properties p = new Properties();
768 try {
769 java.io.InputStream in
770 = new java.io.FileInputStream(new java.io.File(argv[0]));
771 p.load(in);
772 in.close();
773 System.out.println("PROPERTIES: " + p);
774 System.out.println("############");
775 final MetaDataProperties props = new MetaDataProperties(p);
776 String[] classnames = props.getKnownClassNames();
777 for (int i = 0; i < classnames.length; i++) {
778 String classname = classnames[i];
779 System.out.println(classname + ": "
780 + props.getJDOClass(classname));
781 }
782 } catch(Throwable ex) {
783 ex.printStackTrace(System.err);
784 }
785 }
786
787 /***
788 * The holder-class for the name and the value of a property.
789 */
790 static private final class Property
791 {
792 /***
793 * The name of the property.
794 */
795 String name = null;
796
797 /***
798 * The value of the property.
799 */
800 String value = null;
801
802 /***
803 * Creates a string-representation of this object.
804 *
805 * @return The string-representation of this object.
806 */
807 public final String toString()
808 {
809 return '<' + name + ':' + value + '>';
810 }
811 }
812
813
814
815 /***
816 * Holds all unformatted error messages.
817 */
818 static private interface Msg
819 {
820
821 static final String PREFIX = "Error Parsing meta data properties: ";
822
823 static final String ERR_EMPTY_FIELDNAME =
824 PREFIX + "The class ''{0}'' may not have an empty fieldname.";
825
826 static final String ERR_INVALID_FIELDNAME =
827 PREFIX + "The field name ''{1}'' of class ''{0}'' is not valid.";
828
829 static final String ERR_EMPTY_PROPERTY_NAME_OR_VALUE =
830 PREFIX + "The property name and value may not be empty if a ''" +
831 PROPERTY_ASSIGNER + "'' is specified: ''{0}''.";
832
833 static final String ERR_INVALID_PROPERTY_NAME =
834 PREFIX + "Invalid property name for entry ''{0}'': ''{1}''.";
835
836 static final String ERR_INVALID_PROPERTY_VALUE =
837 PREFIX + "Invalid value for property ''{1}'' of entry ''{0}'': ''{2}''.";
838
839 static final String ERR_DUPLICATE_PROPERTY_NAME =
840 PREFIX + "The property ''{1}'' for the entry ''{0}'' entered twice with values: ''{2}'' and ''{3}''.";
841
842 static final String ERR_UNSPECIFIED_FIELD_PERSISTENCE_MODIFIER =
843 PREFIX + "No persistence modifier specified for field: ''{0}.{1}''.";
844
845 static final String ERR_TRANSIENT_CLASS_WITH_PERSISTENT_FIELD =
846 PREFIX + "A non-persistent class cannot have a persistent field(class ''{0}'' with field ''{1})''.";
847
848 static final String ERR_TRANSIENT_CLASS_WITH_TRANSACTIONAL_FIELD =
849 PREFIX + "A non-persistent class cannot have a transactional field(class ''{0}'' with field ''{1})''.";
850
851 static final String ERR_UNSPECIFIED_FIELD_ANNOTATION_TYPE =
852 PREFIX + "No annotation type specified for field: ''{0}.{1}''.";
853
854 static final String ERR_TRANSIENT_CLASS_WITH_ANNOTATED_FIELD =
855 PREFIX + "A non-persistent class cannot have an annotated field(''{1}'' of class ''{0}'') can''t have a fetch group.";
856
857 static final String ERR_NON_MANAGED_ANNOTATED_FIELD =
858 PREFIX + "A non-managed field(''{1}'' of class ''{0}'') can''t be a annotated.";
859 }
860 }