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