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, 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  			return cb.assign(fieldName);
69  		} catch (CannotCompileException e) {
70  			throw new ElmoCompositionException(e);
71  		}
72  	}
73  
74  	public void createField(Class<?> type, String fieldName)
75  			throws ElmoCompositionException {
76  		try {
77  			CtField field = new CtField(cp.get(type), fieldName, cc);
78  			field.setModifiers(Modifier.PRIVATE);
79  			cc.addField(field);
80  		} catch (CannotCompileException e) {
81  			throw new ElmoCompositionException(e);
82  		}
83  	}
84  
85  	public CodeBuilder createMethod(Class<?> type, String name,
86  			Class<?>... parameters) throws ElmoCompositionException {
87  		CtClass[] exces = new CtClass[] { cp.get(Throwable.class) };
88  		try {
89  			return begin(CtNewMethod.make(cp.get(type), name,
90  					asCtClassArray(parameters), exces, null, cc));
91  		} catch (CannotCompileException e) {
92  			throw new ElmoCompositionException(e);
93  		} catch (NotFoundException e) {
94  			throw new ElmoCompositionException(e);
95  		}
96  	}
97  
98  	public CodeBuilder getCodeBuilder() {
99  		return cb;
100 	}
101 
102 	public CtClass getCtClass() {
103 		return cc;
104 	}
105 
106 	public Set<String> getDeclaredFieldNames() {
107 		CtField[] fields = cc.getDeclaredFields();
108 		Set<String> result = new HashSet<String>(fields.length);
109 		for (CtField field : fields) {
110 			result.add(field.getName());
111 		}
112 		return result;
113 	}
114 
115 	public Class<?>[] getInterfaces() throws ElmoCompositionException {
116 		try {
117 			CtClass[] cc1 = cc.getInterfaces();
118 			Class<?>[] result = new Class<?>[cc1.length];
119 			for (int i = 0; i < cc1.length; i++) {
120 				result[i] = cp.getJavaClass(cc1[i]);
121 			}
122 			return result;
123 		} catch (NotFoundException e) {
124 			throw new ElmoCompositionException(e);
125 		} catch (ClassNotFoundException e) {
126 			throw new ElmoCompositionException(e);
127 		}
128 	}
129 
130 	public CodeBuilder overrideMethod(Method method)
131 			throws ElmoCompositionException {
132 		return createMethod(method.getReturnType(), method.getName(), method
133 				.getParameterTypes());
134 	}
135 
136 	@Override
137 	public String toString() {
138 		return cc.getName();
139 	}
140 
141 	private CtClass[] asCtClassArray(Class<?>[] cc) throws NotFoundException {
142 		CtClass[] result = new CtClass[cc.length];
143 		for (int i = 0; i < cc.length; i++) {
144 			result[i] = cp.get(cc[i]);
145 		}
146 		return result;
147 	}
148 
149 	private CodeBuilder begin(final CtMethod cm) {
150 		CodeBuilder cb = new CodeBuilder(this, cp) {
151 			@Override
152 			public CodeBuilder end() {
153 				code("}");
154 				CtClass cc = cm.getDeclaringClass();
155 				try {
156 					int mod = cm.getModifiers();
157 					mod = Modifier.clear(mod, Modifier.ABSTRACT);
158 					mod = Modifier.clear(mod, Modifier.NATIVE);
159 					cm.setModifiers(mod);
160 					cm.setBody(toString());
161 					try {
162 						cc.getDeclaredMethod(cm.getName(), cm
163 								.getParameterTypes());
164 					} catch (NotFoundException e) {
165 						cc.addMethod(cm);
166 					}
167 				} catch (Exception e) {
168 					StringBuilder sb = new StringBuilder();
169 					try {
170 						for (CtClass inter : cc.getInterfaces()) {
171 							sb.append(inter.getSimpleName()).append(" ");
172 						}
173 					} catch (NotFoundException e2) {
174 					}
175 					String sn = cc.getSimpleName();
176 					System.err.println(sn + " implements " + sb);
177 					throw new ElmoCompositionException(e.getMessage() + " for "
178 							+ toString(), e);
179 				}
180 				clear();
181 				return this;
182 			}
183 		};
184 		return cb.code("{");
185 	}
186 
187 }