1 package org.kite9.diagram.builders;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Modifier;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Set;
11
12 import org.kite9.framework.model.MemberHandle;
13 import org.kite9.framework.model.ProjectModel;
14
15 public class ClassBuilder extends AbstractAnnotatedElementBuilder<Class<?>> {
16
17 public ClassBuilder(List<Tie<? extends Object, Class<?>>> forX, ProjectModel model) {
18 super(forX, model);
19 }
20
21 public ClassBuilder showVisibility(Format f) {
22 for (Class<?> c : allElements) {
23 if (Modifier.isPublic(c.getModifiers())) {
24 f.write(c, HasRelationship.VISIBILITY, new JavaModifier("public"));
25 } else if (Modifier.isPrivate(c.getModifiers())) {
26 f.write(c, HasRelationship.VISIBILITY, new JavaModifier("private"));
27 } else if (Modifier.isProtected(c.getModifiers())) {
28 f.write(c, HasRelationship.VISIBILITY, new JavaModifier("protected"));
29 }
30 }
31 return this;
32 }
33
34 public ClassBuilder showStatic(Format f) {
35 for (Class<?> c : allElements) {
36 if (c.getEnclosingClass() != null) {
37
38 if (Modifier.isStatic(c.getModifiers())) {
39 f.write(c, HasRelationship.MODIFIER, new JavaModifier("static"));
40 }
41 }
42 }
43 return this;
44 }
45
46 public ClassBuilder show(Format f) {
47 return (ClassBuilder) super.show(f);
48 }
49
50 public ClassBuilder showFinal(Format f) {
51 for (Class<?> c : allElements) {
52 if (Modifier.isFinal(c.getModifiers())) {
53 f.write(c, HasRelationship.MODIFIER, new JavaModifier("final"));
54 }
55 }
56 return this;
57 }
58
59 /***
60 * Creates a helper to allow you to manipulate the superclasses of the
61 * classes that this builder manages.
62 *
63 * @param f
64 * An optional filter to reduce the number of interfaces being
65 * considered.
66 */
67 public ClassBuilder withSuperClasses(Filter<? super Class<?>> f) {
68 return new ClassBuilder(packContent(allElements, f, new ClassContentSelector<Class<?>>() {
69
70 public Class<?>[] contents(Class<?> c) {
71 return new Class<?>[] { c.getSuperclass() };
72 }
73
74 public Set<? extends Class<?>> traverse(Class<?> c) {
75 throw new UnsupportedOperationException("Not implemented for superClass selector");
76 }
77
78 }, false, Relationship.EXTENDS), model);
79 }
80
81 /***
82 * Creates a helper to allow you to manipulate the interfaces this class
83 * implements or extends
84 *
85 * @param f
86 * An optional filter to reduce the number of interfaces being
87 * considered.
88 *
89 * @param traverse
90 * Set to true if you want interfaces declared by superclasses
91 * and superinterfaces too
92 */
93 public ClassBuilder withInterfaces(Filter<? super Class<?>> f, boolean traverse) {
94 return new ClassBuilder(packContent(allElements, f, new ClassContentSelector<Class<?>>() {
95
96 public Class<?>[] contents(Class<?> c) {
97 return c.getInterfaces();
98 }
99
100 public Set<? extends Class<?>> traverse(Class<?> c) {
101 return superTraverse(c);
102 }
103
104 }, traverse, Relationship.IMPLEMENTS), model);
105 }
106
107 /***
108 * Creates a helper to allow you to manipulate methods on this class.
109 *
110 * @param f
111 * An optional filter to reduce the number of methods being
112 * considered.
113 *
114 * @oparam traverse Set to true if you want declarations from superclasses
115 * and superinterfaces too
116 */
117 public MethodBuilder withMethods(Filter<? super Method> f, boolean traverse) {
118 return new MethodBuilder(packContent(allElements, f, new ClassContentSelector<Method>() {
119 public Method[] contents(Class<?> c) {
120 return c.getDeclaredMethods();
121 }
122
123 public Set<? extends Class<?>> traverse(Class<?> c) {
124 return superTraverse(c);
125 }
126
127 }, traverse, HasRelationship.METHOD), model);
128 }
129
130 /***
131 * Creates a helper to allow you to manipulate inner classes on this class.
132 *
133 * @param f
134 * An optional filter to reduce the number of methods being
135 * considered.
136 *
137 * @oparam traverse Set to true if you want declarations from superclasses
138 * too
139 */
140 public ClassBuilder withInnerClasses(Filter<? super Class<?>> f, boolean traverse) {
141 return new ClassBuilder(packContent(allElements, f, new ClassContentSelector<Class<?>>() {
142 public Class<?>[] contents(Class<?> c) {
143 return c.getDeclaredClasses();
144 }
145
146 public Set<? extends Class<?>> traverse(Class<?> c) {
147 return Collections.singleton(c.getSuperclass());
148 }
149 }, traverse, HasRelationship.INNER_CLASS), model);
150 }
151
152 /***
153 * Creates a helper to allow you to manipulate subclasses within the project
154 * of the current class or classes.
155 *
156 * @param f
157 * Optional filter to reduce the number of returned classes
158 * @param traverse
159 * set to true if you want the entire subclass tree (i.e.
160 * sub-sub-classes etc)s
161 * @return
162 */
163 public ClassBuilder withSubClasses(Filter<? super Class<?>> f, boolean traverse) {
164 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
165 return new ClassBuilder(packContent(allElements, f, new ClassContentSelector<Class<?>>() {
166 public Class<?>[] contents(Class<?> c) {
167 return MemberHandle.hydrateClasses(model.getSubclasses(MemberHandle.convertClassName(c)), cl).toArray(
168 new Class<?>[] {});
169 }
170
171 public Set<Class<?>> traverse(Class<?> c) {
172 return MemberHandle.hydrateClasses(model.getSubclasses(MemberHandle.convertClassName(c)), cl);
173 }
174 }, traverse, Relationship.EXTENDS), model);
175
176 }
177
178 protected interface ClassContentSelector<T> extends ContentSelector<T, Class<?>> {
179
180 }
181
182 /***
183 * Creates a helper to allow you to manipulate fields on this class.
184 *
185 * @param f
186 * An optional filter to reduce the number of methods being
187 * considered.
188 * @oparam traverse Set to true if you want declarations from superclasses
189 * too
190 */
191 public FieldBuilder withFields(Filter<? super Field> f, boolean traverse) {
192 return new FieldBuilder(packContent(allElements, f, new ClassContentSelector<Field>() {
193 public Field[] contents(Class<?> c) {
194 return c.getDeclaredFields();
195 }
196
197 public Set<? extends Class<?>> traverse(Class<?> c) {
198 return Collections.singleton(c.getSuperclass());
199 }
200 }, traverse, HasRelationship.FIELD), model);
201 }
202
203 private Set<? extends Class<?>> superTraverse(Class<?> c) {
204 LinkedHashSet<Class<?>> out = new LinkedHashSet<Class<?>>();
205 if (c.getSuperclass() != null)
206 out.add(c.getSuperclass());
207 for (int i = 0; i < c.getInterfaces().length; i++) {
208 out.add(c.getInterfaces()[i]);
209 }
210 return out;
211 }
212
213 /***
214 * This is a helper method used to create a list of ties correctly, by
215 * applying a ContentSelector.
216 */
217 protected <Y> List<Tie<? extends Object, Y>> packContent(Set<? extends Class<?>> allElements, Filter<? super Y> f,
218 ClassContentSelector<Y> ccs, boolean traverse, Relationship r) {
219 List<Tie<? extends Object, Y>> out = new ArrayList<Tie<? extends Object, Y>>();
220 packContentInner(allElements, f, ccs, traverse, r, out);
221 return out;
222 }
223
224 protected <Y> void packContentInner(Set<? extends Class<?>> allElements, Filter<? super Y> f,
225 ClassContentSelector<Y> ccs, boolean traverse, Relationship r, List<Tie<? extends Object, Y>> out) {
226 for (Class<?> orig : allElements) {
227 Class<?> c = orig;
228 if (model.withinModel(MemberHandle.convertClassName(c))) {
229 for (Y Y : ccs.contents(c)) {
230 if ((f == null) || (f.accept(Y))) {
231 out.add(new Tie<Object, Y>(orig, r, Y));
232 }
233 }
234
235 if (traverse) {
236 packContentInner(ccs.traverse(c), f, ccs, traverse, r, out);
237 }
238 }
239 }
240 }
241
242 @Override
243 public ClassBuilder reduce(Filter<? super Class<?>> f) {
244 return new ClassBuilder(reduceInner(f), model);
245 }
246
247 /***
248 * Assumes that the classes in this builder are annotations, and provides
249 * you with a classbuilder of classes that have declared these annotations.
250 */
251 public ClassBuilder withAnnotatedClasses(Filter<? super Class<?>> f) {
252 final ClassLoader cl = Thread.currentThread().getContextClassLoader();
253 return new ClassBuilder(packContent(allElements, f, new ClassContentSelector<Class<?>>() {
254 public Class<?>[] contents(Class<?> c) {
255 Set<String> classNames = model.getClassesWithAnnotation(MemberHandle.convertClassName(c));
256 Class<?>[] out = new Class<?>[classNames.size()];
257 int i = 0;
258 for (String name : classNames) {
259 out[i++] = MemberHandle.hydrateClass(name, cl);
260 }
261 return out;
262 }
263
264 public Set<? extends Class<?>> traverse(Class<?> c) {
265 return Collections.singleton(c.getSuperclass());
266 }
267 }, false, HasRelationship.ANNOTATION_OF), model);
268 }
269
270 }