MSCRIPTNG-1 Allow scripting in files
diff --git a/pom.xml b/pom.xml
index ca3ad41..eb92171 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,7 +35,8 @@
 

   <name>Apache Maven Scripting Plugin</name>

   <description>

-    The Maven Scripting Plugin is a plugin that wrapped the Scripting API accoring to JSR223

+    The Maven Scripting Plugin is a plugin that wrapped the Scripting API according to JSR223.

+    Add the scripting engines as dependencies of this plugin on its use.

   </description>

   <inceptionYear>2016</inceptionYear>

 

@@ -94,13 +95,6 @@
       <scope>provided</scope>

     </dependency>

 

-    <!-- ScriptEngines -->

-    <dependency>

-      <groupId>org.codehaus.groovy</groupId>

-      <artifactId>groovy-jsr223</artifactId>

-      <version>2.4.7</version>

-    </dependency>

-

     <!-- Test -->

     <dependency>

       <groupId>junit</groupId>

diff --git a/src/it/groovy-script-file-name/pom.xml b/src/it/groovy-script-file-name/pom.xml
new file mode 100644
index 0000000..a5fdfca
--- /dev/null
+++ b/src/it/groovy-script-file-name/pom.xml
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8'?>

+

+<!--

+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.

+-->

+

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

+  <modelVersion>4.0.0</modelVersion>

+

+  <groupId>org.apache.maven.plugins.scripting.its</groupId>

+  <artifactId>groovy-script</artifactId>

+  <version>1.0.0-SNAPSHOT</version>

+  <packaging>pom</packaging>

+  

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-scripting-plugin</artifactId>

+        <version>@project.version@</version>

+        <configuration>

+          <engineName>groovy</engineName>

+          <scriptFile>test.groov</scriptFile>

+        </configuration>

+        <dependencies>

+          <!-- ScriptEngines -->

+          <dependency>

+            <groupId>org.codehaus.groovy</groupId>

+            <artifactId>groovy-jsr223</artifactId>

+            <version>2.4.7</version>

+          </dependency>

+        </dependencies>

+      </plugin>

+    </plugins>

+  </build>

+</project>

diff --git a/src/it/groovy-script-file-name/test.groov b/src/it/groovy-script-file-name/test.groov
new file mode 100644
index 0000000..94d935c
--- /dev/null
+++ b/src/it/groovy-script-file-name/test.groov
@@ -0,0 +1,21 @@
+/*

+ * 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.

+ */

+

+

+(1..10).sum() + ' ' + project.artifactId
\ No newline at end of file
diff --git a/src/it/groovy-script-file/pom.xml b/src/it/groovy-script-file/pom.xml
new file mode 100644
index 0000000..6093e33
--- /dev/null
+++ b/src/it/groovy-script-file/pom.xml
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8'?>

+

+<!--

+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.

+-->

+

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

+  <modelVersion>4.0.0</modelVersion>

+

+  <groupId>org.apache.maven.plugins.scripting.its</groupId>

+  <artifactId>groovy-script</artifactId>

+  <version>1.0.0-SNAPSHOT</version>

+  <packaging>pom</packaging>

+  

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-scripting-plugin</artifactId>

+        <version>@project.version@</version>

+        <configuration>

+          <!--engineName>groovy</engineName-->

+          <scriptFile>test.groovy</scriptFile>

+        </configuration>

+        <dependencies>

+          <!-- ScriptEngines -->

+          <dependency>

+            <groupId>org.codehaus.groovy</groupId>

+            <artifactId>groovy-jsr223</artifactId>

+            <version>2.4.7</version>

+          </dependency>

+        </dependencies>

+      </plugin>

+    </plugins>

+  </build>

+</project>

diff --git a/src/it/groovy-script-file/test.groovy b/src/it/groovy-script-file/test.groovy
new file mode 100644
index 0000000..94d935c
--- /dev/null
+++ b/src/it/groovy-script-file/test.groovy
@@ -0,0 +1,21 @@
+/*

+ * 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.

+ */

+

+

