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 }