View Javadoc

1   package org.openrdf.elmo.dynacode;
2   
3   import java.lang.reflect.Method;
4   import java.util.HashSet;
5   import java.util.Set;
6   
7   import javassist.CannotCompileException;
8   import javassist.CtClass;
9   import javassist.CtConstructor;
10  import javassist.CtField;
11  import javassist.CtMethod;
12  import javassist.CtNewMethod;
13  import javassist.Modifier;
14  import javassist.NotFoundException;
15  
16  import org.openrdf.elmo.exceptions.ElmoCompositionException;
17  
18  public class ClassTemplate {
19  
20  	private CodeBuilder cb;
21  
22  	private CtClass cc;
23  
24  	private ClassFactory cp;
25  
26  	protected ClassTemplate(final CtClass cc, final ClassFactory cp) {
27  		this.cc = cc;
28  		this.cp = cp;
29  		this.cb = new CodeBuilder(this, cp) {
30  			@Override
31  			public CodeBuilder end() {
32  				try {
33  					semi();
34  					cc.makeClassInitializer().insertAfter(toString());
35  				} catch (CannotCompileException e) {
36  					throw new ElmoCompositionException(e.getMessage() + " for "
37  							+ toString(), e);
38  				}
39  				clear();
40  				return this;
41  			}
42  		};
43  	}
44  
45  	public void addConstructor(Class<?>[] types, String string)
46  			throws ElmoCompositionException {
47  		try {
48  			CtConstructor con = new CtConstructor(asCtClassArray(types), cc);
49  			con.setBody(string);
50  			cc.addConstructor(con);
51  		} catch (CannotCompileException e) {
52  			throw new ElmoCompositionException(e);
53  		} catch (NotFoundException e) {
54  			throw new ElmoCompositionException(e);
55  		}
56  	}
57  
58  	public void addInterface(Class<?> face) throws ElmoCompositionException {
59  		cc.addInterface(cp.get(face));
60  	}
61  
62  	public CodeBuilder assignStaticField(Class<?> type, final String fieldName)
63  			throws ElmoCompositionException {
64  		try {
65  			CtField field = new CtField(cp.get(type), fieldName, cc);
66  			field.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
67  			cc.addField(field);
68  		} catch (CannotCompileException e) {
69  			throw new ElmoCompositionException(e);
70  		}
71  		CodeBuilder code = new CodeBuilder(this, cp) {
72  			@Override
73  			public CodeBuilder end() {
74  				semi();
75  				return cb.code(toString()).end();
76  			}
77  		};
78  		return code.assign(fieldName);
79  	}
80  
81  	public void createField(Class<?> type, String fieldName)
82  			throws ElmoCompositionException {
83  		try {
84  			CtField field = new CtField(cp.get(type), fieldName, cc);
85  			field.setModifiers(Modifier.PRIVATE);
86  			cc.addField(field);
87  		} catch (CannotCompileException e) {
88  			throw new ElmoCompositionException(e);
89  		}
90  	}
91  
92  	public CodeBuilder createMethod(Class<?> type, String name,
93  			Class<?>... parameters) throws ElmoCompositionException {
94  		CtClass[] exces = new CtClass[] { cp.get(Throwable.class) };
95  		try {
96  			return begin(CtNewMethod.make(cp.get(type), name,
97  					asCtClassArray(parameters), exces, null, cc));
98  		} catch (CannotCompileException e) {
99  			throw new ElmoCompositionException(e);
100 		} catch (NotFoundException e) {
101 			throw new ElmoCompositionException(e);
102 		}
103 	}
104 
105 	public CodeBuilder createTransientMethod(Class<?> type, String name,
106 			Class<?>... parameters) throws ElmoCompositionException {
107 		CtClass[] exces = new CtClass[] { cp.get(Throwable.class) };
108 		try {
109 			CtMethod cm = CtNewMethod.make(cp.get(type), name,
110 					asCtClassArray(parameters), exces, null, cc);
111 			cm.setModifiers(cm.getModifiers() | Modifier.TRANSIENT);
112 			return begin(cm);
113 		} catch (CannotCompileException e) {
114 			throw new ElmoCompositionException(e);
115 		} catch (NotFoundException e) {
116 			throw new ElmoCompositionException(e);
117 		}
118 	}
119 
120 	public CodeBuilder getCodeBuilder() {
121 		return cb;
122 	}
123 
124 	public CtClass getCtClass() {
125 		return cc;
126 	}
127 
128 	public Set<String> getDeclaredFieldNames() {
129 		CtField[] fields = cc.getDeclaredFields();
130 		Set<String> result = new HashSet<String>(fields.length);
131 		for (CtField field : fields) {
132 			result.add(field.getName());
133 		}
134 		return result;
135 	}
136 
137 	public Class<?>[] getInterfaces() throws ElmoCompositionException {
138 		try {
139 			CtClass[] cc1 = cc.getInterfaces();
140 			Class<?>[] result = new Class<?>[cc1.length];
141 			for (int i = 0; i < cc1.length; i++) {
142 				result[i] = cp.getJavaClass(cc1[i]);
143 			}
144 			return result;
145 		} catch (NotFoundException e) {
146 			throw new ElmoCompositionException(e);
147 		} catch (ClassNotFoundException e) {
148 			throw new ElmoCompositionException(e);
149 		}
150 	}
151 
152 	public CodeBuilder overrideMethod(Method method)
153 			throws ElmoCompositionException {
154 		return createMethod(method.getReturnType(), method.getName(), method
155 				.getParameterTypes());
156 	}
157 
158 	@Override
159 	public String toString() {
160 		return cc.getName();
161 	}
162 
163 	private CtClass[] asCtClassArray(Class<?>[] cc) throws NotFoundException {
164 		CtClass[] result = new CtClass[cc.length];
165 		for (int i = 0; i < cc.length; i++) {
166 			result[i] = cp.get(cc[i]);
167 		}
168 		return result;
169 	}
170 
171 	private CodeBuilder begin(final CtMethod cm) {
172 		CodeBuilder cb = new CodeBuilder(this, cp) {
173 			@Override
174 			public CodeBuilder end() {
175 				code("}");
176 				CtClass cc = cm.getDeclaringClass();
177 				try {
178 					int mod = cm.getModifiers();
179 					mod = Modifier.clear(mod, Modifier.ABSTRACT);
180 					mod = Modifier.clear(mod, Modifier.NATIVE);
181 					cm.setModifiers(mod);
182 					cm.setBody(toString());
183 					try {
184 						cc.getDeclaredMethod(cm.getName(), cm
185 								.getParameterTypes());
186 					} catch (NotFoundException e) {
187 						cc.addMethod(cm);
188 					}
189 				} catch (Exception e) {
190 					StringBuilder sb = new StringBuilder();
191 					try {
192 						for (CtClass inter : cc.getInterfaces()) {
193 							sb.append(inter.getSimpleName()).append(" ");
194 						}
195 					} catch (NotFoundException e2) {
196 					}
197 					String sn = cc.getSimpleName();
198 					System.err.println(sn + " implements " + sb);
199 					throw new ElmoCompositionException(e.getMessage() + " for "
200 							+ toString(), e);
201 				}
202 				clear();
203 				return this;
204 			}
205 		};
206 		return cb.code("{");
207 	}
208 
209 }