    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    }