Java tutorial
/** * Copyright 2011 meltmedia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xchain.framework.jsl; import org.apache.commons.jci.compilers.JavaCompilerFactory; import org.apache.commons.jci.compilers.JavaCompiler; import org.apache.commons.jci.compilers.JavaCompilerSettings; import org.apache.commons.jci.compilers.CompilationResult; import org.apache.commons.jci.problems.CompilationProblem; import org.apache.commons.jci.readers.ResourceReader; import org.apache.commons.jci.readers.MemoryResourceReader; import org.apache.commons.jci.stores.ResourceStore; import org.apache.commons.jci.stores.MemoryResourceStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.io.UnsupportedEncodingException; import org.xml.sax.SAXException; /** * @author Christian Trimble * @author Josh Kennedy */ public class TemplateCompiler { private static Logger log = LoggerFactory.getLogger(TemplateCompiler.class); public static final String SOURCE_VERSION = "1.5"; public static final String SOURCE_ENCODING = "UTF-8"; public static final String TARGET_VERSION = "1.5"; /** The class loader for the catalog. */ private TemplateClassLoader templateClassLoader; /** The compiler that we will use for creating classes. */ private JavaCompiler compiler; /** The resource reader where source files will be stored. */ private WrappedResourceReader resourceReader; /** The settings for the compiler. */ private JavaCompilerSettings settings; public void init(ClassLoader classLoader) { this.templateClassLoader = new TemplateClassLoader(classLoader); resourceReader = new WrappedResourceReader(new MemoryResourceReader(), templateClassLoader); settings = new JavaCompilerSettings(); settings.setSourceVersion(SOURCE_VERSION); settings.setSourceEncoding(SOURCE_ENCODING); settings.setTargetVersion(TARGET_VERSION); compiler = new JavaCompilerFactory().createCompiler("eclipse"); } /** * Compiles the source result. * * @throws SAXException if there is a compilation error in the source file. */ public Class compileTemplate(SourceResult result) throws SAXException { // add the resource to the reader. try { resourceReader.add(result.getSourceResourceName(), result.getSource().getBytes(SOURCE_ENCODING)); } catch (UnsupportedEncodingException uee) { throw new SAXException("Could not build source in the encoding '" + SOURCE_ENCODING + "'.", uee); } // create the resource store. ResourceStore resourceStore = new MemoryResourceStore(); // compile the result. CompilationResult compilationResult = compiler.compile(new String[] { result.getSourceResourceName() }, resourceReader, resourceStore, templateClassLoader, settings); // handle any errors. if (compilationResult.getErrors().length > 0) { if (log.isDebugEnabled()) { log.debug("Source that would not complile:\n" + result.getSource()); for (CompilationProblem error : compilationResult.getErrors()) { log.debug("Error (" + error.getStartLine() + ", " + error.getStartColumn() + "):" + error.getMessage()); } } // TODO: Make this message better. StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Could not compile template source. Errors:\n"); for (CompilationProblem error : compilationResult.getErrors()) { stringBuilder.append("(" + error.getStartLine() + ", " + error.getStartColumn() + "):" + error.getMessage() + "\n"); } throw new SAXException(stringBuilder.toString()); } // handle any errors. if (log.isDebugEnabled()) { for (CompilationProblem warning : compilationResult.getWarnings()) { log.debug("Compilation warning(" + warning.getStartLine() + ", " + warning.getStartColumn() + "):" + warning.getMessage()); } } byte[] compiledBytes = resourceStore.read(result.getClassResourceName()); templateClassLoader.publicDefineClass(result.getClassName(), compiledBytes, 0, compiledBytes.length); Class templateClass = null; try { templateClass = templateClassLoader.loadClass(result.getClassName()); } catch (Exception e) { throw new SAXException("Could not load the class '" + result.getClassName() + "'.", e); } return templateClass; } private class TemplateClassLoader extends ClassLoader { public TemplateClassLoader(ClassLoader parent) { super(parent); } public void publicDefineClass(String name, byte[] b, int off, int len) throws ClassFormatError, IndexOutOfBoundsException, SecurityException { this.defineClass(name, b, off, len); } } public static class WrappedResourceReader implements ResourceReader { protected MemoryResourceReader wrapped; protected ClassLoader classLoader; public WrappedResourceReader(MemoryResourceReader wrapped, ClassLoader classLoader) { this.wrapped = wrapped; this.classLoader = classLoader; } public void add(String name, byte[] data) { wrapped.add(name, data); } public byte[] getBytes(String name) { byte[] result = wrapped.getBytes(name); if (result == null) { try { int bufferSize = 0; byte[] buffer = new byte[10000]; int read = 0; InputStream source = classLoader.getResourceAsStream(name); while ((read = source.read(buffer, bufferSize, buffer.length)) != -1) { bufferSize += read; if (bufferSize >= buffer.length) { break; } } result = new byte[bufferSize]; for (int i = 0; i < bufferSize; i++) { result[i] = buffer[i]; } } catch (Exception e) { e.printStackTrace(); return null; } } return result; } public boolean isAvailable(String name) { boolean result = wrapped.isAvailable(name); if (!result) { result = (classLoader.getResource(name) != null); } return result; } } }