View Javadoc

1   package org.modeshape.sequencer.java;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedList;
5   import java.util.List;
6   import java.util.Map;
7   import org.modeshape.graph.JcrLexicon;
8   import org.modeshape.graph.property.DateTimeFactory;
9   import org.modeshape.graph.property.Path;
10  import org.modeshape.graph.property.PathFactory;
11  import org.modeshape.graph.property.Path.Segment;
12  import org.modeshape.graph.sequencer.SequencerOutput;
13  import org.modeshape.graph.sequencer.StreamSequencerContext;
14  import org.modeshape.sequencer.classfile.ClassFileSequencerLexicon;
15  import org.modeshape.sequencer.classfile.metadata.Visibility;
16  import org.modeshape.sequencer.java.metadata.AnnotationMetadata;
17  import org.modeshape.sequencer.java.metadata.EnumMetadata;
18  import org.modeshape.sequencer.java.metadata.FieldMetadata;
19  import org.modeshape.sequencer.java.metadata.InterfaceMetadata;
20  import org.modeshape.sequencer.java.metadata.JavaMetadata;
21  import org.modeshape.sequencer.java.metadata.MethodMetadata;
22  import org.modeshape.sequencer.java.metadata.TypeMetadata;
23  
24  /**
25   * A source file recorder that writes the Java metadata from the source file to the repository, using the same structure as the
26   * default mode of the Java Class File sequencer.
27   */
28  public class ClassSourceFileRecorder implements SourceFileRecorder {
29  
30      public void record( StreamSequencerContext context,
31                          SequencerOutput output,
32                          JavaMetadata javaMetadata ) {
33  
34          PathFactory pathFactory = pathFactoryFor(context);
35          DateTimeFactory dateFactory = dateFactoryFor(context);
36  
37          writeJavaMetadata(output, pathFactory, dateFactory, javaMetadata);
38  
39      }
40  
41      private DateTimeFactory dateFactoryFor( StreamSequencerContext context ) {
42          return context.getValueFactories().getDateFactory();
43      }
44  
45      private PathFactory pathFactoryFor( StreamSequencerContext context ) {
46          return context.getValueFactories().getPathFactory();
47      }
48  
49      private Path pathFor( PathFactory pathFactory,
50                            TypeMetadata tmd ) {
51          List<Segment> segments = new LinkedList<Segment>();
52  
53          for (String segment : tmd.getName().split("\\.")) {
54              segments.add(pathFactory.createSegment(segment));
55          }
56  
57          return pathFactory.createRelativePath(segments);
58      }
59  
60      private void writeJavaMetadata( SequencerOutput output,
61                                      PathFactory pathFactory,
62                                      DateTimeFactory dateFactory,
63                                      JavaMetadata javaMetadata ) {
64  
65          for (TypeMetadata typeMetadata : javaMetadata.getTypeMetadata()) {
66              writeClassMetadata(output, pathFactory, dateFactory, pathFor(pathFactory, typeMetadata), typeMetadata);
67          }
68      }
69  
70      private void writeClassMetadata( SequencerOutput output,
71                                       PathFactory pathFactory,
72                                       DateTimeFactory dateFactory,
73                                       Path classPath,
74                                       TypeMetadata cmd ) {
75  
76          /*
77          - class:name (string) mandatory 
78          - class:superClassName (string) 
79          - class:visibility (string) mandatory < 'public', 'protected', 'package', 'private'
80          - class:abstract (boolean) mandatory
81          - class:interface (boolean) mandatory
82          - class:final (boolean) mandatory
83          - class:strictFp (boolean) mandatory
84          - class:interfaces (string) multiple
85          + class:annotations (class:annotations) = class:annotations
86          + class:constructors (class:constructors) = class:constructors
87          + class:methods (class:methods) = class:methods
88          + class:fields (class:fields) = class:fields
89           */
90  
91          int numberOfMethods = cmd.getMethods().size();
92          List<MethodMetadata> methods = new ArrayList<MethodMetadata>(numberOfMethods);
93          List<MethodMetadata> ctors = new ArrayList<MethodMetadata>(numberOfMethods);
94  
95          for (MethodMetadata method : cmd.getMethods()) {
96              if (method.isContructor()) {
97                  ctors.add(method);
98              } else {
99                  methods.add(method);
100             }
101         }
102 
103         output.setProperty(classPath, ClassFileSequencerLexicon.NAME, cmd.getName());
104         output.setProperty(classPath, ClassFileSequencerLexicon.SEQUENCED_DATE, dateFactory.create());
105         String superClassName = cmd.getSuperClassName();
106         if (superClassName == null || superClassName.length() == 0) {
107             superClassName = Object.class.getCanonicalName();
108         }
109         output.setProperty(classPath, ClassFileSequencerLexicon.SUPER_CLASS_NAME, superClassName);
110         output.setProperty(classPath, ClassFileSequencerLexicon.VISIBILITY, visibilityFor(cmd).getDescription());
111         output.setProperty(classPath, ClassFileSequencerLexicon.ABSTRACT, cmd.hasModifierNamed("abstract"));
112         output.setProperty(classPath, ClassFileSequencerLexicon.INTERFACE, (cmd instanceof InterfaceMetadata));
113         output.setProperty(classPath, ClassFileSequencerLexicon.FINAL, cmd.hasModifierNamed("final"));
114         output.setProperty(classPath, ClassFileSequencerLexicon.STRICT_FP, cmd.hasModifierNamed("strictfp"));
115         output.setProperty(classPath, ClassFileSequencerLexicon.INTERFACES, cmd.getInterfaceNames().toArray());
116 
117         Path constructorsPath = pathFactory.create(classPath, ClassFileSequencerLexicon.CONSTRUCTORS);
118         output.setProperty(constructorsPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.CONSTRUCTORS);
119         writeMethods(output, pathFactory, constructorsPath, ctors);
120 
121         Path methodsPath = pathFactory.create(classPath, ClassFileSequencerLexicon.METHODS);
122         output.setProperty(methodsPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.METHODS);
123         writeMethods(output, pathFactory, methodsPath, methods);
124 
125         writeFieldsNode(output, pathFactory, classPath, cmd.getFields());
126         writeAnnotationsNode(output, pathFactory, classPath, cmd.getAnnotations());
127 
128         if (cmd instanceof EnumMetadata) {
129             output.setProperty(classPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.ENUM);
130 
131             output.setProperty(classPath, ClassFileSequencerLexicon.ENUM_VALUES, ((EnumMetadata)cmd).getValues().toArray());
132         } else {
133             output.setProperty(classPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.CLASS);
134         }
135     }
136 
137     private Visibility visibilityFor( TypeMetadata cmd ) {
138         if (cmd.hasModifierNamed("public")) return Visibility.PUBLIC;
139         if (cmd.hasModifierNamed("protected")) return Visibility.PROTECTED;
140         if (cmd.hasModifierNamed("private")) return Visibility.PRIVATE;
141 
142         return Visibility.PACKAGE;
143     }
144 
145     private Visibility visibilityFor( FieldMetadata cmd ) {
146         if (cmd.hasModifierNamed("public")) return Visibility.PUBLIC;
147         if (cmd.hasModifierNamed("protected")) return Visibility.PROTECTED;
148         if (cmd.hasModifierNamed("private")) return Visibility.PRIVATE;
149 
150         return Visibility.PACKAGE;
151     }
152 
153     private Visibility visibilityFor( MethodMetadata cmd ) {
154         if (cmd.hasModifierNamed("public")) return Visibility.PUBLIC;
155         if (cmd.hasModifierNamed("protected")) return Visibility.PROTECTED;
156         if (cmd.hasModifierNamed("private")) return Visibility.PRIVATE;
157 
158         return Visibility.PACKAGE;
159     }
160 
161     private void writeAnnotationsNode( SequencerOutput output,
162                                        PathFactory pathFactory,
163                                        Path parentPath,
164                                        List<AnnotationMetadata> annotations ) {
165 
166         /*
167         [class:annotationMember]
168         - class:name (string) mandatory
169         - class:value (string) 
170         
171         [class:annotation]
172         - class:name (string) mandatory
173         + * (class:annotationMember) = class:annotationMember
174         
175         [class:annotations]
176         + * (class:annotation) = class:annotation
177          */
178 
179         Path annotationsPath = pathFactory.create(parentPath, ClassFileSequencerLexicon.ANNOTATIONS);
180         output.setProperty(annotationsPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.ANNOTATIONS);
181 
182         for (AnnotationMetadata annotation : annotations) {
183             Path annotationPath = pathFactory.create(annotationsPath, annotation.getName());
184             output.setProperty(annotationPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.ANNOTATION);
185 
186             for (Map.Entry<String, String> entry : annotation.getMemberValues().entrySet()) {
187                 String key = entry.getKey();
188                 if (key == null) key = "default";
189 
190                 Path annotationMemberPath = pathFactory.create(annotationPath, key);
191                 output.setProperty(annotationMemberPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.ANNOTATION_MEMBER);
192                 output.setProperty(annotationMemberPath, ClassFileSequencerLexicon.NAME, entry.getKey());
193                 output.setProperty(annotationMemberPath, ClassFileSequencerLexicon.VALUE, entry.getValue());
194 
195             }
196         }
197     }
198 
199     private void writeFieldsNode( SequencerOutput output,
200                                   PathFactory pathFactory,
201                                   Path classPath,
202                                   List<FieldMetadata> fields ) {
203 
204         /*
205             [class:field]
206             - class:name (string) mandatory 
207             - class:typeClassName (string) mandatory 
208             - class:visibility (string) mandatory < 'public', 'protected', 'package', 'private'
209             - class:static (boolean) mandatory
210             - class:final (boolean) mandatory
211             - class:transient (boolean) mandatory
212             - class:volatile (boolean) mandatory
213             + class:annotations (class:annotations) = class:annotations
214             
215             [class:fields]
216             + * (class:field) = class:field
217          */
218 
219         Path fieldsPath = pathFactory.create(classPath, ClassFileSequencerLexicon.FIELDS);
220         output.setProperty(fieldsPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.FIELDS);
221 
222         for (FieldMetadata field : fields) {
223             Path fieldPath = pathFactory.create(fieldsPath, field.getName());
224 
225             output.setProperty(fieldPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.FIELD);
226             output.setProperty(fieldPath, ClassFileSequencerLexicon.NAME, field.getName());
227             output.setProperty(fieldPath, ClassFileSequencerLexicon.TYPE_CLASS_NAME, field.getType());
228             output.setProperty(fieldPath, ClassFileSequencerLexicon.VISIBILITY, visibilityFor(field).getDescription());
229             output.setProperty(classPath, ClassFileSequencerLexicon.STATIC, field.hasModifierNamed("static"));
230             output.setProperty(classPath, ClassFileSequencerLexicon.FINAL, field.hasModifierNamed("final"));
231             output.setProperty(classPath, ClassFileSequencerLexicon.TRANSIENT, field.hasModifierNamed("transient"));
232             output.setProperty(classPath, ClassFileSequencerLexicon.VOLATILE, field.hasModifierNamed("volatile"));
233 
234             writeAnnotationsNode(output, pathFactory, fieldPath, field.getAnnotations());
235 
236         }
237     }
238 
239     private void writeMethods( SequencerOutput output,
240                                PathFactory pathFactory,
241                                Path methodsPath,
242                                List<MethodMetadata> methods ) {
243 
244         /*
245             [class:method]
246             - class:name (string) mandatory 
247             - class:returnTypeClassName (string) mandatory 
248             - class:visibility (string) mandatory < 'public', 'protected', 'package', 'private'
249             - class:static (boolean) mandatory
250             - class:final (boolean) mandatory
251             - class:abstract (boolean) mandatory
252             - class:strictFp (boolean) mandatory
253             - class:native (boolean) mandatory
254             - class:synchronized (boolean) mandatory
255             - class:parameters (string) multiple
256             + class:annotations (class:annotations) = class:annotations
257          */
258 
259         for (MethodMetadata method : methods) {
260             Path methodPath = pathFactory.create(methodsPath, method.getId());
261 
262             output.setProperty(methodPath, JcrLexicon.PRIMARY_TYPE, ClassFileSequencerLexicon.METHOD);
263             output.setProperty(methodPath, ClassFileSequencerLexicon.NAME, method.getName());
264             output.setProperty(methodPath, ClassFileSequencerLexicon.RETURN_TYPE_CLASS_NAME, method.getReturnTypeName());
265             output.setProperty(methodPath, ClassFileSequencerLexicon.VISIBILITY, visibilityFor(method).getDescription());
266             output.setProperty(methodPath, ClassFileSequencerLexicon.STATIC, method.hasModifierNamed("static"));
267             output.setProperty(methodPath, ClassFileSequencerLexicon.FINAL, method.hasModifierNamed("final"));
268             output.setProperty(methodPath, ClassFileSequencerLexicon.ABSTRACT, method.hasModifierNamed("abstract"));
269             output.setProperty(methodPath, ClassFileSequencerLexicon.STRICT_FP, method.hasModifierNamed("strictfp"));
270             output.setProperty(methodPath, ClassFileSequencerLexicon.NATIVE, method.hasModifierNamed("native"));
271             output.setProperty(methodPath, ClassFileSequencerLexicon.SYNCHRONIZED, method.hasModifierNamed("synchronized"));
272             output.setProperty(methodPath, ClassFileSequencerLexicon.PARAMETERS, method.getParameterTypes().toArray());
273 
274             writeAnnotationsNode(output, pathFactory, methodPath, method.getAnnotations());
275 
276         }
277 
278     }
279 
280 }