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 &lt;class, taint&gt; to a three dimensional &lt;class, taint, time&gt;
+     * 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 &lt;noOfEntries&gt; 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