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