You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by we...@apache.org on 2010/04/12 21:43:37 UTC
svn commit: r933379 [6/15] - in /myfaces/extensions/scripting/trunk:
extscript-core-root/extscript-core-java6/src/main/java/org/apache/myfaces/extensions/
extscript-core-root/extscript-core-java6/src/main/java/org/apache/myfaces/extensions/scripting/
e...
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/RecompiledClassLoader.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/RecompiledClassLoader.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/RecompiledClassLoader.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/RecompiledClassLoader.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,138 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java;
+
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <p/>
+ * Classloader which loads the compiled files of the corresponding scripting engine
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+@JavaThrowAwayClassloader
+public class RecompiledClassLoader extends ClassLoader {
+ int _scriptingEngine;
+ String _engineExtension;
+ boolean _unTaintClasses = true;
+ String _sourceRoot;
+ ThrowawayClassloader _throwAwayLoader = null;
+
+ static class _Action implements PrivilegedExceptionAction<ThrowawayClassloader> {
+
+ ClassLoader _parent;
+ Integer _scriptingEngine;
+ String _engineExtension;
+ Boolean _untaint;
+
+ _Action(ClassLoader parent, Integer scriptingEngine, String engineExtension, Boolean untaint) {
+ _parent = parent;
+ this._scriptingEngine = scriptingEngine;
+ this._engineExtension = engineExtension;
+ this._untaint = untaint;
+ }
+
+ _Action(ClassLoader parent, Integer scriptingEngine, String engineExtension) {
+ _parent = parent;
+ _scriptingEngine = scriptingEngine;
+ _engineExtension = engineExtension;
+ _untaint = null;
+ }
+
+ public ThrowawayClassloader run() {
+ if (_untaint != null)
+ return new ThrowawayClassloader(_parent, _scriptingEngine, _engineExtension, _untaint);
+ else
+ return new ThrowawayClassloader(_parent, _scriptingEngine, _engineExtension);
+ }
+ }
+
+ RecompiledClassLoader() {
+ }
+
+
+ public RecompiledClassLoader(final ClassLoader classLoader, final int scriptingEngine, final String engineExtension) {
+ super(classLoader);
+ _scriptingEngine = scriptingEngine;
+ _engineExtension = engineExtension;
+ try {
+ _throwAwayLoader = AccessController.doPrivileged(new _Action(classLoader, scriptingEngine, engineExtension));
+ } catch (PrivilegedActionException e) {
+ logSevere(e);
+ }
+ }
+
+ public RecompiledClassLoader(ClassLoader classLoader, final int scriptingEngine, final String engineExtension, final boolean untaint) {
+ this(classLoader, scriptingEngine, engineExtension);
+ _unTaintClasses = untaint;
+ final ClassLoader _parent = getParent();
+ try {
+ _throwAwayLoader = AccessController.doPrivileged(
+ new _Action(_parent, scriptingEngine, engineExtension, untaint)
+ );
+ } catch (PrivilegedActionException e) {
+ logSevere(e);
+ }
+ }
+
+ private void logSevere(PrivilegedActionException e) {
+ Logger _logger = Logger.getLogger(this.getClass().getName());
+ _logger.log(Level.SEVERE, "", e);
+ }
+
+
+ public InputStream getResourceAsStream(String name) {
+ return _throwAwayLoader.getResourceAsStream(name);
+ }
+
+ @Override
+ public Class<?> loadClass(String className) throws ClassNotFoundException {
+ //check if our class exists in the tempDir
+ final ClassLoader _parent = getParent();
+ try {
+ _throwAwayLoader = AccessController.doPrivileged(
+ new _Action(_parent, _scriptingEngine, _engineExtension, _unTaintClasses)
+ );
+ //_throwAwayLoader.setSourceRoot(getSourceRoot());
+ return _throwAwayLoader.loadClass(className);
+ } catch (PrivilegedActionException e) {
+ logSevere(e);
+ }
+ return null;
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ return _throwAwayLoader.findClassExposed(name);
+ }
+
+ @SuppressWarnings("unused")
+ public String getSourceRoot() {
+ return _sourceRoot;
+ }
+
+ public void setSourceRoot(String sourceRoot) {
+ this._sourceRoot = sourceRoot;
+ }
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ScannerClassloader.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ScannerClassloader.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ScannerClassloader.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ScannerClassloader.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,126 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java;
+
+import org.apache.myfaces.extensions.scripting.core.util.ClassUtils;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+import org.apache.myfaces.extensions.scripting.refresh.RefreshContext;
+import org.apache.myfaces.extensions.scripting.refresh.ReloadingMetadata;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A specialized non tainting classloader for our scanners
+ */
+@SuppressWarnings("unused")
+public class ScannerClassloader extends ClassLoader {
+
+ File _tempDir = null;
+
+ Map<String, Class> _alreadyScanned = new HashMap<String, Class>();
+
+ final Logger _logger = Logger.getLogger(ScannerClassloader.class.getName());
+
+
+ public ScannerClassloader(ClassLoader classLoader, int scriptingEngine, String engineExtension, File tempDir) {
+ super(classLoader);
+
+ this._tempDir = tempDir;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String name) {
+ File resource = new File(_tempDir.getAbsolutePath() + File.separator + name);
+ if (resource.exists()) {
+ try {
+ return new FileInputStream(resource);
+ } catch (FileNotFoundException e) {
+ return super.getResourceAsStream(name);
+ }
+ }
+ return super.getResourceAsStream(name);
+ }
+
+ public File getClassFile(String className) {
+ return ClassUtils.classNameToFile(_tempDir.getAbsolutePath(), className);
+ }
+
+ @Override
+ public Class<?> loadClass(String className) throws ClassNotFoundException {
+ //check if our class exists in the tempDir
+
+ if (_alreadyScanned.containsKey(className)) {
+ return _alreadyScanned.get(className);
+ }
+
+ File target = getClassFile(className);
+ if (!target.exists()) {
+ return super.loadClass(className);
+ }
+
+ ReloadingMetadata data = WeavingContext.getFileChangedDaemon().getClassMap().get(className);
+ if (data != null && !data.isTainted()) {
+ return data.getAClass();
+ }
+
+ FileInputStream iStream = null;
+
+ int fileLength;
+ byte[] fileContent;
+ try {
+ //we cannot load while a compile is in progress
+ //we have to wait until it is one
+ synchronized (RefreshContext.COMPILE_SYNC_MONITOR) {
+ fileLength = (int) target.length();
+ fileContent = new byte[fileLength];
+ iStream = new FileInputStream(target);
+ int len = iStream.read(fileContent);
+ if (_logger.isLoggable(Level.FINER)) {
+ _logger.log(Level.FINER, "class read {0}� bytes read", String.valueOf(len));
+ }
+ }
+
+ //we have to do it here because just in case
+ //a dependent class is loaded as well we run into classcast exceptions
+ Class retVal = super.defineClass(className, fileContent, 0, fileLength);
+ _alreadyScanned.put(className, retVal);
+ return retVal;
+
+ } catch (FileNotFoundException e) {
+ throw new ClassNotFoundException(e.toString());
+ } catch (IOException e) {
+ throw new ClassNotFoundException(e.toString());
+ } finally {
+ if (iStream != null) {
+ try {
+ iStream.close();
+ } catch (Exception e) {
+ _logger.log(Level.SEVERE, "", e);
+ }
+ }
+ }
+
+ }
+
+}
+
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ThrowawayClassloader.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ThrowawayClassloader.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ThrowawayClassloader.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/ThrowawayClassloader.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,206 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java;
+
+import org.apache.myfaces.extensions.scripting.core.util.ClassUtils;
+import org.apache.myfaces.extensions.scripting.core.util.FileUtils;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+import org.apache.myfaces.extensions.scripting.refresh.RefreshContext;
+import org.apache.myfaces.extensions.scripting.refresh.ReloadingMetadata;
+
+import java.io.*;
+import java.util.Collection;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static java.util.logging.Level.*;
+
+/**
+ * we move the throw away mechanism into our classloader for cleaner code coverage
+ */
+@JavaThrowAwayClassloader
+@SuppressWarnings("unused")
+public class ThrowawayClassloader extends ClassLoader {
+
+ static final Logger _logger = Logger.getLogger(ThrowawayClassloader.class.getName());
+
+ int _scriptingEngine;
+ String _engineExtension;
+
+
+ public ThrowawayClassloader(ClassLoader classLoader, int scriptingEngine, String engineExtension) {
+ super(classLoader);
+
+ synchronized (this.getClass()) {
+ _scriptingEngine = scriptingEngine;
+ _engineExtension = engineExtension;
+ }
+ }
+
+ public ThrowawayClassloader(ClassLoader classLoader, int scriptingEngine, String engineExtension, boolean untaint) {
+ this(classLoader, scriptingEngine, engineExtension);
+
+ }
+
+ ThrowawayClassloader() {
+ }
+
+ /*
+ * TODO the classcast exception is caused by a loadClassInternal triggered
+ * at the time the referencing class is loaded and then by another classload
+ * at the time the bean is refreshed
+ *
+ * we have to check if a class is loaded by loadClassInternal then
+ * no other refresh should happen but the loaded class should be issued again)
+ *
+ * Dont know how to resolve that for now
+ */
+
+ @Override
+ public InputStream getResourceAsStream(String name) {
+ File resource = new File(WeavingContext.getConfiguration().getCompileTarget().getAbsolutePath() + File.separator + name);
+ if (resource.exists()) {
+ try {
+ return new FileInputStream(resource);
+ } catch (FileNotFoundException e) {
+ return super.getResourceAsStream(name);
+ }
+ }
+ return super.getResourceAsStream(name);
+ }
+
+ @Override
+ public Class<?> loadClass(String className) throws ClassNotFoundException {
+ //check if our class exists in the tempDir
+
+ File target = getClassFile(className);
+ if (target.exists()) {
+ _logger.log(Level.INFO,"[EXT-SCRIPTING] target {0} exists", className);
+
+ ReloadingMetadata data = WeavingContext.getFileChangedDaemon().getClassMap().get(className);
+ if (data != null && !data.isTainted()) {
+ _logger.info("[EXT-SCRIPTING] data found but not tainted yet");
+
+ return data.getAClass();
+ }
+ _logger.log(Level.FINER,"[EXT-SCRIPTING] loading class {0} from filesystem", className);
+
+ FileInputStream iStream = null;
+
+ int fileLength;
+ byte[] fileContent;
+ try {
+ //we cannot load while a compile is in progress
+ //we have to wait until it is one
+ synchronized (RefreshContext.COMPILE_SYNC_MONITOR) {
+ fileLength = (int) target.length();
+ fileContent = new byte[fileLength];
+ iStream = new FileInputStream(target);
+ int result = iStream.read(fileContent);
+ _logger.log(Level.FINER, "read {0} bytes", String.valueOf(result));
+ }
+
+ Class retVal;
+
+ //we have to do it here because just in case
+ //a dependent class is loaded as well we run into classcast exceptions
+ if (data != null) {
+ data.setTainted(false);
+
+ retVal = super.defineClass(className, fileContent, 0, fileLength);
+
+ data.setAClass(retVal);
+ return retVal;
+ } else {
+ //we store the initial reloading meta data information so that it is refreshed
+ //later on, this we we cover dependent classes on the initial load
+ return storeReloadableDefinitions(className, fileLength, fileContent);
+ }
+
+ } catch (FileNotFoundException e) {
+ throw new ClassNotFoundException(e.toString());
+ } catch (IOException e) {
+ throw new ClassNotFoundException(e.toString());
+ } finally {
+ if (iStream != null) {
+ try {
+ iStream.close();
+ } catch (Exception e) {
+ Logger log = Logger.getLogger(this.getClass().getName());
+ log.log(SEVERE, "", e);
+ }
+ }
+ }
+ }
+ _logger.log(Level.FINER,"[EXT-SCRIPTING] target {0} does not exist", target.getAbsolutePath());
+ return super.loadClass(className);
+ }
+
+ private Class<?> storeReloadableDefinitions(String className, int fileLength, byte[] fileContent) {
+ Class retVal;
+ retVal = super.defineClass(className, fileContent, 0, fileLength);
+ ReloadingMetadata reloadingMetaData = new ReloadingMetadata();
+ reloadingMetaData.setAClass(retVal);
+ //find the source for the given class and then
+ //store the filename
+ String separator = FileUtils.getFileSeparatorForRegex();
+ String fileName = className.replaceAll("\\.", separator) + getStandardFileExtension();
+ Collection<String> sourceDirs = WeavingContext.getConfiguration().getSourceDirs(_scriptingEngine);
+ String rootDir = null;
+ File sourceFile = null;
+ for (String sourceDir : sourceDirs) {
+ String fullPath = sourceDir + File.separator + fileName;
+ sourceFile = new File(fullPath);
+ if (sourceFile.exists()) {
+ rootDir = sourceDir;
+ break;
+ }
+ }
+
+ if (rootDir == null) {
+ Logger log = Logger.getLogger(this.getClass().getName());
+ log.log(WARNING, "Warning source for class: {0} could not be found", className);
+ return retVal;
+ }
+
+ reloadingMetaData.setFileName(fileName);
+ reloadingMetaData.setSourcePath(rootDir);
+ reloadingMetaData.setTimestamp(sourceFile.lastModified());
+ reloadingMetaData.setTainted(false);
+ reloadingMetaData.setTaintedOnce(true);
+ reloadingMetaData.setScriptingEngine(_scriptingEngine);
+
+ WeavingContext.getFileChangedDaemon().getClassMap().put(className, reloadingMetaData);
+ return retVal;
+ }
+
+ protected String getStandardFileExtension() {
+ return _engineExtension;
+ }
+
+ protected Class<?> findClassExposed(String name) throws ClassNotFoundException {
+ return super.findClass(name);
+ }
+
+ public File getClassFile(String className) {
+ return ClassUtils.classNameToFile(WeavingContext.getConfiguration().getCompileTarget().getAbsolutePath(), className);
+ }
+
+
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/CompilerFacade.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/CompilerFacade.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/CompilerFacade.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/CompilerFacade.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,172 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java.compiler;
+
+import org.apache.myfaces.extensions.scripting.api.CompilationException;
+import org.apache.myfaces.extensions.scripting.api.CompilationResult;
+import org.apache.myfaces.extensions.scripting.api.DynamicCompiler;
+import org.apache.myfaces.extensions.scripting.api.ScriptingConst;
+import org.apache.myfaces.extensions.scripting.core.util.ClassUtils;
+import org.apache.myfaces.extensions.scripting.core.util.FileUtils;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+import org.apache.myfaces.extensions.scripting.loaders.java.RecompiledClassLoader;
+
+import java.io.File;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ * <p/>
+ * Custom compiler call for jdk5
+ * we can call javac directly
+ */
+@SuppressWarnings("unused")
+public class CompilerFacade implements DynamicCompiler {
+ protected org.apache.myfaces.extensions.scripting.api.Compiler _compiler = null;
+
+ Logger _log = Logger.getLogger(this.getClass().getName());
+
+ static final PrivilegedExceptionAction<RecompiledClassLoader> CLASSLOADER_ACTION = new PrivilegedExceptionAction<RecompiledClassLoader>() {
+ public RecompiledClassLoader run() {
+ return new RecompiledClassLoader(ClassUtils.getContextClassLoader(), ScriptingConst.ENGINE_TYPE_JSF_JAVA, ".java");
+
+ }
+ };
+
+ public CompilerFacade() {
+ super();
+
+ _compiler = JavaCompilerFactory.getInstance().getCompilerInstance();
+ }
+
+ public CompilerFacade(boolean allowJSR) {
+ super();
+
+ _compiler = JavaCompilerFactory.getInstance().getCompilerInstance(allowJSR);
+ }
+
+ /**
+ * does a compilation of all files one compile per request
+ * is allowed for performance reasons, the request blocking will be done
+ * probably on the caller side of things
+ *
+ * @param sourceRoot the source root of our files to be compiled
+ * @param classPath the corresponding classpath
+ */
+
+ public void compileAll(String sourceRoot, String classPath) {
+ try {
+ //TODO do a full compile and block the compile for the rest of the request
+ //so that we do not run into endless compile cycles
+
+ /*
+ * privilege block to allow custom classloading only
+ * in case of having the privileges,
+ * this was proposed by the checkstyle plugin
+ */
+ RecompiledClassLoader classLoader = getRecompiledClassLoader();
+
+ classLoader.setSourceRoot(sourceRoot);
+ CompilationResult result = _compiler.compile(new File(sourceRoot), WeavingContext.getConfiguration().getCompileTarget(), classLoader);
+ displayMessages(result);
+ if (result.hasErrors()) {
+ _log.log(Level.WARNING, "Compiler output:{0}", result.getCompilerOutput());
+ }
+
+ } catch (org.apache.myfaces.extensions.scripting.api.CompilationException e) {
+ _log.log(Level.SEVERE, "CompilationException : ", e);
+ }
+ }
+
+ private RecompiledClassLoader getRecompiledClassLoader() {
+ try {
+ return AccessController.doPrivileged(CLASSLOADER_ACTION);
+ } catch (PrivilegedActionException e) {
+ _log.log(Level.SEVERE, "", e);
+ }
+ return null;
+ }
+
+ public Class compileFile(String sourceRoot, String classPath, String filePath) throws ClassNotFoundException {
+
+ String separator = FileUtils.getFileSeparatorForRegex();
+ String className = filePath.replaceAll(separator, ".");
+ className = ClassUtils.relativeFileToClassName(className);
+ RecompiledClassLoader classLoader = getRecompiledClassLoader();
+
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ try
+
+ {
+ classLoader.setSourceRoot(sourceRoot);
+ Thread.currentThread().setContextClassLoader(classLoader);
+
+ return classLoader.loadClass(className);
+ }
+
+ finally
+
+ {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+
+ }
+
+ /**
+ * compiles all files
+ *
+ * @param sourceRoot the source root
+ * @param classPath the class path
+ * @return the root target path for the classes which are compiled
+ * so that they later can be picked up by the classloader
+ * @throws ClassNotFoundException
+ */
+
+ public File compileAllFiles(String sourceRoot, String classPath) throws ClassNotFoundException {
+ try {
+ RecompiledClassLoader classLoader = getRecompiledClassLoader();
+
+ CompilationResult result = _compiler.compile(new File(sourceRoot), WeavingContext.getConfiguration().getCompileTarget(), classLoader);
+
+ classLoader.setSourceRoot(sourceRoot);
+ displayMessages(result);
+ return WeavingContext.getConfiguration().getCompileTarget();
+ } catch (CompilationException e) {
+ _log.log(Level.SEVERE, "CompilationException :", e);
+ }
+ return null;
+ }
+
+ private void displayMessages(CompilationResult result) {
+ for (CompilationResult.CompilationMessage error : result.getErrors()) {
+ _log.log(Level.WARNING, "[EXT-SCRIPTING] Compile Error: {0} - {1}", new String[]{Long.toString(error.getLineNumber()), error.getMessage()});
+
+ }
+ for (CompilationResult.CompilationMessage error : result.getWarnings()) {
+ _log.warning(error.getMessage());
+ }
+ }
+
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavaCompilerFactory.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavaCompilerFactory.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavaCompilerFactory.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavaCompilerFactory.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,67 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java.compiler;
+
+import org.apache.myfaces.extensions.scripting.api.*;
+import org.apache.myfaces.extensions.scripting.api.Compiler;
+import org.apache.myfaces.extensions.scripting.core.util.ReflectUtil;
+
+/**
+ *
+ */
+public class JavaCompilerFactory {
+ /**
+ * since the object is stateless
+ * declaring it volatile should be enough instead
+ * of using synchronized blocks
+ * please if you introduce statefulness here
+ * we have to add synchronized
+ */
+ private static volatile JavaCompilerFactory _instance = new JavaCompilerFactory();
+
+ public static JavaCompilerFactory getInstance() {
+ if (_instance == null) {
+ _instance = new JavaCompilerFactory();
+ }
+ return _instance;
+ }
+
+ private String getScriptingFacadeClass(boolean allowJSR) {
+ String javaVer = System.getProperty("java.version");
+ String[] versionArr = javaVer.split("\\.");
+
+ int major = Integer.parseInt(versionArr[Math.min(versionArr.length, 1)]);
+
+ if (major > 5 && allowJSR) {
+ //jsr199 compliant jdk
+ return ScriptingConst.JSR199_COMPILER;
+ }
+ //otherwise
+ return ScriptingConst.JAVA5_COMPILER;
+ }
+
+ public org.apache.myfaces.extensions.scripting.api.Compiler getCompilerInstance() {
+ return (Compiler) ReflectUtil.instantiate(getScriptingFacadeClass(true));
+ }
+
+ public org.apache.myfaces.extensions.scripting.api.Compiler getCompilerInstance(boolean allowJSR) {
+ return (Compiler) ReflectUtil.instantiate(getScriptingFacadeClass(allowJSR));
+ }
+
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavacCompiler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavacCompiler.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavacCompiler.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/loaders/java/compiler/JavacCompiler.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,375 @@
+/*
+ * 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.myfaces.extensions.scripting.loaders.java.compiler;
+
+import org.apache.myfaces.extensions.scripting.api.CompilationException;
+import org.apache.myfaces.extensions.scripting.api.CompilationResult;
+import org.apache.myfaces.extensions.scripting.api.CompilerConst;
+import org.apache.myfaces.extensions.scripting.api.ScriptingConst;
+import org.apache.myfaces.extensions.scripting.core.util.ClassLoaderUtils;
+import org.apache.myfaces.extensions.scripting.core.util.ClassUtils;
+import org.apache.myfaces.extensions.scripting.core.util.FileUtils;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <p>A compiler implementation that utilizes some internal classes that enable you to
+ * compile Java source code using the javac compiler being provided by your JDK. However,
+ * note that this only works if you're using a Sun JDK up to the version 1.5 (as of Java 6
+ * you should use the JSR-199 API).</p>
+ * <p/>
+ * <p>This class loads some internal classes from $JAVA_HOME$/lib/tools.jar so be sure to
+ * either include this JAR file in your classpath at startup or set the JAVA_HOME property
+ * accordingly so that it points to a valid JDK home directory (it doesn't work if you're
+ * just using a JRE!)</p>
+ */
+public class JavacCompiler implements org.apache.myfaces.extensions.scripting.api.Compiler {
+
+ /**
+ * The logger instance for this class.
+ */
+ private static final Logger _logger = Logger.getLogger(JavacCompiler.class.getName());
+
+ /**
+ * The class name of the javac compiler. Note that this class
+ * is only available if you're using a Sun JDK.
+ */
+ private static final String JAVAC_MAIN = "com.sun.tools.javac.Main";
+
+ /**
+ * The class reference to the internal Javac compiler.
+ */
+ private Class _compilerClass;
+
+ // ------------------------------------------ Constructors
+
+ /**
+ * <p>Creates a new Javac compiler by searching for the required JAR file '$JAVA_HOME$/lib/tools.jar'
+ * automatically. Note that the user has to specify the JAVA_HOME property in this case.</p>
+ */
+ public JavacCompiler() {
+ this(null);
+ }
+
+ /**
+ * <p>Creates a new Javac compiler by searching for internal classes in the given JAR file.</p>
+ *
+ * @param toolsJar the location of the JAR file '$JAVA_HOME$/lib/tools.jar' or <code>null</code>
+ * if you want it to be searched for automatically
+ */
+ public JavacCompiler(URL toolsJar) {
+ ClassLoader classLoader;
+
+ try {
+ classLoader = createJavacAwareClassLoader(toolsJar);
+ } catch (MalformedURLException ex) {
+ throw new IllegalStateException("An error occured while trying to load the Javac compiler class.", ex);
+ }
+
+ try {
+ this._compilerClass = classLoader.loadClass(JAVAC_MAIN);
+ } catch (ClassNotFoundException ex) {
+ throw new IllegalStateException("The Javac compiler class '" + JAVAC_MAIN + "' couldn't be found even though" +
+ "the required JAR file '$JAVA_HOME$/lib/tools.jar' has been put on the classpath. Are you sure that " +
+ "you're using a valid Sun JDK?");
+ }
+ }
+
+ // ------------------------------------------ Compiler methods
+
+ /**
+ * <p>Compiles the given file and creates an according class file in the given target path.</p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @return the compilation result, i.e. as of now only the compiler output
+ */
+ public CompilationResult compile(File sourcePath, File targetPath, ClassLoader loader) throws CompilationException {
+ FileUtils.assertPath(targetPath);
+
+ try {
+ StringWriter compilerOutput = new StringWriter();
+ // Invoke the Javac compiler
+ Method compile = _compilerClass.getMethod("compile", new Class[]{String[].class, PrintWriter.class});
+ Object[] compilerArguments = new Object[]{buildCompilerArgumentsWhitelisted(sourcePath, targetPath, loader), new PrintWriter(compilerOutput)};
+ logCommandLine(compilerArguments);
+
+ Integer returnCode = (Integer) compile.invoke(null, compilerArguments);
+
+ CompilationResult result = new CompilationResult(compilerOutput.toString());
+ if (returnCode == null || returnCode.intValue() != 0) {
+ result.registerError(new CompilationResult.CompilationMessage(-1,
+ "Executing the javac compiler failed. The return code is '" + returnCode + "'." + compilerOutput.toString()));
+ }
+ WeavingContext.setCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_JAVA, result);
+ return result;
+ } catch (NoSuchMethodException ex) {
+ throw new CompilationException("The Javac compiler class '" + _compilerClass + "' doesn't provide the method " +
+ "compile(String, PrintWriter). Are you sure that you're using a valid Sun JDK?", ex);
+ } catch (InvocationTargetException ex) {
+ throw new CompilationException("An error occured while invoking the compile(String, PrintWriter) method of the " +
+ "Javac compiler class '" + _compilerClass + "'. Are you sure that you're using a valid Sun JDK?", ex);
+ } catch (IllegalAccessException ex) {
+ throw new CompilationException("An error occured while invoking the compile(String, PrintWriter) method of the " +
+ "Javac compiler class '" + _compilerClass + "'. Are you sure that you're using a valid Sun JDK?", ex);
+ }
+
+ }
+
+ /**
+ * <p>Compiles the given file and creates an according class file in the given target path.</p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @param file the relative file name of the class you want to compile
+ * @return the compilation result, i.e. as of now only the compiler output
+ */
+ public CompilationResult compile(File sourcePath, File targetPath, File file, ClassLoader loader) throws CompilationException {
+ // The destination directory must already exist as javac will not create the destination directory.
+ FileUtils.assertPath(targetPath);
+
+ try {
+ StringWriter compilerOutput = new StringWriter();
+
+ // Invoke the Javac compiler
+ Method compile = _compilerClass.getMethod("compile", new Class[]{String[].class, PrintWriter.class});
+ if (!targetPath.exists()) {
+ if (!targetPath.mkdirs()) {
+ throw new IllegalStateException("It wasn't possible to create the target " +
+ "directory for the compiler ['" + targetPath.getAbsolutePath() + "'].");
+ }
+ }
+
+ //TODO make a whitelist check here
+ Object[] compilerArguments = new Object[]{buildCompilerArguments(sourcePath, targetPath, file.getAbsolutePath(), loader), new PrintWriter(compilerOutput)};
+ logCommandLine(compilerArguments);
+
+ Integer returnCode = (Integer) compile.invoke(null,
+ compilerArguments);
+
+ CompilationResult result = new CompilationResult(compilerOutput.toString());
+ if (returnCode == null || returnCode != 0) {
+ result.registerError(new CompilationResult.CompilationMessage(-1,
+ "Executing the javac compiler failed. The return code is '" + returnCode + "'." + compilerOutput.toString()));
+ }
+ WeavingContext.setCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_JAVA, result);
+ return result;
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException("The Javac compiler class '" + _compilerClass + "' doesn't provide the method " +
+ "compile(String, PrintWriter). Are you sure that you're using a valid Sun JDK?", ex);
+ } catch (InvocationTargetException ex) {
+ throw new IllegalStateException("An error occured while invoking the compile(String, PrintWriter) method of the " +
+ "Javac compiler class '" + _compilerClass + "'. Are you sure that you're using a valid Sun JDK?", ex);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalStateException("An error occured while invoking the compile(String, PrintWriter) method of the " +
+ "Javac compiler class '" + _compilerClass + "'. Are you sure that you're using a valid Sun JDK?", ex);
+ }
+ }
+
+ private void logCommandLine(Object[] compilerArguments) {
+ if (_logger.isLoggable(Level.FINE)) {
+ StringBuilder commandLine = new StringBuilder();
+ commandLine.append("javac ");
+ for (String compilerArgument : (String[]) compilerArguments[0]) {
+ commandLine.append(compilerArgument);
+ commandLine.append(" ");
+ }
+ _logger.log(Level.FINE, commandLine.toString());
+ }
+ if (_logger.isLoggable(Level.INFO)) {
+ _logger.info("[EXT-SCRIPTING] compiling java");
+ }
+
+ }
+
+ // ------------------------------------------ Utility methods
+
+ /**
+ * <p/>
+ * Creates the arguments for the compiler, i.e. builds up an array of arguments
+ * that one would pass to the javac compiler to compile a full path instead of a single file
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @return an array of arguments that you have to pass to the Javac compiler
+ */
+ protected String[] buildCompilerArgumentsWhitelisted(File sourcePath, File targetPath, ClassLoader loader) {
+ List<File> sourceFiles = FileUtils.fetchSourceFiles(WeavingContext.getConfiguration().getWhitelistedSourceDirs(ScriptingConst.ENGINE_TYPE_JSF_JAVA), "*.java");
+
+ List arguments = getDefaultArguments(sourcePath, targetPath, loader);
+
+ // Append the source file that is to be compiled. Note that the user specifies only a relative file location.
+ for (File sourceFile : sourceFiles) {
+ arguments.add(sourceFile.getAbsolutePath());
+ }
+ return (String[]) argumentsToArray(arguments);
+ }
+
+ private Object[] argumentsToArray(List arguments) {
+ return arguments.toArray(new String[arguments.size()]);
+ }
+
+ /**
+ * <p/>
+ * Creates the arguments for the compiler, i.e. builds up an array of arguments
+ * that one would pass to the javac compiler to compile a full path instead of a single file
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @return an array of arguments that you have to pass to the Javac compiler
+ */
+ protected String[] buildCompilerArguments(File sourcePath, File targetPath, ClassLoader loader) {
+ List<File> sourceFiles = FileUtils.fetchSourceFiles(sourcePath, "*.java");
+
+ List arguments = getDefaultArguments(sourcePath, targetPath, loader);
+
+ // Append the source file that is to be compiled. Note that the user specifies only a relative file location.
+ for (File sourceFile : sourceFiles) {
+ arguments.add(sourceFile.getAbsolutePath());
+ }
+ return (String[]) argumentsToArray(arguments);
+ }
+
+ /**
+ * <p>Creates the arguments for the compiler, i.e. it builds an array of arguments that one would pass to
+ * the Javac compiler on the command line.</p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @param loader the classpath holder for the compiler
+ * @param file the relative file name of the class you want to compile
+ * @return an array of arguments that you have to pass to the Javac compiler
+ */
+ protected String[] buildCompilerArguments(File sourcePath, File targetPath, String file, ClassLoader loader) {
+ List arguments = getDefaultArguments(sourcePath, targetPath, loader);
+
+ // Append the source file that is to be compiled. Note that the user specifies only a relative file location.
+ arguments.add(new File(sourcePath, file).getAbsolutePath());
+
+ return (String[]) argumentsToArray(arguments);
+ }
+
+ /**
+ * <p>
+ * Determination of the default arguments
+ * which have to be the same over all
+ * different compilation strategies
+ * </p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @param loader the classloader holding the classpath
+ * @return
+ */
+ private List getDefaultArguments(File sourcePath, File targetPath, ClassLoader loader) {
+ List arguments = new ArrayList();
+
+ // Set both the source code path to search for class or interface
+ // definitions and the destination directory for class files.
+ arguments.add(CompilerConst.JC_SOURCEPATH);
+ arguments.add(sourcePath.getAbsolutePath());
+ arguments.add(CompilerConst.JC_TARGET_PATH);
+ arguments.add(targetPath.getAbsolutePath());
+ arguments.add(CompilerConst.JC_CLASSPATH);
+ arguments.add(ClassLoaderUtils.buildClasspath(loader));
+
+ // Enable verbose output.
+ arguments.add(CompilerConst.JC_VERBOSE);
+
+ // Generate all debugging information, including local variables.
+ arguments.add(CompilerConst.JC_DEBUG);
+ return arguments;
+ }
+
+ /**
+ * <p>Returns a possibly newly created classloader that you can use in order to load the
+ * Javac compiler class. Usually the user would have to put the JAR file
+ * '$JAVA_HOME$/lib/tools.jar' on the classpath but this method recognizes this on its own
+ * and loads the JAR file if necessary. However, it's not guaranteed that the Javac compiler
+ * class is available (e.g. if one is providing a wrong tools.jar file that doesn't contain
+ * the required classes).</p>
+ *
+ * @param toolsJar the location of the JAR file '$JAVA_HOME$/lib/tools.jar' or <code>null</code>
+ * if you want it to be searched for automatically
+ * @return a classloader that you can use in order to load the Javac compiler class
+ * @throws MalformedURLException if an error occurred while constructing the URL
+ */
+ private static ClassLoader createJavacAwareClassLoader(URL toolsJar) throws MalformedURLException {
+ // If the user has already included the tools.jar in the classpath we don't have
+ // to create a custom class loader as the class is already available.
+ if (ClassUtils.isPresent(JAVAC_MAIN)) {
+ if (_logger.isLoggable(Level.FINE)) {
+ _logger.log(Level.FINE, "Seemingly the required JAR file '$JAVA_HOME$/lib/tools.jar' has already been "
+ + "put on the classpath as the class '" + JAVAC_MAIN + "' is present. So there's no "
+ + "need to create a custom classloader for the Javac compiler.");
+ }
+
+ return ClassUtils.getContextClassLoader();
+ } else {
+ // The compiler isn't available in the current classpath, but the user could have specified the tools.jar file.
+ if (toolsJar == null) {
+ String javaHome = System.getProperty("java.home");
+ if (javaHome.toLowerCase(Locale.getDefault()).endsWith(File.separator + "jre")) {
+ // Note that even if the user has installed a valid JDK the $JAVA_HOME$ property might reference
+ // the JRE, e.g. '/usr/lib/jvm/java-6-sun-1.6.0.16/jre'. However, in this case we just have to
+ // remove the last four characters (i.e. the '/jre').
+ javaHome = javaHome.substring(0, javaHome.length() - 4);
+ }
+
+ // If the user hasn't specified the URL to the tools.jar file, we'll try to find it on our own.
+ File toolsJarFile = new File(javaHome, "lib" + File.separatorChar + "tools.jar");
+ if (toolsJarFile.exists()) {
+ if (_logger.isLoggable(Level.FINE)) {
+ _logger.log(Level.FINE,
+ "The required JAR file '$JAVA_HOME$/lib/tools.jar' has been found ['" + toolsJarFile.getAbsolutePath()
+ + "']. A custom URL classloader will be created for the Javac compiler.");
+ }
+
+ return new URLClassLoader(
+ new URL[]{toolsJarFile.toURI().toURL()}, ClassUtils.getContextClassLoader());
+ } else {
+ throw new IllegalStateException("The Javac compiler class '" + JAVAC_MAIN + "' and the required JAR file " +
+ "'$JAVA_HOME$/lib/tools.jar' couldn't be found. Are you sure that you're using a valid Sun JDK? " +
+ "[$JAVA_HOME$: '" + System.getProperty("java.home") + "']");
+ }
+ } else {
+ if (_logger.isLoggable(Level.FINE)) {
+ _logger.log(Level.FINE, "The user has specified the required JAR file '$JAVA_HOME$/lib/tools.jar' ['"
+ + toolsJar.toExternalForm() + "']. A custom URL classloader will be created for the Javac compiler.");
+ }
+
+ return new URLClassLoader(new URL[]{toolsJar}, ClassUtils.getContextClassLoader());
+ }
+ }
+ }
+
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/FileChangedDaemon.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/FileChangedDaemon.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/FileChangedDaemon.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/FileChangedDaemon.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,253 @@
+/*
+ * 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.myfaces.extensions.scripting.refresh;
+
+import org.apache.myfaces.extensions.scripting.api.ScriptingConst;
+import org.apache.myfaces.extensions.scripting.api.ScriptingWeaver;
+import org.apache.myfaces.extensions.scripting.core.dependencyScan.core.ClassDependencies;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+
+import javax.servlet.ServletContext;
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Central daemon thread which watches the resources
+ * for changes and marks them as changed.
+ * This watchdog daemon is the central core
+ * of the entire scripting engine it runs asynchronously
+ * to your program and keeps an eye on the resources
+ * and their dependencies, once a file has changed
+ * all the referring dependencies are also marked
+ * as being to reloaded.
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class FileChangedDaemon extends Thread {
+
+ private static final String CONTEXT_KEY = "extscriptDaemon";
+
+ static FileChangedDaemon _instance = null;
+
+ Map<String, ReloadingMetadata> _classMap = new ConcurrentHashMap<String, ReloadingMetadata>(8, 0.75f, 1);
+ ClassDependencies _dependencyMap = new ClassDependencies();
+
+ /**
+ * This map is a shortcut for the various scripting engines.
+ * It keeps track whether the engines source paths
+ * have dirty files or not and if true we enforce a recompile at the
+ * next refresh!
+ * <p/>
+ * We keep track on engine level to avoid to search the classMap for every refresh
+ * the classMap still is needed for various identification tasks which are reload
+ * related
+ */
+ Map<Integer, Boolean> _systemRecompileMap = new ConcurrentHashMap<Integer, Boolean>(8, 0.75f, 1);
+
+ boolean _running = false;
+ boolean _contextInitialized = false;
+ Logger _log = Logger.getLogger(FileChangedDaemon.class.getName());
+ ScriptingWeaver _weavers = null;
+ static WeakReference<ServletContext> _externalContext;
+
+ public static synchronized void startup(ServletContext externalContext) {
+ if (_externalContext != null) return;
+ _externalContext = new WeakReference<ServletContext>(externalContext);
+
+ //we currently keep it as singleton but in the long run we will move it into the context
+ //like everything else singleton-wise
+ if (WeavingContext.isScriptingEnabled() && _instance == null) {
+ _instance = new FileChangedDaemon();
+ externalContext.setAttribute(CONTEXT_KEY, _instance);
+ /**
+ * daemon thread to allow forced
+ * shutdowns for web context restarts
+ */
+ _instance.setDaemon(true);
+ _instance.setRunning(true);
+ _instance.start();
+
+ }
+
+ }
+
+ public static synchronized void clear() {
+
+ }
+
+ public static synchronized FileChangedDaemon getInstance() {
+ //we do it in this complicated manner because of find bugs
+ //practically this cannot really happen except for shutdown were it is not important anymore
+ ServletContext context = _externalContext.get();
+ if (context != null) {
+ return (FileChangedDaemon) context.getAttribute(CONTEXT_KEY);
+ }
+ return null;
+ //return (FileChangedDaemon) ((ServletContext) _externalContext.get()).getAttribute(CONTEXT_KEY);
+ }
+
+ /**
+ * Central run method
+ * which performs the entire scanning process
+ */
+ public void run() {
+ while (WeavingContext.isScriptingEnabled() && _running) {
+ if (_externalContext != null && _externalContext.get() != null && !_contextInitialized) {
+ WeavingContext.initThread((ServletContext) _externalContext.get());
+ _contextInitialized = true;
+ }
+ try {
+ try {
+ Thread.sleep(ScriptingConst.TAINT_INTERVAL);
+ } catch (InterruptedException e) {
+ //if the server shuts down while we are in sleep we get an error
+ //which we better should swallow
+ }
+
+ if (_classMap == null || _classMap.size() == 0)
+ continue;
+ if (_contextInitialized)
+ checkForChanges();
+ } catch (Throwable e) {
+ _log.log(Level.SEVERE, "[EXT-SCRIPTING]", e);
+
+ }
+ }
+ if (_log.isLoggable(Level.INFO)) {
+ _log.info("[EXT-SCRIPTING] Dynamic reloading watch daemon is shutting down");
+ }
+ }
+
+ /**
+ * central tainted mark method which keeps
+ * track if some file in one of the supported engines has changed
+ * and if yes marks the file as tainted as well
+ * as marks the engine as having to do a full recompile
+ */
+ private final void checkForChanges() {
+ ScriptingWeaver weaver = WeavingContext.getWeaver();
+ if (weaver == null) return;
+ weaver.scanForAddedClasses();
+
+ for (Map.Entry<String, ReloadingMetadata> it : this._classMap.entrySet()) {
+
+ File proxyFile = new File(it.getValue().getSourcePath() + File.separator + it.getValue().getFileName());
+ if (isModified(it, proxyFile)) {
+
+ _systemRecompileMap.put(it.getValue().getScriptingEngine(), Boolean.TRUE);
+ ReloadingMetadata meta = it.getValue();
+ meta.setTainted(true);
+ meta.setTaintedOnce(true);
+ printInfo(it, proxyFile);
+ meta.setTimestamp(proxyFile.lastModified());
+ dependencyTainted(meta.getAClass().getName());
+
+ //we add our log entry for further reference
+ WeavingContext.getRefreshContext().addTaintLogEntry(meta);
+ }
+ //}
+ }
+ //we clean up the taint log
+ WeavingContext.getRefreshContext().gcTaintLog();
+ }
+
+ /**
+ * recursive walk over our meta data to taint also the classes
+ * which refer to our refreshing class so that those
+ * are reloaded as well, this helps to avoid classcast
+ * exceptions caused by imports and casts on long running artifacts
+ *
+ * @param className the origin classname which needs to be walked recursively
+ */
+ private void dependencyTainted(String className) {
+ Set<String> referrers = _dependencyMap.getReferringClasses(className);
+ if (referrers == null) return;
+ for (String referrer : referrers) {
+ ReloadingMetadata metaData = _classMap.get(referrer);
+ if (metaData == null) continue;
+ if (metaData.isTainted()) continue;
+ printInfo(metaData);
+
+ metaData.setTainted(true);
+ metaData.setTaintedOnce(true);
+ dependencyTainted(metaData.getAClass().getName());
+ WeavingContext.getRefreshContext().addTaintLogEntry(metaData);
+ }
+ }
+
+ private final boolean isModified(Map.Entry<String, ReloadingMetadata> it, File proxyFile) {
+ return proxyFile.lastModified() != it.getValue().getTimestamp();
+ }
+
+ private void printInfo(ReloadingMetadata it) {
+ if (_log.isLoggable(Level.INFO)) {
+ _log.log(Level.INFO, "[EXT-SCRIPTING] Tainting Dependency: {0}", it.getFileName());
+ }
+ }
+
+ private void printInfo(Map.Entry<String, ReloadingMetadata> it, File proxyFile) {
+ if (_log.isLoggable(Level.INFO)) {
+ _log.log(Level.INFO, "[EXT-SCRIPTING] comparing {0} Dates: {1} {2} ", new String[]{it.getKey(), Long.toString(proxyFile.lastModified()), Long.toString(it.getValue().getTimestamp())});
+ _log.log(Level.INFO, "[EXT-SCRIPTING] Tainting: {0}", it.getValue().getFileName());
+ }
+ }
+
+ public boolean isRunning() {
+ return _running;
+ }
+
+ public void setRunning(boolean running) {
+ this._running = running;
+ }
+
+ public Map<Integer, Boolean> getSystemRecompileMap() {
+ return _systemRecompileMap;
+ }
+
+ public void setSystemRecompileMap(Map<Integer, Boolean> systemRecompileMap) {
+ this._systemRecompileMap = systemRecompileMap;
+ }
+
+ public Map<String, ReloadingMetadata> getClassMap() {
+ return _classMap;
+ }
+
+ public void setClassMap(Map<String, ReloadingMetadata> classMap) {
+ this._classMap = classMap;
+ }
+
+ public ScriptingWeaver getWeavers() {
+ return _weavers;
+ }
+
+ public void setWeavers(ScriptingWeaver weavers) {
+ _weavers = weavers;
+ }
+
+ public ClassDependencies getDependencyMap() {
+ return _dependencyMap;
+ }
+}
+
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/RefreshContext.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/RefreshContext.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/RefreshContext.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/RefreshContext.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,370 @@
+/*
+ * 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.myfaces.extensions.scripting.refresh;
+
+import org.apache.myfaces.extensions.scripting.core.dependencyScan.api.DependencyRegistry;
+import org.apache.myfaces.extensions.scripting.core.dependencyScan.registry.MasterDependencyRegistry;
+import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
+
+import javax.faces.context.FacesContext;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * <p/>
+ * a context which holds information regarding the refresh cycle
+ * which can be picked up by the request filter for refreshing strategies
+ * <p/>
+ * That way we can avoid a separate session filter and a push system
+ * we use a pull system instead
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+
+public class RefreshContext {
+ /**
+ * this is a timed marker which is
+ * a point in time the last bean refresh was issued
+ * every request has to dump its personal scoped
+ * (aka session, or custom) scoped beans
+ * if the point in time is newer than the personal refresh time
+ * application scoped beans are refreshed at the first refresh cycle
+ * by the calling request issuing the compile
+ */
+ private volatile long _personalScopedBeanRefresh = -1l;
+
+ /**
+ * the bean synchronisation has to be dealt with
+ * differently, we have two volatile points in the lifecycle
+ * one being the compile the other one the bean refresh
+ * the refresh can only happen outside of a compile cycle
+ * and also a global refresh has to be atomic and no other
+ * refreshes should happen
+ */
+ public final static Boolean BEAN_SYNC_MONITOR = new Boolean(true);
+
+ /**
+ * second synchronisation monitor
+ * all other artifacts can only be refreshed outside of a
+ * compile cycle otherwise the classloader would get
+ * half finished compile states to load
+ */
+ public final static Boolean COMPILE_SYNC_MONITOR = new Boolean(true);
+
+ private volatile AtomicInteger _currentlyRunningRequests = null;
+
+ private MasterDependencyRegistry _dependencyRegistry = new MasterDependencyRegistry();
+
+ /**
+ * we keep a 10 minutes timeout period to keep the performance in place
+ */
+ private volatile long _taintLogTimeout = 10 * 60 * 1000;
+
+ /**
+ * This is a log which keeps track of the taints
+ * over time, we need that mostly for bean refreshes
+ * in multiuser surroundings, because only tainted beans need
+ * to be refreshed.
+ * Now if a user misses multiple updates he has to get a full
+ * set of changed classes to be able to drop all personal scoped beans tainted
+ * since the he refreshed last! Hence we have to move away from our
+ * two dimensional <class, taint> to a three dimensional <class, taint, time>
+ * view of things
+ */
+ private List<TaintingHistoryEntry> _taintLog = Collections.synchronizedList(new LinkedList<TaintingHistoryEntry>());
+
+ /**
+ * the daemon thread which marks the scripting classes
+ * depending on the state, changed => tainted == true, not changed
+ * tainted == false!
+ */
+ volatile FileChangedDaemon _daemon = null;
+
+ /**
+ * internal class used by our own history log
+ */
+ static class TaintingHistoryEntry {
+ long _timestamp;
+ ReloadingMetadata _data;
+
+ public TaintingHistoryEntry(ReloadingMetadata data) {
+ _data = data.getClone();
+ _timestamp = System.currentTimeMillis();
+ }
+
+ public long getTimestamp() {
+ return _timestamp;
+ }
+
+ public ReloadingMetadata getData() {
+ return _data;
+ }
+ }
+
+ /**
+ * adds a new entry into our taint log
+ * which allows us to access tainting data
+ * from a given point in time
+ *
+ * @param data the tainting data to be added
+ */
+ public void addTaintLogEntry(ReloadingMetadata data) {
+ _taintLog.add(new TaintingHistoryEntry(data));
+ }
+
+ /**
+ * garbage collects our tainting data
+ * and removes all entries which are not
+ * present anymore due to timeout
+ * this gc code is called asynchronously
+ * from our tainting thread to keep the
+ * performance intact
+ */
+ public void gcTaintLog() {
+ long timeoutTimestamp = System.currentTimeMillis() - _taintLogTimeout;
+ Iterator<TaintingHistoryEntry> it = _taintLog.iterator();
+
+ while (it.hasNext()) {
+ TaintingHistoryEntry entry = it.next();
+ if (entry.getTimestamp() < timeoutTimestamp) {
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * returns the last noOfEntries entries in the taint history
+ *
+ * @param noOfEntries the number of entries to be delivered
+ * @return a collection of the last <noOfEntries> entries
+ */
+ public Collection<ReloadingMetadata> getLastTainted(int noOfEntries) {
+ Iterator<TaintingHistoryEntry> it = _taintLog.subList(Math.max(_taintLog.size() - noOfEntries, 0), _taintLog.size()).iterator();
+ List<ReloadingMetadata> retVal = new LinkedList<ReloadingMetadata>();
+ while (it.hasNext()) {
+ TaintingHistoryEntry entry = it.next();
+ retVal.add(entry.getData());
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns a set of tainting data from a given point in time up until now
+ *
+ * @param timestamp the point in time from which the tainting data has to be derived from
+ * @return a set of entries which are a union of all points in time beginning from timestamp
+ */
+ public Collection<ReloadingMetadata> getTaintHistory(long timestamp) {
+ List<ReloadingMetadata> retVal = new LinkedList<ReloadingMetadata>();
+ Iterator<TaintingHistoryEntry> it = _taintLog.iterator();
+
+ while (it.hasNext()) {
+ TaintingHistoryEntry entry = it.next();
+ if (entry.getTimestamp() >= timestamp) {
+ retVal.add(entry.getData());
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * Returns a set of tainted classes from a given point in time up until now
+ *
+ * @param timestamp the point in time from which the tainting data has to be derived from
+ * @return a set of classnames which are a union of all points in time beginning from timestamp
+ */
+ public Set<String> getTaintHistoryClasses(long timestamp) {
+ Set<String> retVal = new HashSet<String>();
+ Iterator<TaintingHistoryEntry> it = _taintLog.iterator();
+
+ while (it.hasNext()) {
+ TaintingHistoryEntry entry = it.next();
+ if (entry.getTimestamp() >= timestamp) {
+ retVal.add(entry.getData().getAClass().getName());
+ }
+ }
+ return retVal;
+ }
+
+ /**
+ * returns the last global personal scoped bean refresh point in time
+ *
+ * @return a long value showing which personal bean refresh was the last in time
+ */
+ public long getPersonalScopedBeanRefresh() {
+ return _personalScopedBeanRefresh;
+ }
+
+ /**
+ * setter for the global personal scope bean refresh
+ *
+ * @param personalScopedBeanRefresh
+ */
+ public void setPersonalScopedBeanRefresh(long personalScopedBeanRefresh) {
+ this._personalScopedBeanRefresh = personalScopedBeanRefresh;
+ }
+
+ /**
+ * checks whether it would make sense at the current point
+ * in time to enforce a recompile or not
+ *
+ * @param scriptingEngine
+ * @return
+ */
+ public boolean isRecompileRecommended(int scriptingEngine) {
+ Boolean recommended = _daemon.getSystemRecompileMap().get(scriptingEngine);
+ return recommended == null || recommended.booleanValue();
+ }
+
+ public void setRecompileRecommended(int scriptingEngine, boolean recompileRecommended) {
+ _daemon.getSystemRecompileMap().put(scriptingEngine, recompileRecommended);
+ }
+
+ public DependencyRegistry getDependencyRegistry(int scriptingEngine) {
+ return _dependencyRegistry.getSubregistry(scriptingEngine);
+ }
+
+ public void setDependencyRegistry(int scriptingEngine, DependencyRegistry registry) {
+ _dependencyRegistry.addSubregistry(scriptingEngine, registry);
+ }
+
+ public boolean isDependencyScanned(int scriptingEngine) {
+ FacesContext ctx = FacesContext.getCurrentInstance();
+ if (ctx == null) {
+ return false;
+ }
+ Map<String, Object> requestMap = (Map<String, Object>) ctx.getExternalContext().getRequestMap();
+ Boolean retVal = (Boolean) requestMap.get("isDependencyScanned_" + scriptingEngine);
+ return (retVal == null) ? false : retVal;
+ }
+
+ public void setDependencyScanned(int scriptingEngine, Boolean val) {
+ FacesContext ctx = FacesContext.getCurrentInstance();
+ if (ctx == null) {
+ return;
+ }
+ Map<String, Object> requestMap = (Map<String, Object>) ctx.getExternalContext().getRequestMap();
+ requestMap.put("isDependencyScanned_" + scriptingEngine, val);
+ }
+
+ public FileChangedDaemon getDaemon() {
+ return _daemon;
+ }
+
+ public void setDaemon(FileChangedDaemon daemon) {
+ this._daemon = daemon;
+ }
+
+ /**
+ * @return true if a compile currently is in progress
+ */
+ public static boolean isCompileInProgress(int engineType) {
+ //TODO implement this
+ return false;
+ }
+
+ /**
+ * returns whether a recompile now at the current point
+ * in time for this engine is allowed or not
+ * This state depends on the state of the application
+ * if non locked compiles is enabled it always will return true
+ * <p/>
+ * if a synchronized locking compile is enabled
+ * it will return true if the calling request is the only
+ * one currently issued because no request is allowed to compile
+ * until others have run out
+ *
+ * @param engineType
+ * @return
+ */
+ public boolean isComileAllowed(int engineType) {
+ return getCurrentlyRunningRequests().get() == 1;
+ }
+
+ /**
+ * getter for our request counter
+ * we need this variable to keep a lock
+ * on the number of requests
+ * we only can compile if the currently
+ * running request is the only one currently
+ * active, to keep the compilation results in sync
+ *
+ * @return the request counter holder which is an atomic integer
+ * <p/>
+ * probably deprecred
+ */
+ public AtomicInteger getCurrentlyRunningRequests() {
+ return _currentlyRunningRequests;
+ }
+
+ /**
+ * setter for our currently running requests
+ *
+ * @param currentlyRunning the number of currently running requests
+ */
+ public void setCurrentlyRunningRequests(AtomicInteger currentlyRunning) {
+ _currentlyRunningRequests = currentlyRunning;
+ }
+
+ /**
+ * checks outside of the request
+ * scope for changes and taints
+ * the corresponding engine
+ */
+ public static void scanAndMarkChange() {
+ WeavingContext.getWeaver();
+ }
+
+ /**
+ * Returns our dependency registry
+ *
+ * @return the Master Dependency registry holding all subregistries
+ */
+ public MasterDependencyRegistry getDependencyRegistry() {
+ return _dependencyRegistry;
+ }
+
+ /**
+ * Sets our master dependency registry
+ *
+ * @param dependencyRegistry the master dependency registry to be set
+ */
+ public void setDependencyRegistry(MasterDependencyRegistry dependencyRegistry) {
+ _dependencyRegistry = dependencyRegistry;
+ }
+
+ /**
+ * getter for the taintlog timeout
+ *
+ * @return the taintlog timeout
+ */
+ public long getTaintLogTimeout() {
+ return _taintLogTimeout;
+ }
+
+ /**
+ * setter for the taintlog timeout
+ *
+ * @param taintLogTimeout a new timeout for the taintlog
+ */
+ public void setTaintLogTimeout(long taintLogTimeout) {
+ _taintLogTimeout = taintLogTimeout;
+ }
+}
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/ReloadingMetadata.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/ReloadingMetadata.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/ReloadingMetadata.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/refresh/ReloadingMetadata.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,122 @@
+/*
+ * 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.myfaces.extensions.scripting.refresh;
+
+import org.apache.myfaces.extensions.scripting.api.ScriptingConst;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * data structure which holds the loaded data
+ * for our taint thread
+ *
+ * @author Werner Punz
+ */
+public class ReloadingMetadata implements Cloneable {
+
+ /*
+ * volatile due to the ram concurrency behavior
+ * of the instance vars jdk 5+
+ */
+ volatile boolean _tainted = false;
+ volatile boolean _annotated = false;
+ volatile boolean _taintedOnce = false;
+ volatile String _fileName = "";
+ volatile String _sourcePath = "";
+ volatile Class _aClass = null;
+ volatile long _timestamp = 0l;
+ volatile int _scriptingEngine = ScriptingConst.ENGINE_TYPE_JSF_NO_ENGINE;
+
+ public boolean isTainted() {
+ return _tainted;
+ }
+
+ public void setTainted(boolean tainted) {
+ this._tainted = tainted;
+ }
+
+ public boolean isTaintedOnce() {
+ return _taintedOnce;
+ }
+
+ public void setTaintedOnce(boolean taintedOnce) {
+ this._taintedOnce = taintedOnce;
+ }
+
+ public String getFileName() {
+ return _fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this._fileName = fileName;
+ }
+
+ public Class getAClass() {
+ return _aClass;
+ }
+
+ public void setAClass(Class aClass) {
+ this._aClass = aClass;
+ }
+
+ public long getTimestamp() {
+ return _timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this._timestamp = timestamp;
+ }
+
+ public int getScriptingEngine() {
+ return _scriptingEngine;
+ }
+
+ public void setScriptingEngine(int scriptingEngine) {
+ this._scriptingEngine = scriptingEngine;
+ }
+
+ public String getSourcePath() {
+ return _sourcePath;
+ }
+
+ public void setSourcePath(String sourcePath) {
+
+ this._sourcePath = sourcePath;
+ }
+
+ public boolean isAnnotated() {
+ return _annotated;
+ }
+
+ public void setAnnotated(boolean annotated) {
+ this._annotated = annotated;
+ }
+
+ public ReloadingMetadata getClone() {
+ try {
+ return (ReloadingMetadata) clone();
+ } catch (CloneNotSupportedException e) {
+ Logger logger = Logger.getLogger(ReloadingMetadata.class.getName());
+ logger.log(Level.SEVERE, "", e);
+ //cannot happen
+ }
+ return null;
+ }
+}
\ No newline at end of file
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/Compiler.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/Compiler.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/Compiler.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/Compiler.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,63 @@
+/*
+ * 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.myfaces.extensions.scripting.sandbox.compiler;
+
+import org.apache.myfaces.extensions.scripting.api.CompilationException;
+import org.apache.myfaces.extensions.scripting.api.CompilationResult;
+
+import java.io.File;
+
+/**
+ * <p>An abstract compiler interface that enables you to compile one particular file at a time.</p>
+ */
+public interface Compiler {
+
+ /**
+ * <p>Compiles the given file and creates an according class file in the given target path. Note that
+ * it is possible for the given class to reference any other classes as long as the dependent classes
+ * are available on the classpath. The given class loader determines the classes that are available
+ * on the classpath.</p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @param file the file of the class you want to compile
+ * @param classLoader the class loader for dependent classes
+ * @return the compilation result, i.e. the compiler output, a list of errors and a list of warnings
+ * @throws CompilationException if a severe error occured while trying to compile a file
+ */
+ public CompilationResult compile(File sourcePath, File targetPath, File file, ClassLoader classLoader)
+ throws CompilationException;
+
+ /**
+ * <p>Compiles the given file and creates an according class file in the given target path. Note that
+ * it is possible for the given class to reference any other classes as long as the dependent classes
+ * are available on the classpath. The given class loader determines the classes that are available
+ * on the classpath.</p>
+ *
+ * @param sourcePath the path to the source directory
+ * @param targetPath the path to the target directory
+ * @param file the relative file name of the class you want to compile
+ * @param classLoader the class loader for dependent classes
+ * @return the compilation result, i.e. the compiler output, a list of errors and a list of warnings
+ * @throws CompilationException if a severe error occurred while trying to compile a file
+ */
+ public CompilationResult compile(File sourcePath, File targetPath, String file, ClassLoader classLoader)
+ throws CompilationException;
+
+}
\ No newline at end of file
Added: myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/CompilerFactory.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/CompilerFactory.java?rev=933379&view=auto
==============================================================================
--- myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/CompilerFactory.java (added)
+++ myfaces/extensions/scripting/trunk/extscript-core-root/extscript-core/src/main/java/org/apache/myfaces/extensions/scripting/sandbox/compiler/CompilerFactory.java Mon Apr 12 19:43:30 2010
@@ -0,0 +1,42 @@
+package org.apache.myfaces.extensions.scripting.sandbox.compiler;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <p>This factory chooses and creates an instance of the according compiler
+ * implementation based on the current JVM for you. If you're using a Java 6
+ * VM, it will return a compiler using the JSR-199 API, otherwise it will
+ * return a compiler that uses the JavaC tool.</p>
+ */
+public class CompilerFactory {
+
+ /**
+ * The logger instance for this class.
+ */
+ private static final Logger logger = Logger.getLogger(CompilerFactory.class.getName());
+
+ // ------------------------------------------ Public methods
+
+ /**
+ * <p>Factory method that creates a new Java compiler depending on the
+ * Java runtime that this application is running on. That means, if the
+ * Java runtime supports the JSR-199 API (i.e. it's at least a Java 6
+ * runtime) this API will be used. Otherwise a compiler will be returned
+ * that tries to use some internal JDK classes.</p>
+ *
+ * @return a new Java compiler depending on the Java runtime
+ */
+ public static Compiler createCompiler() {
+ if (logger.isLoggable(Level.WARNING) &&
+ !System.getProperty("java.vendor").contains("Sun Microsystems")) {
+ logger.warning("This application is running on a Java runtime that neither supports the JSR-199 API " +
+ "nor is it distributed by Sun Microsystems. However, the compiler implementation that will " +
+ "be used depends on internal classes in the package 'com.sun.tools.javac' so compilation " +
+ "is likely to fail! Be sure that the Java runtime that you're using provides these internal " +
+ "classes!");
+ }
+
+ return new JavacCompiler();
+ }
+}
\ No newline at end of file