001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.jci.compilers;
019    
020    import java.io.ByteArrayInputStream;
021    import java.io.ByteArrayOutputStream;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.OutputStream;
025    import java.util.ArrayList;
026    import java.util.Collection;
027    
028    import org.apache.commons.jci.problems.CompilationProblem;
029    import org.apache.commons.jci.readers.ResourceReader;
030    import org.apache.commons.jci.stores.ResourceStore;
031    import org.apache.commons.logging.Log;
032    import org.apache.commons.logging.LogFactory;
033    import org.codehaus.commons.compiler.CompileException;
034    import org.codehaus.commons.compiler.LocatedException;
035    import org.codehaus.commons.compiler.Location;
036    import org.codehaus.janino.ClassLoaderIClassLoader;
037    import org.codehaus.janino.Compiler;
038    import org.codehaus.janino.FilterWarningHandler;
039    import org.codehaus.janino.UnitCompiler.ErrorHandler;
040    import org.codehaus.janino.WarningHandler;
041    import org.codehaus.janino.util.StringPattern;
042    import org.codehaus.janino.util.resource.Resource;
043    import org.codehaus.janino.util.resource.ResourceCreator;
044    import org.codehaus.janino.util.resource.ResourceFinder;
045    
046    /**
047     * @author tcurdt
048     */
049    public final class JaninoJavaCompiler extends AbstractJavaCompiler {
050    
051        private final Log log = LogFactory.getLog(JaninoJavaCompiler.class);
052    
053        private final JaninoJavaCompilerSettings defaultSettings;
054    
055        public JaninoJavaCompiler() {
056            this(new JaninoJavaCompilerSettings());
057        }
058        
059        public JaninoJavaCompiler( final JaninoJavaCompilerSettings pSettings ) {
060            defaultSettings = pSettings;
061        }
062        
063        private final static class JciResource implements Resource {
064    
065            private final String name;
066            private final byte[] bytes;
067            
068            public JciResource( final String pName, final byte[] pBytes ) {
069                    name = pName;
070                    bytes = pBytes;
071            }
072            
073                    public String getFileName() {
074                            return name;
075                    }
076    
077                    public long lastModified() {
078                            return 0;
079                    }
080    
081                    public InputStream open() throws IOException {
082                            return new ByteArrayInputStream(bytes);
083                    }
084        }
085    
086        private final static class JciOutputStream extends ByteArrayOutputStream {
087    
088            private final String name;
089            private final ResourceStore store;
090    
091            public JciOutputStream( final String pName, final ResourceStore pStore ) {
092                    name = pName;
093                    store = pStore;
094            }
095    
096                    @Override
097            public void close() throws IOException {
098                            super.close();
099    
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    }