+(1..10).sum() + ' ' + project.artifactId
\ No newline at end of file
diff --git a/src/it/groovy-script/pom.xml b/src/it/groovy-script/pom.xml
index 5098a79..0c949f7 100644
--- a/src/it/groovy-script/pom.xml
+++ b/src/it/groovy-script/pom.xml
@@ -41,6 +41,14 @@
           ]]>

           </script>

         </configuration>

+        <dependencies>

+          <!-- ScriptEngines -->

+          <dependency>

+            <groupId>org.codehaus.groovy</groupId>

+            <artifactId>groovy-jsr223</artifactId>

+            <version>2.4.7</version>

+          </dependency>

+        </dependencies>

       </plugin>

     </plugins>

   </build>

diff --git a/src/main/java/org/apache/maven/plugins/scripting/EvalMojo.java b/src/main/java/org/apache/maven/plugins/scripting/EvalMojo.java
index f4c349a..6dfc038 100644
--- a/src/main/java/org/apache/maven/plugins/scripting/EvalMojo.java
+++ b/src/main/java/org/apache/maven/plugins/scripting/EvalMojo.java
@@ -19,10 +19,10 @@
  * under the License.

  */

 

-import javax.script.ScriptContext;

-import javax.script.ScriptEngine;

-import javax.script.ScriptEngineManager;

-import javax.script.ScriptException;

+import java.io.File;

+

+import javax.script.Bindings;

+import javax.script.SimpleBindings;

 

 import org.apache.maven.plugin.AbstractMojo;

 import org.apache.maven.plugin.MojoExecutionException;

@@ -33,7 +33,7 @@
 

 /**

  * Evaluate the specified script

- * 

+ *

  * @author Robert Scholte

  * @since 3.0.0

  */

@@ -41,8 +41,8 @@
 public class EvalMojo

     extends AbstractMojo

 {

-    @Parameter( required = true )

-    private String engineName; // or map extension to engineName??

+    @Parameter

+    private String engineName;

 

     /**

      * When used, also specify the engineName

@@ -50,60 +50,71 @@
     @Parameter

     private String script;

 

+    /**

+     * Provide the script as an external file as an alternative to &lt;script&gt;.

+     * When scriptFile provided the script is ignored.

+     * The file name extension identifies the script language to use, as of javax.script.ScriptEngineManager

+     * and {@linkplain "https://jcp.org/aboutJava/communityprocess/final/jsr223/index.html"}

+     */

+    @Parameter

+    private File scriptFile;

+

     // script variables

     @Parameter( defaultValue = "${project}", readonly = true )

     private MavenProject project;

-    

-    private ScriptEngineManager manager = new ScriptEngineManager();

 

     @Override

     public void execute()

         throws MojoExecutionException, MojoFailureException

     {

-        ScriptEngine engine = null;

-        

-        if ( script != null )

-        {

-            engine = getScriptEngine( engineName );

+       Execute execute;

+       Object result;

+       Bindings bindings;

 

-            if ( engine == null )

-            {

-                throw new MojoFailureException( "Missing scriptEngine" );

-            }

-        }

-        else

-        {

-            // from file

-        }

+       try

+       {

+         execute = constructExecute();

 

-        try

-        {

-            ScriptContext context = engine.getContext();

-            context.setAttribute( "project", project, ScriptContext.GLOBAL_SCOPE );

-            

-            Object result = engine.eval( script );

-            

-            getLog().info( "Result:" );

-            if ( result != null )

-            {

-                getLog().info( result.toString() );

-            }

-        }

-        catch ( ScriptException e )

-        {

-            throw new MojoExecutionException( e.getMessage(), e );

-        }

+         bindings = new SimpleBindings();

+         bindings.put( "project", project );

+         bindings.put( "log", getLog() );

+

+         result = execute.run( bindings );

+

+         getLog().info( "Result:" );

+         if ( result != null )

+         {

+           getLog().info( result.toString() );

+         }

+       }

+       catch ( IllegalArgumentException e ) // configuring the plugin failed

+       {

+         throw new MojoExecutionException( e.getMessage(), e );

+       }

+       catch ( Exception e ) // execution failure

+       {

+           throw new MojoFailureException( e.getMessage(), e );

+       }

     }

-    

-    private ScriptEngine getScriptEngine( String name )

+

+    private Execute constructExecute() throws IllegalArgumentException

     {

-        if ( name == null ) 

-        {

-            return null;

-        }

-        else

-        {

-            return manager.getEngineByName( engineName );

-        }

+      Execute execute;

+

+      if ( scriptFile != null )

+      {

+         execute = new ExecuteFile( engineName, scriptFile );

+

+      }

+      else if ( script != null )

+      {

+         execute = new ExecuteString( engineName, script );

+

+      }

+      else

+      {

+         throw new IllegalArgumentException( "Missing script or scriptFile provided" );

+      }

+      return execute;

     }

-}

