KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > util > TraversalUtil


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.util;
21
22 import java.lang.reflect.Method JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import org.apache.cayenne.jpa.JpaProviderException;
29 import org.apache.cayenne.project.ProjectPath;
30
31 /**
32  * Defines tree traversal utility methods. Object tree sematics is determined using
33  * {@link org.apache.cayenne.util.TreeNodeChild} property getter annotation.
34  *
35  * @author Andrus Adamchik
36  */

37 public class TraversalUtil {
38
39     static final ClassTraversalDescriptor noopDescriptor = new ClassTraversalDescriptor();
40     static final Map JavaDoc<String JavaDoc, ClassTraversalDescriptor> descriptors = new HashMap JavaDoc<String JavaDoc, ClassTraversalDescriptor>();
41
42     private static Method JavaDoc[] traversableGetters(Class JavaDoc nodeType) {
43
44         Collection JavaDoc<Method JavaDoc> getters = null;
45
46         Method JavaDoc[] methods = nodeType.getMethods();
47         for (int i = 0; i < methods.length; i++) {
48             if (methods[i].isAnnotationPresent(TreeNodeChild.class)
49                     && !Void.TYPE.equals(methods[i].getReturnType())) {
50
51                 if (getters == null) {
52                     getters = new ArrayList JavaDoc<Method JavaDoc>(5);
53                 }
54
55                 getters.add(methods[i]);
56             }
57         }
58
59         return getters != null ? getters.toArray(new Method JavaDoc[getters.size()]) : null;
60     }
61
62     static synchronized ClassTraversalDescriptor getDescriptor(Class JavaDoc nodeType) {
63         String JavaDoc typeName = nodeType.getName();
64         ClassTraversalDescriptor descriptor = descriptors.get(typeName);
65         if (descriptor == null) {
66             Method JavaDoc[] getters = traversableGetters(nodeType);
67             descriptor = getters != null
68                     ? new ClassTraversalDescriptor(getters)
69                     : noopDescriptor;
70             descriptors.put(typeName, descriptor);
71         }
72
73         return descriptor;
74     }
75
76     /**
77      * Performs tree traversal with a given visitor starting with a given node.
78      */

79     public static void traverse(Object JavaDoc treeRoot, HierarchicalTreeVisitor visitor) {
80         traverse(treeRoot, visitor, null);
81     }
82
83     static void traverse(
84             Object JavaDoc node,
85             HierarchicalTreeVisitor visitor,
86             ProjectPath parentPath) {
87
88         ProjectPath path = parentPath != null
89                 ? parentPath.appendToPath(node)
90                 : new ProjectPath(node);
91
92         if (visitor.onStartNode(path)) {
93
94             ClassTraversalDescriptor descriptor = getDescriptor(node.getClass());
95             Class JavaDoc[] childTypes = descriptor.getTraversableChildTypes();
96             if (childTypes != null && childTypes.length > 0) {
97                 for (int i = 0; i < childTypes.length; i++) {
98
99                     HierarchicalTreeVisitor childVisitor = visitor.childVisitor(
100                             path,
101                             childTypes[i]);
102                     if (childVisitor != null) {
103                         Object JavaDoc child = descriptor.getTraversableChild(node, i);
104
105                         if (child == null) {
106                             continue;
107                         }
108                         else if (child instanceof Collection JavaDoc) {
109                             Collection JavaDoc children = (Collection JavaDoc) child;
110
111                             if (children != null && !children.isEmpty()) {
112                                 for (Object JavaDoc collectionChild : children) {
113                                     traverse(collectionChild, childVisitor, path);
114                                 }
115                             }
116                         }
117                         else {
118                             traverse(child, childVisitor, path);
119                         }
120                     }
121                 }
122             }
123
124             visitor.onFinishNode(path);
125         }
126     }
127
128     static class ClassTraversalDescriptor {
129
130         Class JavaDoc[] traversableChildTypes;
131         Method JavaDoc[] traversableGetters;
132
133         ClassTraversalDescriptor() {
134
135         }
136
137         ClassTraversalDescriptor(Method JavaDoc[] traversableChildGetters) {
138             this.traversableGetters = traversableChildGetters;
139             this.traversableChildTypes = new Class JavaDoc[traversableChildGetters.length];
140             for (int i = 0; i < traversableChildGetters.length; i++) {
141                 Class JavaDoc type = traversableChildGetters[i].getReturnType();
142                 if (Collection JavaDoc.class.isAssignableFrom(type)) {
143                     type = traversableChildGetters[i]
144                             .getAnnotation(TreeNodeChild.class)
145                             .type();
146
147                     // TODO: andrus, 4/27/2006 - determine type from collection generics
148
// metadata.
149
if (void.class.equals(type)) {
150                         throw new JpaProviderException("No type for collection defined: "
151                                 + traversableChildGetters[i].getName());
152                     }
153                 }
154
155                 traversableChildTypes[i] = type;
156             }
157         }
158
159         Class JavaDoc[] getTraversableChildTypes() {
160             return traversableChildTypes;
161         }
162
163         Object JavaDoc getTraversableChild(Object JavaDoc object, int childIndex) {
164
165             try {
166                 return traversableGetters[childIndex].invoke(object, (Object JavaDoc[]) null);
167             }
168             catch (Exception JavaDoc e) {
169                 throw new JpaProviderException("Error reading traversible property", e);
170             }
171         }
172     }
173 }
174
Popular Tags