Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id F1E86200D41 for ; Tue, 7 Nov 2017 11:03:38 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id F095A160C0C; Tue, 7 Nov 2017 10:03:38 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 5851C160C02 for ; Tue, 7 Nov 2017 11:03:36 +0100 (CET) Received: (qmail 43225 invoked by uid 500); 7 Nov 2017 10:03:35 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 42975 invoked by uid 99); 7 Nov 2017 10:03:35 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Nov 2017 10:03:35 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id A205C87B1D; Tue, 7 Nov 2017 10:03:34 +0000 (UTC) Date: Tue, 07 Nov 2017 10:03:35 +0000 To: "commits@sling.apache.org" Subject: [sling-org-apache-sling-scripting-java] 01/41: SLING-619 Add a scripting engine for java servlets. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: rombert@apache.org In-Reply-To: <151004901395.9395.4867042724287205373@gitbox.apache.org> References: <151004901395.9395.4867042724287205373@gitbox.apache.org> X-Git-Host: gitbox.apache.org X-Git-Repo: sling-org-apache-sling-scripting-java X-Git-Refname: refs/tags/org.apache.sling.scripting.java-1.0.0 X-Git-Reftype: annotated tag X-Git-Rev: b709f596557bf0799f3220c7bb761a95ca57da5d X-Git-NotificationType: diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated Message-Id: <20171107100334.A205C87B1D@gitbox.apache.org> archived-at: Tue, 07 Nov 2017 10:03:39 -0000 This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.scripting.java-1.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-java.git commit b709f596557bf0799f3220c7bb761a95ca57da5d Author: Carsten Ziegeler AuthorDate: Wed Aug 20 15:22:10 2008 +0000 SLING-619 Add a scripting engine for java servlets. git-svn-id: https://svn.apache.org/repos/asf/incubator/sling/trunk/scripting/java@687373 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 139 ++++++++ .../sling/scripting/java/CompilationContext.java | 232 +++++++++++++ .../apache/sling/scripting/java/CompilerError.java | 161 +++++++++ .../apache/sling/scripting/java/CompilerUtil.java | 129 +++++++ .../scripting/java/JavaScriptEngineFactory.java | 271 +++++++++++++++ .../sling/scripting/java/JavaServletConfig.java | 94 ++++++ .../sling/scripting/java/JavaServletContext.java | 285 ++++++++++++++++ .../org/apache/sling/scripting/java/Options.java | 177 ++++++++++ .../apache/sling/scripting/java/ServletCache.java | 72 ++++ .../sling/scripting/java/ServletWrapper.java | 275 +++++++++++++++ .../sling/scripting/java/SlingIOProvider.java | 369 +++++++++++++++++++++ .../sling/scripting/java/jdt/CompilationUnit.java | 282 ++++++++++++++++ .../scripting/java/jdt/EclipseJavaCompiler.java | 118 +++++++ 13 files changed, 2604 insertions(+) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c2894dd --- /dev/null +++ b/pom.xml @@ -0,0 +1,139 @@ + + + + + 4.0.0 + + org.apache.sling + sling + 4-incubator-SNAPSHOT + ../../parent/pom.xml + + + org.apache.sling.scripting.java + 2.0.0-incubator-SNAPSHOT + bundle + + Sling - Scripting - Java Support + Support for scripting Java + + + scm:svn:http://svn.apache.org/repos/asf/incubator/sling/trunk/scripting/java + scm:svn:https://svn.apache.org/repos/asf/incubator/sling/trunk/scripting/java + http://svn.apache.org/viewvc/incubator/sling/trunk/scripting/java + + + + + + org.apache.felix + maven-scr-plugin + + + org.apache.felix + maven-bundle-plugin + true + + + + !org.eclipse.*, * + + + org.apache.sling.scripting.java, + org.apache.sling.scripting.java.jdt, + org.eclipse.jdt.* + + * + + ${pom.name} + ${pom.version} + + + jasper* + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + org.apache.sling.scripting + + + + + + + + + org.apache.sling + org.apache.sling.api + 2.0.2-incubator + + + org.apache.sling + org.apache.sling.scripting.api + 2.0.2-incubator + + + org.apache.sling + org.apache.sling.jcr.api + 2.0.2-incubator + + + org.apache.sling + org.apache.sling.jcr.classloader + 2.0.2-incubator + + + + + org.apache.tomcat + jasper-jdt + 6.0.18 + + + + org.apache.felix + org.osgi.core + + + org.apache.felix + org.osgi.compendium + + + javax.servlet + servlet-api + 2.5 + provided + + + org.slf4j + slf4j-api + + + diff --git a/src/main/java/org/apache/sling/scripting/java/CompilationContext.java b/src/main/java/org/apache/sling/scripting/java/CompilationContext.java new file mode 100644 index 0000000..8c5e41b --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/CompilationContext.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.io.FileNotFoundException; +import java.util.List; + +import javax.servlet.ServletException; + +import org.apache.sling.scripting.java.jdt.EclipseJavaCompiler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class CompilationContext { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + /** The name of the generated class. */ + private final String className; + + /** The path to the servlet. */ + private final String sourcePath; + + /** The mapped path. */ + private final String mappedSourcePath; + + /** Compilation options. */ + private final Options options; + + /** The compiler instance. */ + private final EclipseJavaCompiler compiler; + + /** Sling IO Provider. */ + private final SlingIOProvider ioProvider; + + private ServletCache servletCache; + + private long lastModificationTest = 0L; + private int removed = 0; + + private Class servletClass; + + private final ServletWrapper wrapper; + + /** + * A new compilation context. + * @param sourcePath The path to the servlet source. + * @param options The compiler options + * @param provider The Sling IO Provider + * @param servletCache + */ + public CompilationContext(final String sourcePath, + final Options options, + final SlingIOProvider provider, + ServletCache servletCache, + final ServletWrapper wrapper) { + this.sourcePath = sourcePath; + this.mappedSourcePath = CompilerUtil.mapSourcePath(this.sourcePath); + this.className = CompilerUtil.makeClassPath(this.mappedSourcePath); + + this.options = options; + this.ioProvider = provider; + this.compiler = new EclipseJavaCompiler(this); + + this.servletCache = servletCache; + this.wrapper = wrapper; + } + + /** + * Options + */ + public Options getCompilerOptions() { + return options; + } + + /** + * Provider + */ + public SlingIOProvider getIOProvider() { + return this.ioProvider; + } + + /** + * Return the path to the java servlet source file + * @return The source file path. + */ + public String getSourcePath() { + return this.sourcePath; + } + + public String getJavaClassName() { + return this.mappedSourcePath.replace('/', '.'); + } + + /** + * Return the path to the generated class file. + * @return The class file path. + */ + public String getClassFilePath() { + return this.className; + } + + public void incrementRemoved() { + if (removed == 0 && servletCache != null) { + servletCache.removeWrapper(sourcePath); + } + removed++; + } + + public boolean isRemoved() { + if (removed > 1 ) { + return true; + } + return false; + } + + /** + * Check if the compiled class file is older than the source file + */ + public boolean isOutDated() { + if (this.options.getModificationTestInterval() > 0) { + + if (this.lastModificationTest + + (this.options.getModificationTestInterval() * 1000) > System.currentTimeMillis()) { + return false; + } + this.lastModificationTest = System.currentTimeMillis(); + } + + final long sourceLastModified = this.ioProvider.lastModified(getSourcePath()); + + final long targetLastModified = this.ioProvider.lastModified(getCompleteClassPath()); + if (targetLastModified < 0) { + return true; + } + + if (targetLastModified < sourceLastModified) { + if (logger.isDebugEnabled()) { + logger.debug("Compiler: outdated: " + getClassFilePath() + " " + + targetLastModified); + } + return true; + } + + return false; + + } + + private String getCompleteClassPath() { + return options.getDestinationPath() + getClassFilePath() + ".class"; + } + + // ==================== Compile and reload ==================== + + public void compile() throws ServletException, FileNotFoundException { + if (this.isOutDated()) { + try { + final List errors = this.compiler.compile(); + if ( errors != null ) { + //this.ioProvider.delete(getCompleteClassPath()); + throw CompilerException.create(errors); + } + this.wrapper.setReload(true); + this.wrapper.setCompilationException(null); + } catch (ServletException se) { + this.wrapper.setCompilationException(se); + throw se; + } catch (Exception ex) { + final ServletException se = new ServletException("Unable to compile servlet.", ex); + // Cache compilation exception + this.wrapper.setCompilationException(se); + throw se; + } + } + } + + /** + * Load the class. + */ + public Class load() + throws ServletException, FileNotFoundException { + try { + servletClass = this.options.getClassLoader().loadClass(this.getClassFilePath().substring(1).replace('/', '.')); + } catch (ClassNotFoundException cex) { + throw new ServletException("Unable to load servlet class.", cex); + } catch (Exception ex) { + throw new ServletException("Unable to compile servlet.", ex); + } + removed = 0; + return servletClass; + } + + protected final static class CompilerException extends ServletException { + + public static CompilerException create(List errors) { + final StringBuffer buffer = new StringBuffer(); + buffer.append("Compilation errors:\n"); + for(final CompilerError e : errors) { + buffer.append(e.getFile()); + buffer.append(", line "); + buffer.append(e.getStartLine()); + buffer.append(", column "); + buffer.append(e.getStartColumn()); + buffer.append(" : " ); + buffer.append(e.getMessage()); + buffer.append("\n"); + } + return new CompilerException(buffer.toString()); + } + + public CompilerException(final String message) { + super(message); + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/CompilerError.java b/src/main/java/org/apache/sling/scripting/java/CompilerError.java new file mode 100644 index 0000000..e29f67c --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/CompilerError.java @@ -0,0 +1,161 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +/** + * This class encapsulates an error message produced by a programming language + * processor (whether interpreted or compiled) + * @version $Id$ + * @since 2.0 + */ + +public class CompilerError { + /** + * Is this a severe error or a warning? + */ + private boolean error; + /** + * The start line number of the offending program text + */ + private int startline; + /** + * The start column number of the offending program text + */ + private int startcolumn; + /** + * The end line number of the offending program text + */ + private int endline; + /** + * The end column number of the offending program text + */ + private int endcolumn; + /** + * The name of the file containing the offending program text + */ + private String file; + /** + * The actual error text produced by the language processor + */ + private String message; + + /** + * The error message constructor. + * + * @param file The name of the file containing the offending program text + * @param error The actual error text produced by the language processor + * @param startline The start line number of the offending program text + * @param startcolumn The start column number of the offending program text + * @param endline The end line number of the offending program text + * @param endcolumn The end column number of the offending program text + * @param message The actual error text produced by the language processor + */ + public CompilerError( + String file, + boolean error, + int startline, + int startcolumn, + int endline, + int endcolumn, + String message + ) + { + this.file = file; + this.error = error; + this.startline = startline; + this.startcolumn = startcolumn; + this.endline = endline; + this.endcolumn = endcolumn; + this.message = message; + } + + /** + * The error message constructor. + * + * @param message The actual error text produced by the language processor + */ + public CompilerError(String message) { + this.message = message; + } + + /** + * Return the filename associated with this compiler error. + * + * @return The filename associated with this compiler error + */ + public String getFile() { + return file; + } + + /** + * Assert whether this is a severe error or a warning + * + * @return Whether the error is severe + */ + public boolean isError() { + return error; + } + + /** + * Return the starting line number of the program text originating this error + * + * @return The starting line number of the program text originating this error + */ + public int getStartLine() { + return startline; + } + + /** + * Return the starting column number of the program text originating this + * error + * + * @return The starting column number of the program text originating this + * error + */ + public int getStartColumn() { + return startcolumn; + } + + /** + * Return the ending line number of the program text originating this error + * + * @return The ending line number of the program text originating this error + */ + public int getEndLine() { + return endline; + } + + /** + * Return the ending column number of the program text originating this + * error + * + * @return The ending column number of the program text originating this + * error + */ + public int getEndColumn() { + return endcolumn; + } + + /** + * Return the message produced by the language processor + * + * @return The message produced by the language processor + */ + public String getMessage() { + return message; + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/CompilerUtil.java b/src/main/java/org/apache/sling/scripting/java/CompilerUtil.java new file mode 100644 index 0000000..d415ed7 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/CompilerUtil.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +public class CompilerUtil { + + /** + * The path has to be mapped to form a proper java class name. + * @param path + * @return The mapped source path. + */ + public static String mapSourcePath(final String path) { + final String str; + if ( path.endsWith(".java") ) { + str = path.substring(0, path.length() - 5); + } else { + str = path; + } + final int pos = str.lastIndexOf("/"); + if ( pos == -1 ) { + return makeJavaIdentifier(str); + } + return str.substring(0, pos + 1) + makeJavaIdentifier(str.substring(pos + 1)); + } + + /** + * Create the class name from the source name + * @param sourcePath The source path + * @return The corresponding class file path. + */ + public static String makeClassPath(String sourcePath) { + String str = sourcePath; + if (str.endsWith(".java")) { + str = str.substring(0, str.length() - 5); + } + return str; + } + + + /** + * Converts the given identifier to a legal Java identifier + * + * @param identifier Identifier to convert + * + * @return Legal Java identifier corresponding to the given identifier + */ + public static final String makeJavaIdentifier(String identifier) { + StringBuffer modifiedIdentifier = + new StringBuffer(identifier.length()); + if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { + modifiedIdentifier.append('_'); + } + for (int i = 0; i < identifier.length(); i++) { + char ch = identifier.charAt(i); + if (Character.isJavaIdentifierPart(ch) && ch != '_') { + modifiedIdentifier.append(ch); + } else if (ch == '.') { + modifiedIdentifier.append('_'); + } else { + modifiedIdentifier.append(mangleChar(ch)); + } + } + if (isJavaKeyword(modifiedIdentifier.toString())) { + modifiedIdentifier.append('_'); + } + return modifiedIdentifier.toString(); + } + + /** + * Mangle the specified character to create a legal Java class name. + */ + public static final String mangleChar(char ch) { + char[] result = new char[5]; + result[0] = '_'; + result[1] = Character.forDigit((ch >> 12) & 0xf, 16); + result[2] = Character.forDigit((ch >> 8) & 0xf, 16); + result[3] = Character.forDigit((ch >> 4) & 0xf, 16); + result[4] = Character.forDigit(ch & 0xf, 16); + return new String(result); + } + + private static final String javaKeywords[] = { + "abstract", "assert", "boolean", "break", "byte", "case", + "catch", "char", "class", "const", "continue", + "default", "do", "double", "else", "enum", "extends", + "final", "finally", "float", "for", "goto", + "if", "implements", "import", "instanceof", "int", + "interface", "long", "native", "new", "package", + "private", "protected", "public", "return", "short", + "static", "strictfp", "super", "switch", "synchronized", + "this", "throws", "transient", "try", "void", + "volatile", "while" }; + + /** + * Test whether the argument is a Java keyword + */ + public static boolean isJavaKeyword(String key) { + int i = 0; + int j = javaKeywords.length; + while (i < j) { + int k = (i+j)/2; + int result = javaKeywords[k].compareTo(key); + if (result == 0) { + return true; + } + if (result < 0) { + i = k+1; + } else { + j = k; + } + } + return false; + } + +} diff --git a/src/main/java/org/apache/sling/scripting/java/JavaScriptEngineFactory.java b/src/main/java/org/apache/sling/scripting/java/JavaScriptEngineFactory.java new file mode 100644 index 0000000..70190f2 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/JavaScriptEngineFactory.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import static org.apache.sling.api.scripting.SlingBindings.SLING; + +import java.io.Reader; + +import javax.jcr.RepositoryException; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.apache.sling.api.SlingException; +import org.apache.sling.api.SlingIOException; +import org.apache.sling.api.SlingServletException; +import org.apache.sling.api.scripting.SlingBindings; +import org.apache.sling.api.scripting.SlingScript; +import org.apache.sling.api.scripting.SlingScriptHelper; +import org.apache.sling.jcr.api.SlingRepository; +import org.apache.sling.jcr.classloader.RepositoryClassLoaderProvider; +import org.apache.sling.scripting.api.AbstractScriptEngineFactory; +import org.apache.sling.scripting.api.AbstractSlingScriptEngine; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Java engine + * + * @scr.component label="%javahandler.name" description="%javahandler.description" + * @scr.property name="service.description" value="Java Servlet Script Handler" + * @scr.property name="service.vendor" value="The Apache Software Foundation" + * @scr.service + * + * @scr.property name="java.javaEncoding" value="UTF-8" + * @scr.property name="java.compilerSourceVM" value="1.5" + * @scr.property name="java.compilerTargetVM" value="1.5" + * @scr.property name="java.development" value="true" + * @scr.property name="java.outputPath" value="/var/classes" + * @scr.property name="java.modificationTestInterval" value="-1" + * @scr.property name="java.classdebuginfo" value="truie" + */ +public class JavaScriptEngineFactory extends AbstractScriptEngineFactory { + + private static final String CLASSLOADER_NAME = "admin"; + + /** default logger */ + private final Logger log = LoggerFactory.getLogger(getClass()); + + /** @scr.reference */ + private SlingRepository repository; + + /** + * @scr.reference + */ + private RepositoryClassLoaderProvider repoCLProvider; + + /** + * The class loader + */ + private ClassLoader javaClassLoader; + + /** @scr.reference */ + private ServletContext slingServletContext; + + private SlingIOProvider ioProvider; + + private JavaServletContext javaServletContext; + + private ServletConfig servletConfig; + + private ServletCache servletCache; + + /** Compiler options. */ + private Options compilerOptions; + + public static final String SCRIPT_TYPE = "java"; + + /** + * Constructor + */ + public JavaScriptEngineFactory() { + setExtensions(SCRIPT_TYPE); + } + + /** + * @see javax.script.ScriptEngineFactory#getScriptEngine() + */ + public ScriptEngine getScriptEngine() { + return new JavaScriptEngine(this); + } + + /** + * @see javax.script.ScriptEngineFactory#getLanguageName() + */ + public String getLanguageName() { + return "Java Servlet Compiler"; + } + + /** + * @see javax.script.ScriptEngineFactory#getLanguageVersion() + */ + public String getLanguageVersion() { + return "1.5"; + } + + /** + * Activate this engine + * @param componentContext + */ + protected void activate(ComponentContext componentContext) { + this.ioProvider = new SlingIOProvider(repository); + this.servletCache = new ServletCache(); + + this.javaServletContext = new JavaServletContext(ioProvider, + slingServletContext); + + this.servletConfig = new JavaServletConfig(javaServletContext, + componentContext.getProperties()); + this.compilerOptions = new Options(componentContext, + this.javaClassLoader); + if (log.isDebugEnabled()) { + log.debug("JavaServletScriptEngine.activate()"); + } + } + + /** + * Deactivate this engine + * @param oldComponentContext + */ + protected void deactivate(ComponentContext oldComponentContext) { + if (log.isDebugEnabled()) { + log.debug("JavaServletScriptEngine.deactivate()"); + } + + ioProvider = null; + javaServletContext = null; + servletConfig = null; + servletCache = null; + compilerOptions = null; + } + + /** + * Call the servlet. + * @param scriptHelper + * @throws SlingServletException + * @throws SlingIOException + */ + private void callServlet(Bindings bindings, SlingScriptHelper scriptHelper) { + + ioProvider.setRequestResourceResolver(scriptHelper.getRequest().getResourceResolver()); + try { + ServletWrapper servlet = getWrapperAdapter(scriptHelper); + // create a SlingBindings object + final SlingBindings slingBindings = new SlingBindings(); + slingBindings.putAll(bindings); + servlet.service(slingBindings); + } finally { + ioProvider.resetRequestResourceResolver(); + } + } + + private ServletWrapper getWrapperAdapter( + SlingScriptHelper scriptHelper) throws SlingException { + + SlingScript script = scriptHelper.getScript(); + final String scriptName = script.getScriptResource().getPath(); + ServletWrapper wrapper = this.servletCache.getWrapper(scriptName); + if (wrapper != null) { + return wrapper; + } + + synchronized (this) { + wrapper = this.servletCache.getWrapper(scriptName); + if (wrapper != null) { + return wrapper; + } + + wrapper = new ServletWrapper(servletConfig, + this.compilerOptions, ioProvider, scriptName, this.servletCache); + this.servletCache.addWrapper(scriptName, wrapper); + + return wrapper; + } + } + + /** + * Bind the class load provider. + * @param repositoryClassLoaderProvider the new provider + */ + protected void bindRepositoryClassLoaderProvider(RepositoryClassLoaderProvider rclp) { + if ( this.javaClassLoader != null ) { + this.ungetClassLoader(); + } + this.getClassLoader(rclp); + } + + /** + * Unbind the class loader provider. + * @param repositoryClassLoaderProvider the old provider + */ + protected void unbindRepositoryClassLoaderProvider(RepositoryClassLoaderProvider rclp) { + if ( this.repoCLProvider == rclp ) { + this.ungetClassLoader(); + } + } + + /** + * Get the class loader + */ + private void getClassLoader(RepositoryClassLoaderProvider rclp) { + try { + this.repoCLProvider = rclp; + this.javaClassLoader = rclp.getClassLoader(CLASSLOADER_NAME); + } catch (RepositoryException re) { + log.error("Cannot get Java class loader", re); + } + } + + /** + * Unget the class loader + */ + private void ungetClassLoader() { + if ( this.repoCLProvider != null ) { + if ( this.javaClassLoader != null ) { + this.repoCLProvider.ungetClassLoader(this.javaClassLoader); + this.javaClassLoader = null; + } + this.repoCLProvider = null; + } + } + // ---------- Internal ----------------------------------------------------- + + private static class JavaScriptEngine extends AbstractSlingScriptEngine { + + JavaScriptEngine(JavaScriptEngineFactory factory) { + super(factory); + } + + /** + * @see javax.script.ScriptEngine#eval(java.io.Reader, javax.script.ScriptContext) + */ + public Object eval(Reader script, ScriptContext context) + throws ScriptException { + final Bindings props = context.getBindings(ScriptContext.ENGINE_SCOPE); + final SlingScriptHelper scriptHelper = (SlingScriptHelper) props.get(SLING); + if (scriptHelper != null) { + ((JavaScriptEngineFactory)this.getFactory()).callServlet(props, scriptHelper); + } + return null; + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/JavaServletConfig.java b/src/main/java/org/apache/sling/scripting/java/JavaServletConfig.java new file mode 100644 index 0000000..48f305e --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/JavaServletConfig.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.sling.scripting.java; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.osgi.framework.Constants; + +/** + * The JavaServletConfig + * is passed to the compiled servlets. + */ +public class JavaServletConfig implements ServletConfig { + + /** The servlet context. */ + private final ServletContext servletContext; + + /** The name of the servlet. */ + private final String servletName; + + private final Map initParams; + + public JavaServletConfig(ServletContext servletContext, Dictionary config) { + this.servletContext = servletContext; + + // set the servlet name + if (config.get(Constants.SERVICE_DESCRIPTION) == null) { + servletName = "Java Script Handler"; + } else{ + servletName = config.get(Constants.SERVICE_DESCRIPTION).toString(); + } + + // copy the "java." properties + initParams = new HashMap(); + for (Enumeration ke = config.keys(); ke.hasMoreElements();) { + String key = (String) ke.nextElement(); + if (key.startsWith("java.")) { + initParams.put(key.substring("java.".length()), + String.valueOf(config.get(key))); + } + } + } + + /** + * @see javax.servlet.ServletConfig#getInitParameter(java.lang.String) + */ + public String getInitParameter(String name) { + return initParams.get(name); + } + + /** + * @see javax.servlet.ServletConfig#getInitParameterNames() + */ + public Enumeration getInitParameterNames() { + return Collections.enumeration(initParams.keySet()); + } + + /** + * @see javax.servlet.ServletConfig#getServletContext() + */ + public ServletContext getServletContext() { + return servletContext; + } + + /** + * @see javax.servlet.ServletConfig#getServletName() + */ + public String getServletName() { + return servletName; + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/sling/scripting/java/JavaServletContext.java b/src/main/java/org/apache/sling/scripting/java/JavaServletContext.java new file mode 100644 index 0000000..8b1969a --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/JavaServletContext.java @@ -0,0 +1,285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Set; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The JavaServletContext + * is passed to the compiled servlets. + */ +public class JavaServletContext implements ServletContext { + + /** default log */ + private final Logger log = LoggerFactory.getLogger(getClass()); + + private final SlingIOProvider ioProvider; + private final ServletContext delegatee; + + JavaServletContext(SlingIOProvider ioProvider, ServletContext componentContext) { + this.ioProvider = ioProvider; + this.delegatee = componentContext; + } + + /** + * @see javax.servlet.ServletContext#getResource(java.lang.String) + */ + public URL getResource(String path) throws MalformedURLException { + if (path.startsWith("/")) { + URL url = ioProvider.getURL(path); + if (url != null) { + return url; + } + } + + // fall back to trying a real URL + return getUrlForResource(path); + } + + /** + * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) + */ + public InputStream getResourceAsStream(String path) { + // path might be an URL, so only check resource provider in case of an + // absolute path - assuming URLs have no leading slash at all, we + // don't care for the scheme separating colon here + if (path.startsWith("/")) { + try { + return ioProvider.getInputStream(path); + } catch (Exception ex) { + // FileNotFoundException or IOException + log.debug("getResourceAsStream: Cannot get resource {}: {}", + path, ex.getMessage()); + } + } + + // check whether we can resolve as an URL ... + try { + // create the URL and try to access + URL url = getUrlForResource(path); + if (url != null) { + return url.openStream(); + } + } catch (Exception e) { + log.debug( + "getResourceAsStream: Cannot access resource {} through URL: {}", + path, e.getMessage()); + } + + return null; + } + + /** + * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) + */ + public Set getResourcePaths(String path) { + return ioProvider.getResourcePaths(path); + } + + /** + * @see javax.servlet.ServletContext#log(java.lang.String) + */ + public void log(String msg) { + log.info(msg); + } + + /** + * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String) + */ + @Deprecated + public void log(Exception exception, String msg) { + log(msg, exception); + } + + /** + * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable) + */ + public void log(String message, Throwable throwable) { + log.error(message, throwable); + } + + /** + * @see javax.servlet.ServletContext#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) { + return delegatee.getAttribute(name); + } + + /** + * @see javax.servlet.ServletContext#getAttributeNames() + */ + public Enumeration getAttributeNames() { + return delegatee.getAttributeNames(); + } + + /** + * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) + */ + public void removeAttribute(String name) { + delegatee.removeAttribute(name); + } + + /** + * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) + */ + public void setAttribute(String name, Object object) { + delegatee.setAttribute(name, object); + } + + /** + * @see javax.servlet.ServletContext#getContext(java.lang.String) + */ + public ServletContext getContext(String uripath) { + return delegatee.getContext(uripath); + } + + /** + * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) + */ + public String getInitParameter(String name) { + return delegatee.getInitParameter(name); + } + + /** + * @see javax.servlet.ServletContext#getInitParameterNames() + */ + public Enumeration getInitParameterNames() { + return delegatee.getInitParameterNames(); + } + + /** + * @see javax.servlet.ServletContext#getMajorVersion() + */ + public int getMajorVersion() { + return delegatee.getMajorVersion(); + } + + /** + * @see javax.servlet.ServletContext#getMimeType(java.lang.String) + */ + public String getMimeType(String file) { + return delegatee.getMimeType(file); + } + + /** + * @see javax.servlet.ServletContext#getMinorVersion() + */ + public int getMinorVersion() { + return delegatee.getMinorVersion(); + } + + /** + * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) + */ + public RequestDispatcher getNamedDispatcher(String name) { + return delegatee.getNamedDispatcher(name); + } + + /** + * @see javax.servlet.ServletContext#getRealPath(java.lang.String) + */ + public String getRealPath(String path) { + return delegatee.getRealPath(path); + } + + /** + * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) + */ + public RequestDispatcher getRequestDispatcher(String path) { + return delegatee.getRequestDispatcher(path); + } + + /** + * @see javax.servlet.ServletContext#getServerInfo() + */ + public String getServerInfo() { + return delegatee.getServerInfo(); + } + + /** + * @see javax.servlet.ServletContext#getServlet(java.lang.String) + */ + @Deprecated + public Servlet getServlet(String name) throws ServletException { + return delegatee.getServlet(name); + } + + /** + * @see javax.servlet.ServletContext#getServletContextName() + */ + public String getServletContextName() { + return delegatee.getServletContextName(); + } + + /** + * @see javax.servlet.ServletContext#getServletNames() + */ + @Deprecated + public Enumeration getServletNames() { + return delegatee.getServletNames(); + } + + /** + * @see javax.servlet.ServletContext#getServlets() + */ + @Deprecated + public Enumeration getServlets() { + return delegatee.getServlets(); + } + + /** + * @see javax.servlet.ServletContext#getContextPath() + */ + public String getContextPath() { + return delegatee.getContextPath(); + } + + //---------- internal ----------------------------------------------------- + + private URL getUrlForResource(String path) { + int cs = path.indexOf(":/"); + if (cs > 0 && cs < path.length()-2) { + // insert second slash after scheme (was canonicalized away) + cs += 2; + if (cs < path.length() && path.charAt(cs) != '/') { + path = path.substring(0, cs) + "/" + path.substring(cs); + } + + // create the URL and try to access + try { + return new URL(path); + } catch (MalformedURLException mue) { + log.debug("getUrlForResource: Cannot create URL for {}: {}", + path, mue.getMessage()); + } + } + + return null; + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/Options.java b/src/main/java/org/apache/sling/scripting/java/Options.java new file mode 100644 index 0000000..bc445ac --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/Options.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Properties; + +import org.osgi.service.component.ComponentContext; + + +/** + * A class to hold all init parameters specific to the compiler + */ +public class Options { + + private static final String PROPERTY_JAVA_ENCODING = "javaEncoding"; + + private static final String PROPERTY_COMPILER_SOURCE_V_M = "compilerSourceVM"; + + private static final String PROPERTY_COMPILER_TARGET_V_M = "compilerTargetVM"; + + private static final String PROPERTY_DEVELOPMENT = "development"; + + private static final String PROPERTY_OUTPUT_PATH = "outputPath"; + + private static final String PROPERTY_MODIFICATION_TEST_INTERVAL = "modificationTestInterval"; + + private static final String PROPERTY_CLASSDEBUGINFO = "classdebuginfo"; + + /** Default source and target VM version (value is "1.5"). */ + private static final String DEFAULT_VM_VERSION = "1.5"; + + /** + * Is the engine being used in development mode? + */ + private final boolean development; + + /** + * Do we want to include debugging information in the class file? + */ + private final boolean classDebugInfo; + + /** + * Compiler target VM. + */ + private final String compilerTargetVM; + + /** + * The compiler source VM. + */ + private final String compilerSourceVM; + + /** + * Java platform encoding to generate the servlet. + */ + private final String javaEncoding; + + /** + * Modification test interval. + */ + private final int modificationTestInterval; + + /** + * Classloader + */ + private final ClassLoader classLoader; + + private final String destinationDir; + + /** + * Create an compiler options object using data available from + * the component configuration. + */ + public Options(final ComponentContext componentContext, + final ClassLoader classLoader) { + + this.classLoader = classLoader; + + // generate properties + final Properties properties = new Properties(); + // set default values first + properties.put(PROPERTY_CLASSDEBUGINFO, "true"); + properties.put(PROPERTY_DEVELOPMENT, "true"); + properties.put(PROPERTY_MODIFICATION_TEST_INTERVAL, "-1"); + properties.put(PROPERTY_COMPILER_TARGET_V_M, DEFAULT_VM_VERSION); + properties.put(PROPERTY_COMPILER_SOURCE_V_M, DEFAULT_VM_VERSION); + properties.put(PROPERTY_JAVA_ENCODING, "UTF-8"); + properties.put(PROPERTY_OUTPUT_PATH, "/var/classes"); + + // now check component properties + Dictionary config = componentContext.getProperties(); + Enumeration enumeration = config.keys(); + while (enumeration.hasMoreElements()) { + String key = (String) enumeration.nextElement(); + if (key.startsWith("java.")) { + Object value = config.get(key); + if (value != null) { + properties.put(key.substring("java.".length()), + value.toString()); + } + } + } + + this.destinationDir = properties.get(PROPERTY_OUTPUT_PATH).toString(); + this.classDebugInfo = Boolean.valueOf(properties.get(PROPERTY_CLASSDEBUGINFO).toString()); + this.modificationTestInterval = Integer.valueOf(properties.get(PROPERTY_MODIFICATION_TEST_INTERVAL).toString()); + this.development = Boolean.valueOf(properties.get(PROPERTY_DEVELOPMENT).toString()); + this.compilerTargetVM = properties.get(PROPERTY_COMPILER_TARGET_V_M).toString(); + this.compilerSourceVM = properties.get(PROPERTY_COMPILER_SOURCE_V_M).toString(); + this.javaEncoding = properties.get(PROPERTY_JAVA_ENCODING).toString(); + } + + /** + * Return the destination directory. + */ + public String getDestinationPath() { + return this.destinationDir; + } + + /** + * Should class files be compiled with debug information? + */ + public boolean getClassDebugInfo() { + return this.classDebugInfo; + } + + /** + * Modification test interval. + */ + public int getModificationTestInterval() { + return this.modificationTestInterval; + } + + /** + * Is the engine being used in development mode? + */ + public boolean getDevelopment() { + return this.development; + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + /** + * @see Options#getCompilerTargetVM + */ + public String getCompilerTargetVM() { + return this.compilerTargetVM; + } + + /** + * @see Options#getCompilerSourceVM + */ + public String getCompilerSourceVM() { + return this.compilerSourceVM; + } + + public String getJavaEncoding() { + return this.javaEncoding; + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/ServletCache.java b/src/main/java/org/apache/sling/scripting/java/ServletCache.java new file mode 100644 index 0000000..9755621 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/ServletCache.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This is a simple in memory cache for compiled servlets. + */ +public final class ServletCache { + + /** + * Maps servlet source urls to servlet wrappers. + */ + private Map servlets = new ConcurrentHashMap(); + + /** + * Add a new ServletWrapper. + * + * @param servletUri Servlet URI + * @param sw Servlet wrapper + */ + public void addWrapper(String servletUri, ServletWrapper sw) { + servlets.put(servletUri, sw); + } + + /** + * Get an already existing ServletWrapper. + * + * @param servletUri Servlet URI + * @return ServletWrapper + */ + public ServletWrapper getWrapper(String servletUri) { + return servlets.get(servletUri); + } + + /** + * Remove a ServletWrapper. + * + * @param servletUri Servlet URI + */ + public void removeWrapper(String servletUri) { + servlets.remove(servletUri); + } + + /** + * Process a "destory" event for this web application context. + */ + public void destroy() { + Iterator i = this.servlets.values().iterator(); + while (i.hasNext()) { + i.next().destroy(); + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/ServletWrapper.java b/src/main/java/org/apache/sling/scripting/java/ServletWrapper.java new file mode 100644 index 0000000..a052c8b --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/ServletWrapper.java @@ -0,0 +1,275 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.SingleThreadModel; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.sling.api.SlingException; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingIOException; +import org.apache.sling.api.SlingServletException; +import org.apache.sling.api.scripting.SlingBindings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + + */ + +public class ServletWrapper { + + /** The logger. */ + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final String servletUri; + + /** The servlet config. */ + private ServletConfig config; + + /** Reload flag. */ + private boolean reload = true; + + /** Compiler options. */ + private final Options options; + + private Servlet theServlet; + private long available = 0L; + private boolean firstTime = true; + private ServletException compileException; + private CompilationContext ctxt; + + /** + * A wrapper for servlets. + */ + public ServletWrapper(final ServletConfig config, + final Options options, + final SlingIOProvider ioProvider, + final String servletPath, + final ServletCache servletCache) { + this.config = config; + this.servletUri = servletPath; + this.options = options; + this.ctxt = new CompilationContext(servletUri, options, + ioProvider, servletCache, this); + } + + /** + * Set the reload flag. + * @param reload + */ + public void setReload(boolean reload) { + this.reload = reload; + } + + /** + * Get the servlet. + * @return The servlet. + * @throws ServletException + * @throws IOException + * @throws FileNotFoundException + */ + private Servlet getServlet() + throws ServletException, IOException, FileNotFoundException { + if (reload) { + synchronized (this) { + if (reload) { + destroy(); + + Servlet servlet = null; + + try { + final Class servletClass = ctxt.load(); + servlet = (Servlet) servletClass.newInstance(); + } catch (IllegalAccessException e) { + throw new ServletException(e); + } catch (InstantiationException e) { + throw new ServletException(e); + } catch (Exception e) { + throw new ServletException(e); + } + + servlet.init(config); + + theServlet = servlet; + reload = false; + } + } + } + return theServlet; + } + + /** + * Sets the compilation exception for this ServletWrapper. + * + * @param je The compilation exception + */ + public void setCompilationException(ServletException je) { + this.compileException = je; + } + + /** + * @param bindings + * @throws SlingIOException + * @throws SlingServletException + * @throws IllegalArgumentException if the Jasper Precompile controller + * request parameter has an illegal value. + */ + public void service(SlingBindings bindings) { + final SlingHttpServletRequest request = bindings.getRequest(); + final Object oldValue = request.getAttribute(SlingBindings.class.getName()); + try { + request.setAttribute(SlingBindings.class.getName(), bindings); + service(request, bindings.getResponse()); + } catch (SlingException se) { + // rethrow as is + throw se; + } catch (IOException ioe) { + throw new SlingIOException(ioe); + } catch (ServletException se) { + throw new SlingServletException(se); + } finally { + request.setAttribute(SlingBindings.class.getName(), oldValue); + } + } + + /** + * Call the servlet. + * @param request The current request. + * @param response The current response. + * @throws ServletException + * @throws IOException + * @throws FileNotFoundException + */ + public void service(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException, FileNotFoundException { + + try { + + if (ctxt.isRemoved()) { + throw new FileNotFoundException(servletUri); + } + + if ((available > 0L) && (available < Long.MAX_VALUE)) { + if (available > System.currentTimeMillis()) { + response.setDateHeader("Retry-After", available); + response.sendError + (HttpServletResponse.SC_SERVICE_UNAVAILABLE, + "Servlet unavailable."); + return; + } + // Wait period has expired. Reset. + available = 0; + } + + /* + * (1) Compile + */ + if (options.getDevelopment() || firstTime ) { + synchronized (this) { + firstTime = false; + + // The following sets reload to true, if necessary + ctxt.compile(); + } + } else { + if (compileException != null) { + // Throw cached compilation exception + throw compileException; + } + } + + /* + * (2) (Re)load servlet class file + */ + getServlet(); + + } catch (FileNotFoundException ex) { + ctxt.incrementRemoved(); + try { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + ex.getMessage()); + } catch (IllegalStateException ise) { + logger.error("Java servlet source not found." + + ex.getMessage(), ex); + } + } catch (ServletException ex) { + throw ex; + } catch (IOException ex) { + throw ex; + } catch (IllegalStateException ex) { + throw ex; + } catch (Exception ex) { + throw new ServletException(ex); + } + + try { + + /* + * (3) Service request + */ + if (theServlet instanceof SingleThreadModel) { + // sync on the wrapper so that the freshness + // of the page is determined right before servicing + synchronized (this) { + theServlet.service(request, response); + } + } else { + theServlet.service(request, response); + } + + } catch (UnavailableException ex) { + int unavailableSeconds = ex.getUnavailableSeconds(); + if (unavailableSeconds <= 0) { + unavailableSeconds = 60; // Arbitrary default + } + available = System.currentTimeMillis() + + (unavailableSeconds * 1000L); + response.sendError + (HttpServletResponse.SC_SERVICE_UNAVAILABLE, + ex.getMessage()); + } catch (ServletException ex) { + throw ex; + } catch (IOException ex) { + throw ex; + } catch (IllegalStateException ex) { + throw ex; + } catch (Exception ex) { + throw new ServletException(ex); + } + } + + /** + * Destroy the servlet. + */ + public void destroy() { + if (theServlet != null) { + theServlet.destroy(); + theServlet = null; + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/SlingIOProvider.java b/src/main/java/org/apache/sling/scripting/java/SlingIOProvider.java new file mode 100644 index 0000000..00e714a --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/SlingIOProvider.java @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; + +import javax.jcr.Item; +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.sling.api.SlingException; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceMetadata; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.jcr.api.SlingRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The SlingIOProvider TODO + */ +public class SlingIOProvider { + + /** default log */ + private static final Logger log = LoggerFactory.getLogger(SlingIOProvider.class); + + private final SlingRepository repository; + + private ThreadLocal requestResourceResolver; + + // private session for write access + private ThreadLocal privateSession; + + SlingIOProvider(SlingRepository repository) { + this.repository = repository; + this.requestResourceResolver = new ThreadLocal(); + this.privateSession = new ThreadLocal(); + } + + void setRequestResourceResolver(ResourceResolver resolver) { + requestResourceResolver.set(resolver); + } + + void resetRequestResourceResolver() { + requestResourceResolver.remove(); + + // at the same time logout this thread's session + Session session = privateSession.get(); + if (session != null) { + if (session.isLive()) { + session.logout(); + } + privateSession.remove(); + } + } + + // ---------- IOProvider interface ----------------------------------------- + + /** + * Returns an InputStream for the file name which is looked up with the + * ResourceProvider and retrieved from the Resource if the StreamProvider + * interface is implemented. + */ + public InputStream getInputStream(String fileName) + throws FileNotFoundException, IOException { + + try { + + Resource resource = getResourceInternal(fileName); + if (resource == null) { + throw new FileNotFoundException("Cannot find " + fileName); + } + + InputStream stream = resource.adaptTo(InputStream.class); + if (stream == null) { + throw new FileNotFoundException("Cannot find " + fileName); + } + + return stream; + + } catch (SlingException se) { + throw (IOException) new IOException( + "Failed to get InputStream for " + fileName).initCause(se); + } + } + + /** + * Returns the value of the last modified meta data field of the resource + * found at file name or zero if the meta data field is not set. If the + * resource does not exist or an error occurrs finding the resource, -1 is + * returned. + */ + public long lastModified(String fileName) { + try { + Resource resource = getResourceInternal(fileName); + if (resource != null) { + ResourceMetadata meta = resource.getResourceMetadata(); + long modTime = meta.getModificationTime(); + return (modTime > 0) ? modTime : 0; + } + + } catch (SlingException se) { + log.error("Cannot get last modification time for " + fileName, se); + } + + // fallback to "non-existant" in case of problems + return -1; + } + + /** + * Removes the named item from the repository. + */ + public boolean delete(String fileName) { + Node parentNode = null; + try { + fileName = cleanPath(fileName); + Session session = getPrivateSession(); + if (session.itemExists(fileName)) { + Item fileItem = session.getItem(fileName); + parentNode = fileItem.getParent(); + fileItem.remove(); + parentNode.save(); + return true; + } + } catch (RepositoryException re) { + log.error("Cannot remove " + fileName, re); + } finally { + checkNode(parentNode, fileName); + } + + // fall back to false if item does not exist or in case of error + return false; + } + + /** + * Returns an output stream to write to the repository. + */ + public OutputStream getOutputStream(String fileName) { + fileName = cleanPath(fileName); + return new RepositoryOutputStream(this, fileName); + } + + /* package */URL getURL(String path) throws MalformedURLException { + try { + Resource resource = getResourceInternal(path); + return (resource != null) ? resource.adaptTo(URL.class) : null; + } catch (SlingException se) { + throw (MalformedURLException) new MalformedURLException( + "Cannot get URL for " + path).initCause(se); + } + } + + /* package */Set getResourcePaths(String path) { + Set paths = new HashSet(); + + ResourceResolver resolver = requestResourceResolver.get(); + if (resolver != null) { + try { + Resource resource = resolver.getResource(cleanPath(path)); + if (resource != null) { + Iterator entries = resolver.listChildren(resource); + while (entries.hasNext()) { + paths.add(entries.next().getPath()); + } + } + } catch (SlingException se) { + log.warn("getResourcePaths: Cannot list children of " + path, + se); + } + } + + return paths.isEmpty() ? null : paths; + } + + private Resource getResourceInternal(String path) throws SlingException { + ResourceResolver resolver = requestResourceResolver.get(); + if (resolver != null) { + return resolver.getResource(cleanPath(path)); + } + + return null; + } + + // ---------- internal ----------------------------------------------------- + + private Session getPrivateSession() throws RepositoryException { + Session session = privateSession.get(); + if (session == null) { + session = repository.loginAdministrative(null); + privateSession.set(session); + } + + return session; + } + + private static void checkNode(Node node, String path) { + if (node != null && node.isModified()) { + try { + node.refresh(false); + } catch (RepositoryException re) { + log.error("Cannot refresh node for " + path + + " after failed save", re); + } + } + } + + private String cleanPath(String path) { + // replace backslash by slash + path = path.replace('\\', '/'); + + // cut off trailing slash + while (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + + return path; + } + + private static class RepositoryOutputStream extends ByteArrayOutputStream { + + private final SlingIOProvider repositoryOutputProvider; + + private final String fileName; + + RepositoryOutputStream(SlingIOProvider repositoryOutputProvider, + String fileName) { + this.repositoryOutputProvider = repositoryOutputProvider; + this.fileName = fileName; + } + + public void close() throws IOException { + super.close(); + + Node parentNode = null; + try { + Session session = repositoryOutputProvider.getPrivateSession(); + Node fileNode = null; + Node contentNode = null; + if (session.itemExists(fileName)) { + Item item = session.getItem(fileName); + if (item.isNode()) { + Node node = item.isNode() + ? (Node) item + : item.getParent(); + if ("jcr:content".equals(node.getName())) { + // replace the content properties of the jcr:content + // node + parentNode = node; + contentNode = node; + } else if (node.isNodeType("nt:file")) { + // try to set the content properties of jcr:content + // node + parentNode = node; + contentNode = node.getNode("jcr:content"); + } else { // fileName is a node + // try to set the content properties of the node + parentNode = node; + contentNode = node; + } + } else { + // replace property with an nt:file node (if possible) + parentNode = item.getParent(); + String name = item.getName(); + fileNode = parentNode.addNode(name, "nt:file"); + item.remove(); + } + } else { + fileNode = createPath(fileName, "nt:folder", "nt:file", session); + parentNode = session.getRootNode(); + } + + // if we have a file node, create the contentNode + if (fileNode != null) { + contentNode = fileNode.addNode("jcr:content", "nt:resource"); + } + + contentNode.setProperty("jcr:lastModified", + System.currentTimeMillis()); + contentNode.setProperty("jcr:data", new ByteArrayInputStream( + buf, 0, size())); + contentNode.setProperty("jcr:mimeType", + "application/octet-stream"); + + parentNode.save(); + } catch (RepositoryException re) { + log.error("Cannot write file " + fileName, re); + throw new IOException("Cannot write file " + fileName + + ", reason: " + re.toString()); + } finally { + checkNode(parentNode, fileName); + } + } + } + + /** + * Creates or gets the {@link javax.jcr.Node Node} at the given Path. + * In case it has to create the Node all non-existent intermediate path-elements + * will be create with the given intermediate node type and the returned node + * will be created with the given nodeType + * + * @param path to create + * @param intermediateNodeType to use for creation of intermediate nodes + * @param nodeType to use for creation of the final node + * @param session to use + * @return the Node at path + * @throws RepositoryException in case of exception accessing the Repository + */ + private static Node createPath(String path, + String intermediateNodeType, + String nodeType, + Session session) + throws RepositoryException { + if (path == null || path.length() == 0 || "/".equals(path)) { + return session.getRootNode(); + } else if (!session.itemExists(path)) { + Node node = session.getRootNode(); + path = path.substring(1); + int pos = path.lastIndexOf('/'); + if ( pos != -1 ) { + final StringTokenizer st = new StringTokenizer(path.substring(0, pos), "/"); + while ( st.hasMoreTokens() ) { + final String token = st.nextToken(); + if ( !node.hasNode(token) ) { + try { + node.addNode(token, intermediateNodeType); + } catch (RepositoryException re) { + // we ignore this as this folder might be created from a different task + node.refresh(false); + } + } + node = node.getNode(token); + } + path = path.substring(pos + 1); + } + if ( !node.hasNode(path) ) { + node.addNode(path, nodeType); + } + return node.getNode(path); + } else { + return (Node) session.getItem(path); + } + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/jdt/CompilationUnit.java b/src/main/java/org/apache/sling/scripting/java/jdt/CompilationUnit.java new file mode 100644 index 0000000..80459f4 --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/jdt/CompilationUnit.java @@ -0,0 +1,282 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java.jdt; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.sling.scripting.java.CompilerError; +import org.apache.sling.scripting.java.Options; +import org.apache.sling.scripting.java.SlingIOProvider; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.ClassFile; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.ICompilerRequestor; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; + + +public class CompilationUnit + implements ICompilationUnit, INameEnvironment, ICompilerRequestor { + + private final Options options; + private final SlingIOProvider ioProvider; + private final String className; + private final String sourceFile; + + /** The list of compile errors. */ + private final List errors = new LinkedList(); + + public CompilationUnit(String sourceFile, + String className, + Options options, + SlingIOProvider ioProvider) { + this.className = className; + this.sourceFile = sourceFile; + this.ioProvider = ioProvider; + this.options = options; + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName() + */ + public char[] getFileName() { + return className.concat(".java").toCharArray(); + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents() + */ + public char[] getContents() { + char[] result = null; + InputStream fr = null; + try { + fr = ioProvider.getInputStream(this.sourceFile); + final Reader reader = new BufferedReader(new InputStreamReader(fr, this.options.getJavaEncoding())); + try { + char[] chars = new char[8192]; + StringBuffer buf = new StringBuffer(); + int count; + while ((count = reader.read(chars, 0, chars.length)) > 0) { + buf.append(chars, 0, count); + } + result = new char[buf.length()]; + buf.getChars(0, result.length, result, 0); + } finally { + reader.close(); + } + } catch (IOException e) { + handleError(-1, -1, e.getMessage()); + } + return result; + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getMainTypeName() + */ + public char[] getMainTypeName() { + int dot = className.lastIndexOf('.'); + if (dot > 0) { + return className.substring(dot + 1).toCharArray(); + } + return className.toCharArray(); + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getPackageName() + */ + public char[][] getPackageName() { + StringTokenizer izer = new StringTokenizer(className.replace('/', '.'), "."); + char[][] result = new char[izer.countTokens()-1][]; + for (int i = 0; i < result.length; i++) { + String tok = izer.nextToken(); + result[i] = tok.toCharArray(); + } + return result; + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[][]) + */ + public NameEnvironmentAnswer findType(char[][] compoundTypeName) { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < compoundTypeName.length; i++) { + if (i > 0) { + result.append("."); + } + result.append(compoundTypeName[i]); + } + return findType(result.toString()); + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#findType(char[], char[][]) + */ + public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < packageName.length; i++) { + if (i > 0) { + result.append("."); + } + result.append(packageName[i]); + } + result.append("."); + result.append(typeName); + return findType(result.toString()); + } + + /** + * @param className + * @return + */ + private NameEnvironmentAnswer findType(String className) { + try { + if (className.equals(this.className)) { + ICompilationUnit compilationUnit = this; + return new NameEnvironmentAnswer(compilationUnit, null); + } + String resourceName = className.replace('.', '/') + ".class"; + InputStream is = options.getClassLoader().getResourceAsStream(resourceName); + if (is != null) { + byte[] classBytes; + byte[] buf = new byte[8192]; + ByteArrayOutputStream baos = + new ByteArrayOutputStream(buf.length); + int count; + while ((count = is.read(buf, 0, buf.length)) > 0) { + baos.write(buf, 0, count); + } + baos.flush(); + classBytes = baos.toByteArray(); + char[] fileName = className.toCharArray(); + ClassFileReader classFileReader = + new ClassFileReader(classBytes, fileName, + true); + return + new NameEnvironmentAnswer(classFileReader, null); + } + } catch (IOException exc) { + handleError(-1, -1, exc.getMessage()); + } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) { + handleError(-1, -1, exc.getMessage()); + } + return null; + } + + private boolean isPackage(String result) { + if (result.equals(this.className)) { + return false; + } + String resourceName = result.replace('.', '/') + ".class"; + InputStream is = options.getClassLoader().getResourceAsStream(resourceName); + return is == null; + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#isPackage(char[][], char[]) + */ + public boolean isPackage(char[][] parentPackageName, char[] packageName) { + StringBuffer result = new StringBuffer(); + if (parentPackageName != null) { + for (int i = 0; i < parentPackageName.length; i++) { + if (i > 0) { + result.append("."); + } + result.append(parentPackageName[i]); + } + } + String str = new String(packageName); + if (Character.isUpperCase(str.charAt(0)) && !isPackage(result.toString())) { + return false; + } + result.append("."); + result.append(str); + return isPackage(result.toString()); + } + + /** + * @see org.eclipse.jdt.internal.compiler.env.INameEnvironment#cleanup() + */ + public void cleanup() { + // EMPTY + } + + /** + * @see org.eclipse.jdt.internal.compiler.ICompilerRequestor#acceptResult(org.eclipse.jdt.internal.compiler.CompilationResult) + */ + public void acceptResult(CompilationResult result) { + try { + if (result.hasErrors()) { + IProblem[] errors = result.getErrors(); + for (int i = 0; i < errors.length; i++) { + IProblem error = errors[i]; + handleError(error.getSourceLineNumber(), -1, error.getMessage()); + } + } else { + ClassFile[] classFiles = result.getClassFiles(); + for (int i = 0; i < classFiles.length; i++) { + ClassFile classFile = classFiles[i]; + char[][] compoundName = classFile.getCompoundName(); + StringBuffer className = new StringBuffer(); + for (int j = 0; j < compoundName.length; j++) { + if (j > 0) { + className.append("."); + } + className.append(compoundName[j]); + } + byte[] bytes = classFile.getBytes(); + final StringBuffer b = new StringBuffer(this.options.getDestinationPath()); + b.append('/'); + b.append(className.toString().replace('.', '/')); + b.append(".class"); + OutputStream fout = ioProvider.getOutputStream(b.toString()); + BufferedOutputStream bos = new BufferedOutputStream(fout); + bos.write(bytes); + bos.close(); + } + } + } catch (IOException exc) { + exc.printStackTrace(); + } + } + + private void handleError(int line, int column, Object errorMessage) { + if (column < 0) column = 0; + errors.add(new CompilerError(this.sourceFile, + true, + line, + column, + line, + column, + errorMessage.toString())); + } + + public List getErrors() throws IOException { + return errors; + } +} diff --git a/src/main/java/org/apache/sling/scripting/java/jdt/EclipseJavaCompiler.java b/src/main/java/org/apache/sling/scripting/java/jdt/EclipseJavaCompiler.java new file mode 100644 index 0000000..8ed73af --- /dev/null +++ b/src/main/java/org/apache/sling/scripting/java/jdt/EclipseJavaCompiler.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.sling.scripting.java.jdt; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.sling.scripting.java.CompilationContext; +import org.apache.sling.scripting.java.CompilerError; +import org.apache.sling.scripting.java.Options; +import org.apache.sling.scripting.java.SlingIOProvider; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; +import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; + +/** + * Eclipse Java Compiler + * + * @version $Id$ + */ +public class EclipseJavaCompiler { + + /** The io provider. */ + private final SlingIOProvider ioProvider; + + /** The compiler options. */ + private final Options compilerOptions; + + /** The compilation context. */ + private final CompilationContext context; + + /** + * Construct a new java compiler. + * @param context + */ + public EclipseJavaCompiler(final CompilationContext context) { + this.ioProvider = context.getIOProvider(); + this.compilerOptions = context.getCompilerOptions(); + this.context = context; + } + + private CompilerOptions getCompilerOptions() { + CompilerOptions options = new CompilerOptions(); + final Map settings = new HashMap(); + settings.put(CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + settings.put(CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + settings.put(CompilerOptions.OPTION_ReportDeprecation, + CompilerOptions.IGNORE); + settings.put(CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.IGNORE); + settings.put(CompilerOptions.OPTION_Encoding, this.compilerOptions.getJavaEncoding()); + if (this.compilerOptions.getClassDebugInfo()) { + settings.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); + } + if ( this.compilerOptions.getCompilerSourceVM().equals("1.6") ) { + settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6); + } else { + settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5); + } + if ( this.compilerOptions.getCompilerTargetVM().equals("1.6") ) { + settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6); + settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); + } else { + settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5); + settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5); + } + + options.set(settings); + return options; + } + + /** + * Compile the java class. + * @return null if no error occured, a list of errors otherwise. + * @throws IOException + */ + public List compile() throws IOException { + final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems(); + final IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault()); + final CompilationUnit unit = new CompilationUnit(this.context.getSourcePath(), + this.context.getJavaClassName(), + this.context.getCompilerOptions(), + this.ioProvider); + + final Compiler compiler = new Compiler(unit, + policy, + getCompilerOptions(), + unit, + problemFactory); + compiler.compile(new CompilationUnit[] {unit}); + if ( unit.getErrors().size() == 0 ) { + return null; + } + return unit.getErrors(); + } + +} -- To stop receiving notification emails like this one, please contact "commits@sling.apache.org" .