+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/plugins/scripting/Execute.java b/src/main/java/org/apache/maven/plugins/scripting/Execute.java
new file mode 100644
index 0000000..5563bc5
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/scripting/Execute.java
@@ -0,0 +1,71 @@
+package org.apache.maven.plugins.scripting;

+

+/*

+ * 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.

+ */

+

+import javax.script.Bindings;

+import javax.script.ScriptContext;

+import javax.script.ScriptEngine;

+import javax.script.ScriptEngineManager;

+import javax.script.ScriptException;

+

+/**

+ * Execute a script in the appropriate context and return its possibly null result

+ * @author Rusi Popov

+ */

+abstract class Execute

+{

+

+  /**

+   * @param bindings not null bindings to provide to the script to execute

+   * @return the possibly null result the script produced

+   * @throws IllegalArgumentException when the engine is not configured correctly

+   * @throws ScriptException

+   */

+  public final Object run( Bindings bindings ) throws IllegalArgumentException, ScriptException

+  {

+    ScriptEngine engine;

+    ScriptEngineManager manager;

+    ScriptContext context;

+

+    manager = new ScriptEngineManager();

+    engine = constructEngine( manager );

+    context = engine.getContext();

+

+    context.setBindings( bindings, ScriptContext.GLOBAL_SCOPE );

+

+    return execute( engine, context );

+  }

+

+  /**

+   * Execute the script

+   * @param engine not null

+   * @param context not null, initialized

+   * @return possibly null result of the script

+   * @throws ScriptException

+   */

+  protected abstract Object execute( ScriptEngine engine, ScriptContext context ) throws ScriptException;

+

+  /**

+   * @param manager not null

+   * @return non-null engine to execute the script

+   * @throws IllegalArgumentException when no engine could be identified

+   */

+  protected abstract ScriptEngine constructEngine( ScriptEngineManager manager ) throws IllegalArgumentException;

+}

diff --git a/src/main/java/org/apache/maven/plugins/scripting/ExecuteFile.java b/src/main/java/org/apache/maven/plugins/scripting/ExecuteFile.java
new file mode 100644
index 0000000..0c9ce9c
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/scripting/ExecuteFile.java
@@ -0,0 +1,126 @@
+package org.apache.maven.plugins.scripting;

+

+/*

+ * 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.

+ */

+

+import java.io.File;

+import java.io.FileReader;

+import java.io.IOException;

+

+import javax.script.ScriptContext;

+import javax.script.ScriptEngine;

+import javax.script.ScriptEngineManager;

+import javax.script.ScriptException;

+

+/**

+ * Execute a script held in a file. Use the engine name to override the engine if the file name does not refer/decode

+ * to a valid engine name or not define any at all.

+ * @author Rusi Popov

+ */

+public class ExecuteFile extends Execute

