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.commons.compiler.CompileException;
34  import org.codehaus.commons.compiler.LocatedException;
35  import org.codehaus.commons.compiler.Location;
36  import org.codehaus.janino.ClassLoaderIClassLoader;
37  import org.codehaus.janino.Compiler;
38  import org.codehaus.janino.FilterWarningHandler;
39  import org.codehaus.janino.UnitCompiler.ErrorHandler;
40  import org.codehaus.janino.WarningHandler;
41  import org.codehaus.janino.util.StringPattern;
42  import org.codehaus.janino.util.resource.Resource;
43  import org.codehaus.janino.util.resource.ResourceCreator;
44  import org.codehaus.janino.util.resource.ResourceFinder;
45  
46  /**
47   * @author tcurdt
48   */
49  public final class JaninoJavaCompiler extends AbstractJavaCompiler {
50  
51      private final Log log = LogFactory.getLog(JaninoJavaCompiler.class);
52  
53      private final JaninoJavaCompilerSettings defaultSettings;
54  
55      public JaninoJavaCompiler() {
56      	this(new JaninoJavaCompilerSettings());
57      }
58      
59      public JaninoJavaCompiler( final JaninoJavaCompilerSettings pSettings ) {
60      	defaultSettings = pSettings;
61      }
62      
63      private final static class JciResource implements Resource {
64  
65      	private final String name;
66      	private final byte[] bytes;
67      	
68      	public JciResource( final String pName, final byte[] pBytes ) {
69      		name = pName;
70      		bytes = pBytes;
71      	}
72      	
73  		public String getFileName() {
74  			return name;
75  		}
76  
77  		public long lastModified() {
78  			return 0;
79  		}
80  
81  		public InputStream open() throws IOException {
82  			return new ByteArrayInputStream(bytes);
83  		}
84      }
85  
86      private final static class JciOutputStream extends ByteArrayOutputStream {
87  
88      	private final String name;
89      	private final ResourceStore store;
90  
91      	public JciOutputStream( final String pName, final ResourceStore pStore ) {
92      		name = pName;
93      		store = pStore;
94      	}
95  
96  		@Override
97          public void close() throws IOException {
98  			super.close();
99  
100 			final byte[] bytes = toByteArray();
101 			
102 			store.write(name, bytes);
103 		}
104     }
105     
106     public CompilationResult compile( final String[] pSourceNames, final ResourceReader pResourceReader, final ResourceStore pStore, final ClassLoader pClassLoader, final JavaCompilerSettings pSettings ) {
107 
108     	final Collection<CompilationProblem> problems = new ArrayList<CompilationProblem>();
109     	
110     	final StringPattern[] pattern = StringPattern.PATTERNS_NONE;
111 
112     	final Compiler compiler = new Compiler(
113     			new ResourceFinder() {
114 					@Override
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 					@Override
131                     public Resource findResource( final String pResourceName ) {
132 						final byte[] bytes = pStore.read(pResourceName);
133 						
134 						if (bytes == null) {
135 							log.debug("failed to find " + pResourceName);
136 							return null;
137 						}
138 
139 						log.debug("reading " + pResourceName + " (" + bytes.length + ")");
140 						
141 						return new JciResource(pResourceName, bytes);
142 					}    		
143     			},
144     			new ResourceCreator() {
145 					public OutputStream createResource( final String pResourceName ) throws IOException {
146 						return new JciOutputStream(pResourceName, pStore);
147 					}
148 
149 					public boolean deleteResource( final String pResourceName ) {
150 						log.debug("removing " + pResourceName);
151 
152 						pStore.remove(pResourceName);
153 						return true;
154 					}    				
155     			},
156     			pSettings.getSourceEncoding(),
157     			false,
158     			pSettings.isDebug(),
159                 pSettings.isDebug(),
160                 pSettings.isDebug(),
161     			new FilterWarningHandler(pattern, new WarningHandler() {
162 						public void handleWarning( final String pHandle, final String pMessage, final Location pLocation ) {
163 							final CompilationProblem problem = new JaninoCompilationProblem(pLocation.getFileName(), pLocation, pMessage, false);
164 							if (problemHandler != null) {
165 								problemHandler.handle(problem);
166 							}
167 							problems.add(problem);
168 						}    		
169 			    	})    			
170     			);
171     	
172     	
173     	compiler.setCompileErrorHandler(new ErrorHandler() {
174 			public void handleError( final String pMessage, final Location pLocation ) throws CompileException {
175 				final CompilationProblem problem = new JaninoCompilationProblem(pLocation.getFileName(), pLocation, pMessage, true);
176 				if (problemHandler != null) {
177 					problemHandler.handle(problem);
178 				}
179 				problems.add(problem);
180 			}
181     	});
182     	
183 
184     	final Resource[] resources = new Resource[pSourceNames.length];
185         for (int i = 0; i < pSourceNames.length; i++) {
186             log.debug("compiling " + pSourceNames[i]);
187             final byte[] source = pResourceReader.getBytes(pSourceNames[i]);
188             resources[i] = new JciResource(pSourceNames[i], source);
189         }
190         
191         try {
192             compiler.compile(resources);
193         } catch ( LocatedException e ) {
194             problems.add(new JaninoCompilationProblem(e));
195         } catch ( IOException e ) {
196             // low level problems reading or writing bytes
197         	log.error("this error should have been cought before", e);
198         }        
199         final CompilationProblem[] result = new CompilationProblem[problems.size()];
200         problems.toArray(result);
201         return new CompilationResult(result);
202     }
203 
204     public JavaCompilerSettings createDefaultSettings() {
205         return new JaninoJavaCompilerSettings(defaultSettings);
206     }
207     
208 }