View Javadoc

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  				// inner class
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 }