+{

+

+  /**

+   * Not null, existing readable file with the script

+   */

+  private final File scriptFile;

+

+  /**

+   * Possibly null engine name

+   */

+  private final String engineName;

+

+  /**

+   * @param engineName optional engine name, used to override the engine selection from the file extension

+   * @param scriptFile not null

+   * @throws IllegalArgumentException when the combination of parameters is incorrect

+   */

+  public ExecuteFile( String engineName, File scriptFile ) throws IllegalArgumentException

+  {

+    if ( scriptFile == null

+         || !scriptFile.isFile()

+         || !scriptFile.exists()

+         || !scriptFile.canRead() )

+    {

+      throw new IllegalArgumentException( "Expected an existing readable file \"" + scriptFile + "\" provided" );

+    }

+    this.scriptFile = scriptFile;

+

+    this.engineName = engineName;

+  }

+

+  /**

+   * @param engine

+   * @param context

+   * @return

+   * @throws ScriptException

+   * @see org.apache.maven.plugins.scripting.Execute#execute(javax.script.ScriptEngine, javax.script.ScriptContext)

+   */

+  protected Object execute( ScriptEngine engine, ScriptContext context ) throws ScriptException

+  {

+    FileReader reader;

+

+    try

+    {

+      reader = new FileReader( scriptFile );

+    }

+    catch ( IOException ex )

+    {

+      throw new IllegalArgumentException( scriptFile + " caused:", ex );

+    }

+    return engine.eval( reader, context );

+  }

+

+  /**

+   * @see org.apache.maven.plugins.scripting.Execute#constructEngine(javax.script.ScriptEngineManager)

+   */

+  protected ScriptEngine constructEngine( ScriptEngineManager manager ) throws IllegalArgumentException

+  {

+    ScriptEngine result;

+    String extension;

+    int position;

+

+    if ( engineName != null && !engineName.trim().isEmpty() )

+    {

+      result = manager.getEngineByName( engineName );

+

+      if ( result == null )

+      {

+        throw new IllegalArgumentException( "No engine found by name \"" + engineName + "\n" );

+      }

+    }

+    else

+    {

+      extension = scriptFile.getName();

+      position = extension.indexOf( "." );

+

+      if ( position >= 0 )

+      {

+        extension = extension.substring( position + 1 );

+      }

+      result = manager.getEngineByExtension( extension );

+

+      if ( result == null )

+      {

+        throw new IllegalArgumentException( "No engine found by extension \"" + extension + "\n" );

+      }

+    }

+    return result;

+  }

+}

diff --git a/src/main/java/org/apache/maven/plugins/scripting/ExecuteString.java b/src/main/java/org/apache/maven/plugins/scripting/ExecuteString.java
new file mode 100644
index 0000000..b3171e5
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/scripting/ExecuteString.java
@@ -0,0 +1,87 @@
+package org.apache.maven.plugins.scripting;

+

+/*

+ * 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.

+ */

+

+import javax.script.ScriptContext;

+import javax.script.ScriptEngine;

+import javax.script.ScriptEngineManager;

+import javax.script.ScriptException;

+

+/**

+ * Execute a script held in a string

+ * @author Rusi Popov

+ */

+public class ExecuteString extends Execute

+{

+

+  /**

+   * Not null name of the engine to execute the script

+   */

+  private final String engineName;

+

+  /**

+   * The non-null script itself

+   */

+  private final String script;

+

+  /**

+   * @param engineName

+   * @param script

+   * @throws IllegalArgumentException

+   */

+  public ExecuteString( String engineName, String script ) throws IllegalArgumentException

+  {

+    if ( engineName == null || engineName.trim().isEmpty() )

+    {

+      throw new IllegalArgumentException( "Expected a non-empty engine name provided" );

+    }

+    this.engineName = engineName;

+

+    if ( script == null || script.trim().isEmpty() )

+    {

+      throw new IllegalArgumentException( "Expected a non-empty script provided" );

+    }

+    this.script = script;

+  }

+

+  /**

+   * @throws IllegalArgumentException

+   * @see org.apache.maven.plugins.scripting.Execute#constructEngine(javax.script.ScriptEngineManager)

+   */

+  protected ScriptEngine constructEngine( ScriptEngineManager manager ) throws IllegalArgumentException

+  {

+    ScriptEngine result;

+

+    result = manager.getEngineByName( engineName );

+    if ( result == null )

+    {

+      throw new IllegalArgumentException( "Unknown engine specified with name \"" + engineName + "\"" );

+    }

+    return result;

+  }

+

+  /**

+   * @see org.apache.maven.plugins.scripting.Execute#execute(javax.script.ScriptEngine, javax.script.ScriptContext)

+   */

+  protected Object execute( ScriptEngine engine, ScriptContext context ) throws ScriptException

+  {

+    return engine.eval( script, context );

+  }

+}
\ No newline at end of file