EXTSCRIPT-154: Code Rewrite/Refactoring,cleaning up the compiler interface ongoing works on the components
git-svn-id: https://svn.apache.org/repos/asf/myfaces/extensions/scripting/trunk@1300132 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/api/WeavingContext.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/api/WeavingContext.java
index 2c361c3..c0572d7 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/api/WeavingContext.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/api/WeavingContext.java
@@ -23,6 +23,7 @@
import rewrite.org.apache.myfaces.extensions.scripting.core.common.util.ReflectUtil;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.FactoryEngines;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.ClassScanner;
+import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.CompilationResult;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.ScriptingEngine;
import rewrite.org.apache.myfaces.extensions.scripting.core.loader.ThrowAwayClassloader;
import rewrite.org.apache.myfaces.extensions.scripting.core.monitor.ClassResource;
@@ -34,10 +35,7 @@
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
@@ -51,23 +49,90 @@
public class WeavingContext
{
+ static final Logger log = Logger.getLogger(WeavingContext.class.getName());
+
/**
* lock var which can be used for recompilation
*/
public AtomicBoolean recompileLock = new AtomicBoolean(false);
+ /**
+ * configuration which stores all external configuration entries
+ */
protected Configuration configuration = new Configuration();
//ClassDependencies _dependencyMap = new ClassDependencies();
-
+ /**
+ * Service provider for the implementation under which this extension
+ * runs
+ */
ImplementationSPI _implementation = null;
+ /**
+ * the collection of reloading strategies depending on their artifact type
+ */
GlobalReloadingStrategy _reloadingStrategy = new GlobalReloadingStrategy();
+ /**
+ * the annotation scanning reference
+ */
ClassScanner _annotationScanner = null;
- Logger log = Logger.getLogger(this.getClass().getName());
+
+ /**
+ * true only if the startup has performed without errors
+ */
boolean _scriptingEnabled = true;
- /*holder for various operations within our lifecycle*/
+ /**
+ * holder for various operations within our lifecycle
+ */
ConcurrentHashMap<String, Long> lifecycleRegistry = new ConcurrentHashMap<String, Long>();
+ /**
+ * 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>());
+
+ /**
+ * compilation results holder for the compiler listeners (components etc...)
+ */
+ private static final Map<Integer, CompilationResult> _compilationResults = new ConcurrentHashMap<Integer, CompilationResult>();
+
+ /**
+ * we keep a 10 minutes timeout period to keep the performance in place
+ */
+ private final long TAINT_HISTORY_TIMEOUT = 10 * 60 * 1000;
+
+ /**
+ * internal class used by our own history log
+ */
+ static class TaintingHistoryEntry
+ {
+ long _timestamp;
+ ClassResource _data;
+
+ public TaintingHistoryEntry(ClassResource data)
+ {
+ _data = data;
+ _timestamp = System.currentTimeMillis();
+ }
+
+ public long getTimestamp()
+ {
+ return _timestamp;
+ }
+
+ public ClassResource getData()
+ {
+ return _data;
+ }
+ }
+
public void initEngines() throws IOException
{
FactoryEngines.getInstance().init();
@@ -115,6 +180,9 @@
return ret;
}
+ /**
+ * @return a map of all watched resources over all engines
+ */
public Map<String, ClassResource> getAllWatchedResources()
{
Map<String, ClassResource> ret = new HashMap<String, ClassResource>();
@@ -129,6 +197,10 @@
return ret;
}
+ /**
+ * @param key the watched resource classname
+ * @return the watched resource from the given key or null
+ */
public ClassResource getWatchedResource(String key)
{
for (ScriptingEngine engine : getEngines())
@@ -139,6 +211,12 @@
return null;
}
+ /**
+ * checks if a resource idenified by key is tainted
+ *
+ * @param key the identifier for the resource
+ * @return true in case of being tainted
+ */
public boolean isTainted(String key)
{
ClassResource res = getWatchedResource(key);
@@ -353,6 +431,9 @@
lifecycleRegistry.put("LIFECYCLE_LAST_TAINTED", System.currentTimeMillis());
}
+ /**
+ * @return the time value of the last taint happening
+ */
public long getLastTaint()
{
Long lastTainted = lifecycleRegistry.get("LIFECYCLE_LAST_TAINTED");
@@ -360,11 +441,17 @@
return lastTainted;
}
+ /**
+ * marks the last annotation scan
+ */
public void markLastAnnotationScan()
{
lifecycleRegistry.put("LIFECYCLE_LAST_ANN_SCAN", System.currentTimeMillis());
}
+ /**
+ * @return a the time value of the last annotation scan
+ */
public long getLastAnnotationScan()
{
Long lastTainted = lifecycleRegistry.get("LIFECYCLE_LAST_ANN_SCAN");
@@ -372,6 +459,111 @@
return lastTainted;
}
+ //------------------------------ tainting history entries -----------------------
+
+ /**
+ * 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(ClassResource 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() - TAINT_HISTORY_TIMEOUT;
+ 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<ClassResource> getLastTainted(int noOfEntries)
+ {
+ Iterator<TaintingHistoryEntry> it = _taintLog.subList(Math.max(_taintLog.size() - noOfEntries, 0), _taintLog.size()).iterator();
+ List<ClassResource> retVal = new LinkedList<ClassResource>();
+ 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<ClassResource> getTaintHistory(long timestamp)
+ {
+ List<ClassResource> retVal = new LinkedList<ClassResource>();
+ 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)
+ {
+ if (entry.getData() instanceof ClassResource)
+ {
+ retVal.add(((ClassResource) entry.getData()).getAClass().getName());
+ } else
+ {
+ retVal.add(entry.getData().getFile().getAbsolutePath());
+ }
+ }
+ }
+ return retVal;
+ }
+
//----------------------------------------------------------------------
/*public ClassDependencies getDependencyMap()
{
@@ -410,4 +602,14 @@
_scriptingEnabled = scriptingEnabled;
}
+ public CompilationResult getCompilationResult(Integer scriptingEngine)
+ {
+ return _compilationResults.get(scriptingEngine);
+ }
+
+ public void setCompilationResult(Integer scriptingEngine, CompilationResult result)
+ {
+ _compilationResults.put(scriptingEngine, result);
+ }
+
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/common/util/FileUtils.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/common/util/FileUtils.java
index 5894256..472acd9 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/common/util/FileUtils.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/common/util/FileUtils.java
@@ -76,7 +76,7 @@
File tempDir;
String baseTempPath = System.getProperty("java.io.tmpdir");
- String tempDirName = "myfaces_compilation_"; //+ _tempMarker;
+ String tempDirName = "myfaces_compilation_" + _tempMarker;
tempDir = new File(baseTempPath + File.separator + tempDirName);
/*while (tempDir.exists()) {
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/EngineJava.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/EngineJava.java
index 36b6764..e329ff7 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/EngineJava.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/EngineJava.java
@@ -23,6 +23,7 @@
import rewrite.org.apache.myfaces.extensions.scripting.core.api.WeavingContext;
import rewrite.org.apache.myfaces.extensions.scripting.core.common.util.ClassUtils;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.CompilationException;
+import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.CompilationResult;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.ScriptingEngine;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.compiler.JSR199Compiler;
@@ -62,15 +63,12 @@
Collection<String> sourceDirs = configuration.getSourceDirs(getEngineType());
for (String sourceRoot : sourceDirs)
{
- try
- {
- compiler.compile(new File(sourceRoot), targetDir, ClassUtils.getContextClassLoader());
+ CompilationResult res = compiler.compile(new File(sourceRoot), targetDir,
+ ClassUtils.getContextClassLoader());
+ if(res.hasErrors()) {
+ log.severe(res.getCompilerOutput());
}
- catch (CompilationException e)
- {
- log.severe(e.getMessage());
- e.printStackTrace();
- }
+
}
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/api/Compiler.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/api/Compiler.java
index 34f8fcd..038f801 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/api/Compiler.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/api/Compiler.java
@@ -40,7 +40,6 @@
* @throws CompilationException
* if a severe error occurred while trying to compile a file
*/
- public CompilationResult compile(File sourcePath, File targetPath, ClassLoader classLoader)
- throws CompilationException;
+ public CompilationResult compile(File sourcePath, File targetPath, ClassLoader classLoader);
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/GroovyCompiler.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/GroovyCompiler.java
index b522c27..0ce2f82 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/GroovyCompiler.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/GroovyCompiler.java
@@ -96,6 +96,10 @@
result.registerWarning(convertMessage(collector.getWarning(i)));
}
+ if(result != null) {
+ WeavingContext.getInstance().setCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_GROOVY, result);
+ }
+
return result;
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/JSR199Compiler.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/JSR199Compiler.java
index e69fba7..68a0e56 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/JSR199Compiler.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/engine/compiler/JSR199Compiler.java
@@ -20,6 +20,7 @@
package rewrite.org.apache.myfaces.extensions.scripting.core.engine.compiler;
import rewrite.org.apache.myfaces.extensions.scripting.core.api.Configuration;
+import rewrite.org.apache.myfaces.extensions.scripting.core.api.ScriptingConst;
import rewrite.org.apache.myfaces.extensions.scripting.core.api.WeavingContext;
import rewrite.org.apache.myfaces.extensions.scripting.core.common.util.FileUtils;
import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.CompilationException;
@@ -51,7 +52,7 @@
javax.tools.JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
ContainerFileManager fileManager = null;
- CompilationResult result = null;
+
public JSR199Compiler()
{
@@ -59,56 +60,6 @@
}
/**
- * Compile a single file
- *
- * @param sourceRoot the source search path (root of our source)
- * @return the compilation result of the compilation
- * @throws org.apache.myfaces.extensions.scripting.api.CompilationException
- * in case of a compilation error
- * @deprecated note we will move over to a single
- * compile step in the beginning in the long run
- * we will deprecate it as soon as the full
- * compile at the beginning of the request
- * is implemented
- * <p/>
- * TODO move this code over to the weaver instead of the compiler
- * we do not do a single compile step anymore
- */
- public CompilationResult compile(File sourceRoot, File targetPath, File toCompile, ClassLoader classPathHolder) throws CompilationException
- {
- try
- {
- fileManager = new ContainerFileManager(javaCompiler.getStandardFileManager(new DiagnosticCollector<JavaFileObject>(), null, null));
-
- DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
-
- //TODO add whitelist check here
-
- getLog().info("[EXT-SCRIPTING] Doing a full recompile");
-
- Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(toCompile);
- String[] options = new String[]{JC_CLASSPATH, fileManager.getClassPath(), JC_TARGET_PATH,
- targetPath.getAbsolutePath(),
- JC_SOURCEPATH,
- sourceRoot.getAbsolutePath(), JC_DEBUG};
- javaCompiler.getTask(null, fileManager, diagnosticCollector, Arrays.asList(options), null, fileObjects).call();
- try
- {
- handleDiagnostics(diagnosticCollector);
- }
- catch (ClassNotFoundException e)
- {
- throw new CompilationException(e);
- }
- return this.result;
- }
- finally
- {
- this.result = null;
- }
- }
-
- /**
* compile all files starting from a given root
* <p/>
* note, the java compiler interface does not allow per se
@@ -122,10 +73,7 @@
* @throws org.apache.myfaces.extensions.scripting.api.CompilationException
* in case of a compilation error
*/
- public CompilationResult compile(File sourceRoot, File destination, ClassLoader loader) throws CompilationException
- {
- try
- {
+ public CompilationResult compile(File sourceRoot, File destination, ClassLoader loader) {
WeavingContext context = WeavingContext.getInstance();
Configuration configuration = context.getConfiguration();
@@ -135,8 +83,6 @@
getLog().info("[EXT-SCRIPTING] Doing a full recompile");
- //List<File> sourceFiles = FileUtils.fetchSourceFiles(WeavingContext.getConfiguration()
- // .getWhitelistedSourceDirs(ENGINE_TYPE_JSF_JAVA), JAVA_WILDCARD);
List<File> sourceFiles = FileUtils.fetchSourceFiles(configuration.getWhitelistedSourceDirs
(ENGINE_TYPE_JSF_JAVA), JAVA_WILDCARD);
@@ -152,20 +98,13 @@
destination.getAbsolutePath(), JC_SOURCEPATH,
sourceRoot.getAbsolutePath(), JC_DEBUG};
javaCompiler.getTask(null, fileManager, diagnosticCollector, Arrays.asList(options), null, fileObjects).call();
- try
- {
- handleDiagnostics(diagnosticCollector);
- }
- catch (ClassNotFoundException e)
- {
- throw new CompilationException(e);
- }
- return this.result;
- }
- finally
- {
- this.result = null;
- }
+
+
+ CompilationResult result = handleDiagnostics(diagnosticCollector);
+
+ WeavingContext.getInstance().setCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_JAVA, result);
+ return result;
+
}
/**
@@ -177,8 +116,7 @@
* @throws ClassNotFoundException in case of an error (this is enforced by the compiler interface
* and probably will be overhauled in the long run)
*/
- private void handleDiagnostics(DiagnosticCollector<JavaFileObject> diagnosticCollector) throws
- ClassNotFoundException
+ private CompilationResult handleDiagnostics(DiagnosticCollector<JavaFileObject> diagnosticCollector)
{
if (diagnosticCollector.getDiagnostics().size() > 0)
{
@@ -200,15 +138,13 @@
result.getWarnings().add(new CompilationResult.CompilationMessage(diagnostic.getLineNumber(), diagnostic.getMessage(Locale.getDefault())));
}
errors.append(error);
+
}
- this.result = result;
- //WeavingContext.setCompilationResult(ENGINE_TYPE_JSF_JAVA, result);
- assertErrorFound(errors, hasError);
- //return result;
+ return result;
} else
{
//WeavingContext.setCompilationResult(ENGINE_TYPE_JSF_JAVA, new CompilationResult(""));
- this.result = new CompilationResult("");
+ return new CompilationResult("");
}
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/monitor/ClassResource.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/monitor/ClassResource.java
index 367fb16..a7a3297 100644
--- a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/monitor/ClassResource.java
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/core/monitor/ClassResource.java
@@ -152,6 +152,8 @@
WeavingContext.getInstance().markLastTaint();
//TODO add logging event here
logger.info("[EXT-SCRIPTING] tainting " + getSourceFile());
+ WeavingContext.getInstance().addTaintLogEntry(this);
+ WeavingContext.getInstance().gcTaintLog();
}
tainted = value;
}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponent.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponent.java
new file mode 100644
index 0000000..58cbd9b
--- /dev/null
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponent.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package rewrite.org.apache.myfaces.extensions.scripting.jsf.components;
+
+
+import rewrite.org.apache.myfaces.extensions.scripting.core.api.ScriptingConst;
+import rewrite.org.apache.myfaces.extensions.scripting.core.common.util.StringUtils;
+
+import javax.el.ValueExpression;
+import javax.faces.component.UIOutput;
+import javax.faces.context.FacesContext;
+import java.util.Locale;
+
+/**
+ * Compiler component which currently
+ * just shows the last compile output in the system
+ * <p/>
+ * Not to keep backwards compatibility to JSF 1.2
+ * we do not use the StateHelper but go the old route
+ * instead
+ */
+@SuppressWarnings("unused")
+public class CompilerComponent extends UIOutput {
+
+ String _scriptingLanguage = null;
+ String _errorsLabel = null;
+ String _warningsLabel = null;
+ private static final String RENDERER_TYPE = "org.apache.myfaces.extensions.scripting.components.CompilerComponentRenderer";
+ private static final String ERRORS_LABEL = "errorsLabel";
+ private static final String WARNINGS_LABEL = "warningsLabel";
+ private static final String SCRIPTING_LANGUAGE = "scriptingLanguage";
+
+ public CompilerComponent() {
+ super();
+ setRendererType(RENDERER_TYPE);
+ }
+
+ @Override
+ public boolean isTransient() {
+ return true;
+ }
+
+ @Override
+ public Object saveState(FacesContext facesContext) {
+ Object values[] = new Object[4];
+ values[0] = super.saveState(facesContext); //To change body of overridden methods use File | Settings | File Templates.
+ values[1] = _scriptingLanguage;
+ values[2] = _errorsLabel;
+ values[3] = _warningsLabel;
+ return values;
+ }
+
+ @Override
+ public void restoreState(FacesContext facesContext, Object state) {
+ Object[] values = (Object[]) state;
+ super.restoreState(facesContext, values[0]);
+
+ _scriptingLanguage = (String) values[1];
+ _errorsLabel = (String) values[2];
+ _warningsLabel = (String) values[3];
+ }
+
+
+ public String getScriptingLanguage() {
+ if (_scriptingLanguage != null) {
+ return _scriptingLanguage;
+ }
+ ValueExpression vb = getValueExpression(SCRIPTING_LANGUAGE);
+ return vb != null ? ((String) vb.getValue(getFacesContext().getELContext())) : null;
+ }
+
+ public Integer getScriptingLanguageAsInt() {
+ if (StringUtils.isBlank(_scriptingLanguage)) {
+ return ScriptingConst.ENGINE_TYPE_JSF_ALL;
+ } else {
+ String scriptingLanguage = _scriptingLanguage.toLowerCase(Locale.getDefault()).trim();
+ if (scriptingLanguage.equals("java")) {
+ return ScriptingConst.ENGINE_TYPE_JSF_JAVA;
+ } else if (_scriptingLanguage.toLowerCase(Locale.getDefault()).trim().equals("groovy")) {
+ return ScriptingConst.ENGINE_TYPE_JSF_GROOVY;
+ }
+ }
+ return ScriptingConst.ENGINE_TYPE_JSF_NO_ENGINE;
+ }
+
+ public void setScriptingLanguage(String scriptingLanguage) {
+ _scriptingLanguage = scriptingLanguage;
+ }
+
+ public String getErrorsLabel() {
+ if (_errorsLabel != null) {
+ return _errorsLabel;
+ }
+ ValueExpression vb = getValueExpression(ERRORS_LABEL);
+ return vb != null ? ((String) vb.getValue(getFacesContext().getELContext())) : null;
+ }
+
+ public void setErrorsLabel(String _errorsLabel) {
+ this._errorsLabel = _errorsLabel;
+ }
+
+ public String getWarningsLabel() {
+ if (_warningsLabel != null) {
+ return _warningsLabel;
+ }
+ ValueExpression vb = getValueExpression(WARNINGS_LABEL);
+ return vb != null ? ((String) vb.getValue(getFacesContext().getELContext())) : null;
+ }
+
+ public void setWarningsLabel(String _warningsLabel) {
+ this._warningsLabel = _warningsLabel;
+ }
+}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponentRenderer.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponentRenderer.java
new file mode 100644
index 0000000..196777e
--- /dev/null
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/CompilerComponentRenderer.java
@@ -0,0 +1,150 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.components;
+
+import rewrite.org.apache.myfaces.extensions.scripting.core.api.ScriptingConst;
+import rewrite.org.apache.myfaces.extensions.scripting.core.api.WeavingContext;
+import rewrite.org.apache.myfaces.extensions.scripting.core.common.util.StringUtils;
+import rewrite.org.apache.myfaces.extensions.scripting.core.engine.api.CompilationResult;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.Renderer;
+import java.io.IOException;
+import java.util.logging.Logger;
+
+/**
+ * Renderer for the compiler component
+ * <p/>
+ * This renderer is responsible for rendering the last compiler output
+ * hosted in our weavingContext
+ */
+@SuppressWarnings("unchecked")
+public class CompilerComponentRenderer extends Renderer {
+
+ @Override
+ public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
+ super.encodeBegin(context, component);
+
+ ResponseWriter responseWriter = FacesContext.getCurrentInstance().getResponseWriter();
+ CompilerComponent compilerComp = (CompilerComponent) component;
+
+ Integer scriptingLanguage = compilerComp.getScriptingLanguageAsInt();
+ CompilationResult result = null;
+ switch (scriptingLanguage) {
+ case ScriptingConst.ENGINE_TYPE_JSF_JAVA:
+ result = WeavingContext.getInstance().getCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_JAVA);
+ break;
+ case ScriptingConst.ENGINE_TYPE_JSF_GROOVY:
+ result = WeavingContext.getInstance().getCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_GROOVY);
+ break;
+ case ScriptingConst.ENGINE_TYPE_JSF_ALL:
+ result = new CompilationResult("");
+ CompilationResult tempResult = WeavingContext.getInstance().getCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_JAVA);
+ if (tempResult != null) {
+ copyCompilationResult(result, tempResult);
+ }
+
+ tempResult = WeavingContext.getInstance().getCompilationResult(ScriptingConst.ENGINE_TYPE_JSF_GROOVY);
+ if (tempResult != null) {
+ copyCompilationResult(result, tempResult);
+ }
+
+ break;
+ case ScriptingConst.ENGINE_TYPE_JSF_NO_ENGINE:
+ Logger log = Logger.getLogger(this.getClass().getName());
+ log.warning(RendererConst.WARNING_ENGINE_NOT_FOUND);
+ break;
+ }
+
+ startDiv(component, responseWriter, RendererConst.ERROR_BOX);
+ if (result == null || (!result.hasErrors() && result.getWarnings().isEmpty())) {
+ responseWriter.write(RendererConst.NO_COMPILE_ERRORS);
+ } else {
+ writeErrorsLabel(component, responseWriter, compilerComp);
+ writeErrors(component, responseWriter, result);
+ writeWarningsLabel(component, responseWriter, compilerComp);
+ writeWarnings(component, responseWriter, result);
+ }
+ endDiv(responseWriter);
+
+ responseWriter.flush();
+
+ }
+
+ private void writeWarnings(UIComponent component, ResponseWriter responseWriter, CompilationResult result) throws IOException {
+ startDiv(component, responseWriter, RendererConst.WARNINGS);
+ for (CompilationResult.CompilationMessage msg : result.getWarnings()) {
+ startDiv(component, responseWriter, RendererConst.LINE);
+ writeDiv(component, responseWriter, RendererConst.LINE_NO, String.valueOf(msg.getLineNumber()));
+ writeDiv(component, responseWriter, RendererConst.MESSAGE, msg.getMessage());
+ endDiv(responseWriter);
+ }
+ endDiv(responseWriter);
+ }
+
+ private void writeWarningsLabel(UIComponent component, ResponseWriter responseWriter, CompilerComponent compilerComp) throws IOException {
+ if (!StringUtils.isBlank(compilerComp.getWarningsLabel())) {
+ startDiv(component, responseWriter, RendererConst.WARNINGS_LABEL);
+ responseWriter.write(compilerComp.getWarningsLabel());
+ endDiv(responseWriter);
+ }
+ }
+
+ private void writeErrors(UIComponent component, ResponseWriter responseWriter, CompilationResult result) throws IOException {
+ startDiv(component, responseWriter, RendererConst.ERRORS);
+ for (CompilationResult.CompilationMessage msg : result.getErrors()) {
+ startDiv(component, responseWriter, RendererConst.LINE);
+ writeDiv(component, responseWriter, RendererConst.LINE_NO, String.valueOf(msg.getLineNumber()));
+ writeDiv(component, responseWriter, RendererConst.MESSAGE, msg.getMessage());
+ endDiv(responseWriter);
+ }
+ endDiv(responseWriter);
+ }
+
+ private String writeDiv(UIComponent component, ResponseWriter responseWriter, String styleClass, String value) throws IOException {
+ startDiv(component, responseWriter, styleClass);
+ responseWriter.write(value);
+ endDiv(responseWriter);
+ return "";
+ }
+
+ private void endDiv(ResponseWriter responseWriter) throws IOException {
+ responseWriter.endElement(RendererConst.HTML_DIV);
+ }
+
+ private void startDiv(UIComponent component, ResponseWriter responseWriter, String styleClass) throws IOException {
+ responseWriter.startElement(RendererConst.HTML_DIV, component);
+ responseWriter.writeAttribute(RendererConst.HTML_CLASS, styleClass, null);
+ }
+
+ private void writeErrorsLabel(UIComponent component, ResponseWriter responseWriter, CompilerComponent compilerComp) throws IOException {
+ if (!StringUtils.isBlank(compilerComp.getErrorsLabel())) {
+ startDiv(component, responseWriter, RendererConst.ERRORS_LABEL);
+ responseWriter.write(compilerComp.getErrorsLabel());
+ endDiv(responseWriter);
+ }
+ }
+
+ private void copyCompilationResult(CompilationResult result, CompilationResult tempResult) {
+ result.getErrors().addAll(tempResult.getErrors());
+ result.getWarnings().addAll(tempResult.getWarnings());
+ }
+}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/RendererConst.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/RendererConst.java
new file mode 100644
index 0000000..5e31042
--- /dev/null
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/RendererConst.java
@@ -0,0 +1,45 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.components;
+
+/**
+ * Renderer Constant shared by both renderers
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+
+public class RendererConst {
+ static final String ERROR_BOX = "errorBox";
+ static final String WARNING_ENGINE_NOT_FOUND = "Warning engine not found";
+ static final String LINE_NO = "lineNo";
+ static final String MESSAGE = "message";
+ static final String NO_COMPILE_ERRORS = "No compile errors";
+ static final String HTML_DIV = "div";
+ static final String HTML_CLASS = "class";
+ static final String NO_TAINT_HISTORY_FOUND = "No taint history found";
+ static final String LINE = "line";
+ static final String TIMESTAMP = "timestamp";
+ static final String CHANGED_FILE = "changedFile";
+ static final String ERRORS_LABEL = "errorsLabel";
+ static final String WARNINGS_LABEL = "warningsLabel";
+ static final String ERRORS = "errors";
+ static final String WARNINGS = "warnings";
+}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistory.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistory.java
new file mode 100644
index 0000000..ea4af67
--- /dev/null
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistory.java
@@ -0,0 +1,90 @@
+/*
+ * 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 rewrite.org.apache.myfaces.extensions.scripting.jsf.components;
+
+import javax.el.ValueExpression;
+import javax.faces.component.UIOutput;
+import javax.faces.context.FacesContext;
+
+/**
+ * Component which allows to check which files
+ * have been marked as possibly modified in the recent history
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+
+public class TaintHistory extends UIOutput {
+
+ public static final int DEFAULT_NO_ENTRIES = 10;
+
+ Integer _noEntries;
+ String _filter;
+ private static final String RENDERER_TYPE = "org.apache.myfaces.extensions.scripting.components.TaintHistoryRenderer";
+ private static final String NO_ENTRIES = "noEntries";
+
+ public TaintHistory() {
+ setRendererType(RENDERER_TYPE);
+ }
+
+ @SuppressWarnings("unused")
+ public void setNoEntries(Integer entries) {
+ _noEntries = entries;
+ }
+
+ @Override
+ public Object saveState(FacesContext facesContext) {
+ Object values[] = new Object[3];
+ values[0] = super.saveState(facesContext); //To change body of overridden methods use File | Settings | File Templates.
+ values[1] = _noEntries;
+ values[2] = _filter;
+ return values;
+ }
+
+ @Override
+ public void restoreState(FacesContext facesContext, Object state) {
+ Object[] values = (Object[]) state;
+ super.restoreState(facesContext, values[0]);
+ _noEntries = (Integer) values[1];
+ _filter = (String) values[2];
+ }
+
+ public Integer getNoEntries() {
+ if (_noEntries != null) {
+ return _noEntries;
+ }
+ ValueExpression vb = getValueExpression(NO_ENTRIES);
+ return vb != null ? ((Integer) vb.getValue(getFacesContext().getELContext())) : DEFAULT_NO_ENTRIES;
+ }
+
+ @SuppressWarnings("unused")
+ public void setFilter(String filter) {
+ _filter = filter;
+ }
+
+ @SuppressWarnings("unused")
+ public String getFilter() {
+ if (_filter != null) {
+ return _filter;
+ }
+ ValueExpression vb = getValueExpression(NO_ENTRIES);
+ return vb != null ? ((String) vb.getValue(getFacesContext().getELContext())) : null;
+ }
+}
diff --git a/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistoryRenderer.java b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistoryRenderer.java
new file mode 100644
index 0000000..c89550c
--- /dev/null
+++ b/extscript-core-root/extscript-core/src/main/java/rewrite/org/apache/myfaces/extensions/scripting/jsf/components/TaintHistoryRenderer.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package rewrite.org.apache.myfaces.extensions.scripting.jsf.components;
+
+
+import rewrite.org.apache.myfaces.extensions.scripting.core.api.WeavingContext;
+import rewrite.org.apache.myfaces.extensions.scripting.core.monitor.ClassResource;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.Renderer;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.util.Collection;
+
+/**
+ * A renderer which displays our taint history
+ *
+ * @author Werner Punz (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("unchecked")
+//we have to suppress here because of the component cast
+public class TaintHistoryRenderer extends Renderer {
+
+ @Override
+ public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
+ super.encodeBegin(context, component);
+
+ ResponseWriter responseWriter = FacesContext.getCurrentInstance().getResponseWriter();
+
+ startDiv(component, responseWriter, "historyBox");
+ int lastTainted = ((TaintHistory) component).getNoEntries();
+
+ Collection<ClassResource> result = WeavingContext.getInstance().getLastTainted(lastTainted);
+ if (result == null || result.isEmpty()) {
+ responseWriter.write(RendererConst.NO_TAINT_HISTORY_FOUND);
+ } else {
+ writeHistory(component, responseWriter, result);
+ }
+ endDiv(responseWriter);
+
+ responseWriter.flush();
+
+ }
+
+ private void writeHistory(UIComponent component, ResponseWriter responseWriter,
+ Collection<ClassResource> result) throws IOException {
+ startDiv(component, responseWriter, "history");
+ for (ClassResource entry : result) {
+ startDiv(component, responseWriter, RendererConst.LINE);
+ writeDiv(component, responseWriter, RendererConst.TIMESTAMP, DateFormat.getInstance().format(entry.getFile().lastModified()));
+ writeDiv(component, responseWriter, RendererConst.CHANGED_FILE, entry.getFile().getAbsolutePath());
+ endDiv(responseWriter);
+ }
+
+ endDiv(responseWriter);
+ }
+
+ private String writeDiv(UIComponent component, ResponseWriter responseWriter, String styleClass, String value) throws IOException {
+ startDiv(component, responseWriter, styleClass);
+ responseWriter.write(value);
+ endDiv(responseWriter);
+ return "";
+ }
+
+ private void endDiv(ResponseWriter responseWriter) throws IOException {
+ responseWriter.endElement(RendererConst.HTML_DIV);
+ }
+
+ private void startDiv(UIComponent component, ResponseWriter responseWriter, String styleClass) throws IOException {
+ responseWriter.startElement(RendererConst.HTML_DIV, component);
+ responseWriter.writeAttribute(RendererConst.HTML_CLASS, styleClass, null);
+ }
+
+}
diff --git a/extscript-core-root/extscript-core/src/test/java/rewrite/org/apache/myfaces/extensions/scripting/scanningcore/engine/compiler/JavaCompilerTest.java b/extscript-core-root/extscript-core/src/test/java/rewrite/org/apache/myfaces/extensions/scripting/scanningcore/engine/compiler/JavaCompilerTest.java
index 404d408..8c93322 100644
--- a/extscript-core-root/extscript-core/src/test/java/rewrite/org/apache/myfaces/extensions/scripting/scanningcore/engine/compiler/JavaCompilerTest.java
+++ b/extscript-core-root/extscript-core/src/test/java/rewrite/org/apache/myfaces/extensions/scripting/scanningcore/engine/compiler/JavaCompilerTest.java
@@ -105,14 +105,8 @@
WeavingContext.getInstance().getConfiguration().addWhitelistPackage("compiler.myPackage");
CompilationResult result = null;
- try
- {
- result = compiler.compile(root, target, loader);
- }
- catch (CompilationException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
+
+ result = compiler.compile(root, target, loader);
assertTrue(RESULT_HAS_NO_ERRORS, !result.hasErrors());
@@ -141,14 +135,7 @@
target.deleteOnExit();
CompilationResult result = null;
- try
- {
- result = compiler.compile(root, target, loader);
- }
- catch (CompilationException e)
- {
- e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
- }
+ result = compiler.compile(root, target, loader);
assertTrue(RESULT_HAS_NO_ERRORS, !result.hasErrors());