View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jci.compilers;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
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.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  import org.codehaus.janino.ClassLoaderIClassLoader;
34  import org.codehaus.janino.CompileException;
35  import org.codehaus.janino.Compiler;
36  import org.codehaus.janino.DebuggingInformation;
37  import org.codehaus.janino.FilterWarningHandler;
38  import org.codehaus.janino.Location;
39  import org.codehaus.janino.WarningHandler;
40  import org.codehaus.janino.Parser.ParseException;
41  import org.codehaus.janino.Scanner.ScanException;
42  import org.codehaus.janino.UnitCompiler.ErrorHandler;
43  import org.codehaus.janino.util.StringPattern;
44  import org.codehaus.janino.util.resource.Resource;
45  import org.codehaus.janino.util.resource.ResourceCreator;
46  import org.codehaus.janino.util.resource.ResourceFinder;
47  
48  /**
49   * @author tcurdt
50   */
51  public final class JaninoJavaCompiler extends AbstractJavaCompiler {
52  
53      private final Log log = LogFactory.getLog(JaninoJavaCompiler.class);
54  
55      private final JaninoJavaCompilerSettings defaultSettings;
56  
57      public JaninoJavaCompiler() {
58      	this(new JaninoJavaCompilerSettings());
59      }
60      
61      public JaninoJavaCompiler( final JaninoJavaCompilerSettings pSettings ) {
62      	defaultSettings = pSettings;
63      }
64      
65      private final static class JciResource implements Resource {
66  
67      	private final String name;
68      	private final byte[] bytes;
69      	
70      	public JciResource( final String pName, final byte[] pBytes ) {
71      		name = pName;
72      		bytes = pBytes;
73      	}
74      	
75  		public String getFileName() {
76  			return name;
77  		}
78  
79  		public long lastModified() {
80  			return 0;
81  		}
82  
83  		public InputStream open() throws IOException {
84  			return new ByteArrayInputStream(bytes);
85  		}
86      }
87  
88      private final static class JciOutputStream extends ByteArrayOutputStream {
89  
90      	private final String name;
91      	private final ResourceStore store;
92  
93      	public JciOutputStream( final String pName, final ResourceStore pStore ) {
94      		name = pName;
95      		store = pStore;
96      	}
97  
98  		public void close() throws IOException {
99  			super.close();
100 
101 			final byte[] bytes = toByteArray();
102 			
103 			store.write(name, bytes);
104 		}
105     }
106     
107     public CompilationResult compile( final String[] pSourceNames, final ResourceReader pResourceReader, final ResourceStore pStore, final ClassLoader pClassLoader, final JavaCompilerSettings pSettings ) {
108 
109     	final Collection problems = new ArrayList();
110     	
111     	final StringPattern[] pattern = StringPattern.PATTERNS_NONE;
112 
113     	final Compiler compiler = new Compiler(
114     			new ResourceFinder() {
115 					public Resource findResource( final String pSourceName ) {
116 						final byte[] bytes = pResourceReader.getBytes(pSourceName);
117 						
118 						if (bytes == null) {
119 							log.debug("failed to find source " + pSourceName);
120 							return null;
121 						}
122 						
123 						log.debug("reading " + pSourceName + " (" + bytes.length + ")");
124 						
125 						return new JciResource(pSourceName, bytes);
126 					}    		
127     			},
128     			new ClassLoaderIClassLoader(pClassLoader),
129     			new ResourceFinder() {
130 					public Resource findResource( final String pResourceName ) {
131 						final byte[] bytes = pStore.read(pResourceName);
132 						
133 						if (bytes == null) {
134 							log.debug("failed to find " + pResourceName);
135 							return null;
136 						}
137 
138 						log.debug("reading " + pResourceName + " (" + bytes.length + ")");
139 						
140 						return new JciResource(pResourceName, bytes);
141 					}    		
142     			},
143     			new ResourceCreator() {
144 					public OutputStream createResource( final String pResourceName ) throws IOException {
145 						return new JciOutputStream(pResourceName, pStore);
146 					}
147 
148 					public boolean deleteResource( final String pResourceName ) {
149 						log.debug("removing " + pResourceName);
150 
151 						pStore.remove(pResourceName);
152 						return true;
153 					}    				
154     			},
155     			pSettings.getSourceEncoding(),
156     			false,
157     			pSettings.isDebug()?DebuggingInformation.ALL:DebuggingInformation.NONE,
158     			new FilterWarningHandler(pattern, new WarningHandler() {
159 						public void handleWarning( final String pHandle, final String pMessage, final Location pLocation ) {
160 							final CompilationProblem problem = new JaninoCompilationProblem(pLocation.getFileName(), pLocation, pMessage, false);
161 							if (problemHandler != null) {
162 								problemHandler.handle(problem);
163 							}
164 							problems.add(problem);
165 						}    		
166 			    	})    			
167     			);
168     	
169     	
170     	compiler.setCompileErrorHandler(new ErrorHandler() {
171 			public void handleError( final String pMessage, final Location pLocation ) throws CompileException {
172 				final CompilationProblem problem = new JaninoCompilationProblem(pLocation.getFileName(), pLocation, pMessage, true);
173 				if (problemHandler != null) {
174 					problemHandler.handle(problem);
175 				}
176 				problems.add(problem);
177 			}
178     	});
179     	
180 
181     	final Resource[] resources = new Resource[pSourceNames.length];
182         for (int i = 0; i < pSourceNames.length; i++) {
183             log.debug("compiling " + pSourceNames[i]);
184             final byte[] source = pResourceReader.getBytes(pSourceNames[i]);
185             resources[i] = new JciResource(pSourceNames[i], source);
186         }
187         
188         try {
189             compiler.compile(resources);
190         } catch ( ScanException e ) {
191             problems.add(new JaninoCompilationProblem(e));
192         } catch ( ParseException e ) {
193             problems.add(new JaninoCompilationProblem(e)); 
194         } catch ( IOException e ) {
195             // I'm hoping the existing compiler problems handler catches these
196         	log.error("this error should have been cought before", e);
197         } catch ( CompileException e ) {
198             // I'm hoping the existing compiler problems handler catches these
199         	log.error("this error should have been cought before", e);
200         }        
201         final CompilationProblem[] result = new CompilationProblem[problems.size()];
202         problems.toArray(result);
203         return new CompilationResult(result);
204     }
205 
206     public JavaCompilerSettings createDefaultSettings() {
207         return new JaninoJavaCompilerSettings(defaultSettings);
208     }
209     
210 }