1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jci.compilers;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24 import java.io.Reader;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
28
29 import org.apache.commons.jci.problems.CompilationProblem;
30 import org.apache.commons.jci.readers.ResourceReader;
31 import org.apache.commons.jci.stores.ResourceStore;
32 import org.apache.commons.jci.utils.ConversionUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.mozilla.javascript.CompilerEnvirons;
36 import org.mozilla.javascript.Context;
37 import org.mozilla.javascript.ErrorReporter;
38 import org.mozilla.javascript.EvaluatorException;
39 import org.mozilla.javascript.GeneratedClassLoader;
40 import org.mozilla.javascript.ImporterTopLevel;
41 import org.mozilla.javascript.JavaScriptException;
42 import org.mozilla.javascript.NativeArray;
43 import org.mozilla.javascript.Scriptable;
44 import org.mozilla.javascript.ScriptableObject;
45 import org.mozilla.javascript.optimizer.ClassCompiler;
46
47
48
49
50 public final class RhinoJavaCompiler extends AbstractJavaCompiler {
51
52 private final Log log = LogFactory.getLog(RhinoJavaCompiler.class);
53
54 private final JavaCompilerSettings defaultSettings;
55
56
57 public RhinoJavaCompiler() {
58 defaultSettings = new RhinoJavaCompilerSettings();
59 }
60
61
62
63
64
65 private final class RhinoCompilingClassLoader extends ClassLoader {
66
67 private final ScriptableObject scope;
68 private final ResourceReader reader;
69 private final ResourceStore store;
70
71 private final Collection<CompilationProblem> problems = new ArrayList<CompilationProblem>();
72
73 private final class ProblemCollector implements ErrorReporter {
74
75 public void error(String pMessage, String pFileName, int pLine, String pScript, int pColumn) {
76
77 final CompilationProblem problem = new RhinoCompilationProblem(pMessage, pFileName, pLine, pScript, pColumn, true);
78
79 if (problemHandler != null) {
80 problemHandler.handle(problem);
81 }
82
83 problems.add(problem);
84 }
85
86 public void warning(String pMessage, String pFileName, int pLine, String pScript, int pColumn) {
87
88 final CompilationProblem problem = new RhinoCompilationProblem(pMessage, pFileName, pLine, pScript, pColumn, false);
89
90 if (problemHandler != null) {
91 problemHandler.handle(problem);
92 }
93
94 problems.add(problem);
95 }
96
97 public EvaluatorException runtimeError(String pMessage, String pFileName, int pLine, String pScript, int pColumn) {
98 return new EvaluatorException(pMessage, pFileName, pLine, pScript, pColumn);
99 }
100 }
101
102 public RhinoCompilingClassLoader( final ResourceReader pReader, final ResourceStore pStore, final ClassLoader pClassLoader) {
103 super(pClassLoader);
104
105 reader = pReader;
106 store = pStore;
107
108 final Context context = Context.enter();
109 scope = new ImporterTopLevel(context);
110 Context.exit();
111 }
112
113 public Collection<CompilationProblem> getProblems() {
114 return problems;
115 }
116
117 @Override
118 protected Class<?> findClass( final String pName ) throws ClassNotFoundException {
119 final Context context = Context.enter();
120 context.setErrorReporter(new ProblemCollector());
121
122 try {
123 return compileClass(context, pName);
124 } catch( EvaluatorException e ) {
125 throw new ClassNotFoundException(e.getMessage(), e);
126 } catch (IOException e) {
127 throw new ClassNotFoundException(e.getMessage(), e);
128 } finally {
129 Context.exit();
130 }
131 }
132
133
134 private Class<?> compileClass( final Context pContext, final String pClassName) throws IOException, ClassNotFoundException {
135
136 Class<?> superclass = null;
137
138 final String pSourceName = pClassName.replace('.', '/') + ".js";
139
140 final Scriptable target = evaluate(pContext, pSourceName);
141
142 final Object baseClassName = ScriptableObject.getProperty(target, "__extends__");
143
144 if (baseClassName instanceof String) {
145 superclass = Class.forName((String) baseClassName);
146 }
147
148 final List<Class<?>> interfaceClasses = new ArrayList<Class<?>>();
149
150 final Object interfaceNames = ScriptableObject.getProperty(target, "__implements__");
151
152 if (interfaceNames instanceof NativeArray) {
153
154 final NativeArray interfaceNameArray = (NativeArray) interfaceNames;
155
156 for (int i=0; i<interfaceNameArray.getLength(); i++) {
157
158 final Object obj = interfaceNameArray.get(i, interfaceNameArray);
159
160 if (obj instanceof String) {
161 interfaceClasses.add(Class.forName((String) obj));
162 }
163 }
164
165 } else if (interfaceNames instanceof String) {
166
167 interfaceClasses.add(Class.forName((String) interfaceNames));
168
169 }
170
171 final Class<?>[] interfaces;
172
173 if (!interfaceClasses.isEmpty()) {
174 interfaces = new Class[interfaceClasses.size()];
175 interfaceClasses.toArray(interfaces);
176 } else {
177
178 interfaces = null;
179 }
180
181 return compileClass(pContext, pSourceName, pClassName, superclass, interfaces);
182
183 }
184
185
186 private Class<?> compileClass( final Context pContext, final String pSourceName, final String pClassName, final Class<?> pSuperClass, final Class<?>[] pInterfaces) {
187
188 final CompilerEnvirons environments = new CompilerEnvirons();
189 environments.initFromContext(pContext);
190 final ClassCompiler compiler = new ClassCompiler(environments);
191
192 if (pSuperClass != null) {
193 compiler.setTargetExtends(pSuperClass);
194 }
195
196 if (pInterfaces != null) {
197 compiler.setTargetImplements(pInterfaces);
198 }
199
200 final byte[] sourceBytes = reader.getBytes(pSourceName);
201
202 final Object[] classes = compiler.compileToClassFiles(new String(sourceBytes), getName(pSourceName), 1, pClassName);
203
204 final GeneratedClassLoader loader = pContext.createClassLoader(pContext.getApplicationClassLoader());
205
206 Class<?> clazz = null;
207
208 for (int i = 0; i < classes.length; i += 2) {
209
210 final String clazzName = (String) classes[i];
211 final byte[] clazzBytes = (byte[]) classes[i+1];
212
213 store.write(clazzName.replace('.', '/') + ".class", clazzBytes);
214
215 Class<?> c = loader.defineClass(clazzName, clazzBytes);
216 loader.linkClass(c);
217
218 if (i == 0) {
219 clazz = c;
220 }
221
222 }
223
224 return clazz;
225 }
226
227 private String getName(String s) {
228 final int i = s.lastIndexOf('/');
229 if (i < 0) {
230 return s;
231 }
232
233 return s.substring(i + 1);
234 }
235
236 private Scriptable evaluate( final Context pContext, final String pSourceName) throws JavaScriptException, IOException {
237
238 if (!reader.isAvailable(pSourceName)) {
239 throw new FileNotFoundException("File " + pSourceName + " not found");
240 }
241
242 final Scriptable target = pContext.newObject(scope);
243
244 final byte[] sourceBytes = reader.getBytes(pSourceName);
245
246 final Reader reader = new InputStreamReader(new ByteArrayInputStream(sourceBytes));
247
248 pContext.evaluateReader(target, reader, getName(pSourceName), 1, null);
249
250 return target;
251 }
252
253 }
254
255
256 public CompilationResult compile( final String[] pResourcePaths, final ResourceReader pReader, final ResourceStore pStore, final ClassLoader pClassLoader, final JavaCompilerSettings pSettings ) {
257
258 final RhinoCompilingClassLoader cl = new RhinoCompilingClassLoader(pReader, pStore, pClassLoader);
259
260 for (int i = 0; i < pResourcePaths.length; i++) {
261 log.debug("compiling " + pResourcePaths[i]);
262
263 final String clazzName = ConversionUtils.convertResourceToClassName(pResourcePaths[i]);
264 try {
265 cl.loadClass(clazzName);
266 } catch (ClassNotFoundException e) {
267 }
268 }
269
270 final Collection<CompilationProblem> problems = cl.getProblems();
271 final CompilationProblem[] result = new CompilationProblem[problems.size()];
272 problems.toArray(result);
273 return new CompilationResult(result);
274 }
275
276
277 public JavaCompilerSettings createDefaultSettings() {
278 return defaultSettings;
279 }
280
281 }