You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by km...@apache.org on 2013/03/19 02:55:06 UTC

git commit: Cleanup future handling in client. Add sample scripts.

Updated Branches:
  refs/heads/master ee4df3759 -> d084401b8


Cleanup future handling in client.
Add sample scripts.


Project: http://git-wip-us.apache.org/repos/asf/incubator-knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-knox/commit/d084401b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-knox/tree/d084401b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-knox/diff/d084401b

Branch: refs/heads/master
Commit: d084401b839bab0ef59d0a33673c902382e5d761
Parents: ee4df37
Author: Kevin Minder <ke...@hortonworks.com>
Authored: Mon Mar 18 21:54:59 2013 -0400
Committer: Kevin Minder <ke...@hortonworks.com>
Committed: Mon Mar 18 21:54:59 2013 -0400

----------------------------------------------------------------------
 gateway-provider-security-jwt/pom.xml              |   16 +-
 gateway-release/pom.xml                            |    6 +
 gateway-release/samples/ComplexCommand.groovy      |   70 ++++++
 gateway-release/samples/SampleScript.groovy        |   29 +++
 gateway-release/samples/SampleService.groovy       |   32 +++
 gateway-release/samples/SimpleCommand.groovy       |   52 +++++
 gateway-release/samples/SmokeTestJob.groovy        |   61 +++++
 gateway-release/samples/SmokeTestWorkflow.groovy   |   92 ++++++++
 gateway-release/samples/hadoop-examples.jar        |  Bin 0 -> 142457 bytes
 gateway-release/templates/topology.xml             |    4 +-
 gateway-shell/pom.xml                              |    7 +-
 .../hadoop/gateway/shell/AbstractRequest.java      |   19 +-
 .../hadoop/gateway/shell/AbstractResponse.java     |   98 --------
 .../apache/hadoop/gateway/shell/BasicResponse.java |   98 ++++++++
 .../apache/hadoop/gateway/shell/ErrorResponse.java |   35 +++
 .../org/apache/hadoop/gateway/shell/Example.groovy |   40 ----
 .../org/apache/hadoop/gateway/shell/Hadoop.java    |   35 +++-
 .../hadoop/gateway/shell/HadoopException.java      |    4 +
 .../org/apache/hadoop/gateway/shell/Shell.java     |   29 ++-
 .../hadoop/gateway/shell/hdfs/Example.groovy       |   29 ++-
 .../org/apache/hadoop/gateway/shell/hdfs/Get.java  |    4 +-
 .../org/apache/hadoop/gateway/shell/hdfs/Ls.java   |    4 +-
 .../apache/hadoop/gateway/shell/hdfs/Mkdir.java    |    6 +-
 .../org/apache/hadoop/gateway/shell/hdfs/Put.java  |    7 +-
 .../org/apache/hadoop/gateway/shell/hdfs/Rm.java   |    4 +-
 .../org/apache/hadoop/gateway/shell/job/Hive.java  |    4 +-
 .../org/apache/hadoop/gateway/shell/job/Java.java  |    5 +-
 .../org/apache/hadoop/gateway/shell/job/Pig.java   |    7 +-
 .../org/apache/hadoop/gateway/shell/job/Queue.java |    8 +-
 .../apache/hadoop/gateway/shell/job/Status.java    |    8 +-
 .../hadoop/gateway/shell/workflow/Status.java      |    6 +-
 .../hadoop/gateway/shell/workflow/Submit.java      |    7 +-
 .../src/main/resources/META-INF/launcher.cfg       |   16 ++
 gateway-util-launcher/pom.xml                      |   39 ++++
 .../apache/hadoop/gateway/launcher/Command.java    |  154 +++++++++++++
 .../org/apache/hadoop/gateway/launcher/Forker.java |   32 +++
 .../apache/hadoop/gateway/launcher/Invoker.java    |   66 ++++++
 .../apache/hadoop/gateway/launcher/Launcher.java   |  171 +++++++++++++++
 .../apache/hadoop/gateway/launcher/Streamer.java   |   50 +++++
 pom.xml                                            |   18 ++-
 40 files changed, 1153 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-provider-security-jwt/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/pom.xml b/gateway-provider-security-jwt/pom.xml
index c436be9..9a15a04 100644
--- a/gateway-provider-security-jwt/pom.xml
+++ b/gateway-provider-security-jwt/pom.xml
@@ -46,16 +46,16 @@
             <artifactId>commons-io</artifactId>
         </dependency>
 
-	  	  <dependency>
-          <groupId>commons-codec</groupId>
-          <artifactId>commons-codec</artifactId>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
         </dependency>
-        
-				<dependency>
-          <groupId>com.jayway.jsonpath</groupId>
-          <artifactId>json-path</artifactId>
+
+        <dependency>
+            <groupId>com.jayway.jsonpath</groupId>
+            <artifactId>json-path</artifactId>
         </dependency>
-        
+
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml
index a872983..1967ca4 100644
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@ -124,6 +124,12 @@
             <artifactId>gateway-provider-identity-assertion-pseudo</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-shell</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/ComplexCommand.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/ComplexCommand.groovy b/gateway-release/samples/ComplexCommand.groovy
new file mode 100644
index 0000000..c87d5ec
--- /dev/null
+++ b/gateway-release/samples/ComplexCommand.groovy
@@ -0,0 +1,70 @@
+/*
+ * 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 com.jayway.jsonpath.JsonPath
+import org.apache.hadoop.gateway.shell.AbstractRequest
+import org.apache.hadoop.gateway.shell.BasicResponse
+import org.apache.hadoop.gateway.shell.Hadoop
+import org.apache.http.HttpResponse
+import org.apache.http.client.methods.HttpGet
+import org.apache.http.client.utils.URIBuilder
+
+import java.util.concurrent.Callable
+
+class ComplexCommand {
+
+  static class Request extends AbstractRequest<Response> {
+
+    Request( Hadoop hadoop ) {
+      super( hadoop )
+    }
+
+    private String param;
+    Request param( String param ) {
+      this.param = param;
+      return this;
+    }
+
+    @Override
+    protected Callable<Response> callable() {
+      return new Callable<Response>() {
+        @Override
+        Response call() {
+          URIBuilder uri = uri( SampleService.PATH, param );
+          addQueryParam( uri, "op", "LISTSTATUS" );
+          HttpGet get = new HttpGet( uri.build() );
+          return new Response( execute( get ) );
+        }
+      }
+    }
+
+  }
+
+  static class Response extends BasicResponse {
+
+    Response(HttpResponse response) {
+      super(response)
+    }
+
+    public List<String> getNames() {
+      return JsonPath.read( string, "\$.FileStatuses.FileStatus[*].pathSuffix" );
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/SampleScript.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/SampleScript.groovy b/gateway-release/samples/SampleScript.groovy
new file mode 100644
index 0000000..8258d90
--- /dev/null
+++ b/gateway-release/samples/SampleScript.groovy
@@ -0,0 +1,29 @@
+/*
+* 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 org.apache.hadoop.gateway.shell.Hadoop
+
+gateway = "https://localhost:8443/gateway/sample"
+username = "mapred"
+password = "mapred-password"
+
+hadoop = Hadoop.login( gateway, username, password )
+
+println "JSON=" + SampleService.simple(hadoop).param("/tmp").now().string
+
+println "Names=" + SampleService.complex(hadoop).param("/tmp").now().names
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/SampleService.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/SampleService.groovy b/gateway-release/samples/SampleService.groovy
new file mode 100644
index 0000000..ecf7753
--- /dev/null
+++ b/gateway-release/samples/SampleService.groovy
@@ -0,0 +1,32 @@
+/*
+* 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 org.apache.hadoop.gateway.shell.Hadoop
+
+class SampleService {
+
+  static String PATH = "/namenode/api/v1";
+
+  static SimpleCommand simple( Hadoop hadoop ) {
+    return new SimpleCommand( hadoop );
+  }
+
+  static ComplexCommand.Request complex( Hadoop hadoop ) {
+    return new ComplexCommand.Request( hadoop );
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/SimpleCommand.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/SimpleCommand.groovy b/gateway-release/samples/SimpleCommand.groovy
new file mode 100644
index 0000000..f1ce04d
--- /dev/null
+++ b/gateway-release/samples/SimpleCommand.groovy
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.hadoop.gateway.shell.AbstractRequest
+import org.apache.hadoop.gateway.shell.BasicResponse
+import org.apache.hadoop.gateway.shell.Hadoop
+import org.apache.http.client.methods.HttpGet
+import org.apache.http.client.utils.URIBuilder
+
+import java.util.concurrent.Callable
+
+class SimpleCommand extends AbstractRequest<BasicResponse> {
+
+  SimpleCommand( Hadoop hadoop ) {
+    super( hadoop )
+  }
+
+  private String param;
+  SimpleCommand param( String param ) {
+    this.param = param;
+    return this;
+  }
+
+  @Override
+  protected Callable<BasicResponse> callable() {
+    return new Callable<BasicResponse>() {
+      @Override
+      BasicResponse call() {
+        URIBuilder uri = uri( SampleService.PATH, param );
+        addQueryParam( uri, "op", "LISTSTATUS" );
+        HttpGet get = new HttpGet( uri.build() );
+        return new BasicResponse( execute( get ) );
+      }
+    }
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/SmokeTestJob.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/SmokeTestJob.groovy b/gateway-release/samples/SmokeTestJob.groovy
new file mode 100644
index 0000000..871a274
--- /dev/null
+++ b/gateway-release/samples/SmokeTestJob.groovy
@@ -0,0 +1,61 @@
+/**
+ * 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 com.jayway.jsonpath.JsonPath
+import org.apache.hadoop.gateway.shell.Hadoop
+import org.apache.hadoop.gateway.shell.hdfs.Hdfs
+import org.apache.hadoop.gateway.shell.job.Job
+
+import static java.util.concurrent.TimeUnit.SECONDS
+
+gateway = "https://localhost:8443/gateway/sample"
+username = "mapred"
+password = "mapred-password"
+dataFile = "LICENSE"
+jarFile = "samples/hadoop-examples.jar"
+
+hadoop = Hadoop.login( gateway, username, password )
+
+println "Delete /tmp/test " + Hdfs.rm(hadoop).file( "/tmp/test" ).recursive().now().statusCode
+println "Create /tmp/test " + Hdfs.mkdir(hadoop).dir( "/tmp/test").now().statusCode
+
+putData = Hdfs.put(hadoop).file( dataFile ).to( "/tmp/test/input/FILE" ).later() {
+  println "Put /tmp/test/input/FILE " + it.statusCode }
+putJar = Hdfs.put(hadoop).file( jarFile ).to( "/tmp/test/hadoop-examples.jar" ).later() {
+  println "Put /tmp/test/hadoop-examples.jar " + it.statusCode }
+hadoop.waitFor( putData, putJar )
+
+jobId = Job.submitJava(hadoop) \
+  .jar( "/tmp/test/hadoop-examples.jar" ) \
+  .app( "wordcount" ) \
+  .input( "/tmp/test/input" ) \
+  .output( "/tmp/test/output" ) \
+  .now().jobId
+println "Submit job " + jobId
+
+done = false
+count = 0
+while( !done && count++ < 60 ) {
+  sleep( 1000 )
+  json = Job.queryStatus(hadoop).jobId(jobId).now().string
+  done = JsonPath.read( json, "\$.status.jobComplete" )
+}
+println "Done " + done
+
+println "Shutdown " + hadoop.shutdown( 10, SECONDS )
+

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/SmokeTestWorkflow.groovy
----------------------------------------------------------------------
diff --git a/gateway-release/samples/SmokeTestWorkflow.groovy b/gateway-release/samples/SmokeTestWorkflow.groovy
new file mode 100644
index 0000000..c515797
--- /dev/null
+++ b/gateway-release/samples/SmokeTestWorkflow.groovy
@@ -0,0 +1,92 @@
+/**
+ * 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 com.jayway.jsonpath.JsonPath
+import org.apache.hadoop.gateway.shell.Hadoop
+import org.apache.hadoop.gateway.shell.hdfs.Hdfs
+import org.apache.hadoop.gateway.shell.workflow.Workflow
+
+import static java.util.concurrent.TimeUnit.SECONDS
+
+gateway = "https://localhost:8443/gateway/sample"
+jobTracker = "sandbox:50300";
+nameNode = "sandbox:8020";
+username = "mapred"
+password = "mapred-password"
+inputFile = "LICENSE"
+jarFile = "samples/hadoop-examples.jar"
+
+definition = """\
+<workflow-app xmlns="uri:oozie:workflow:0.2" name="wordcount-workflow">
+    <start to="root-node"/>
+    <action name="root-node">
+        <java>
+            <job-tracker>$jobTracker</job-tracker>
+            <name-node>hdfs://$nameNode</name-node>
+            <main-class>org.apache.hadoop.examples.WordCount</main-class>
+            <arg>/tmp/test/input</arg>
+            <arg>/tmp/test/output</arg>
+        </java>
+        <ok to="end"/>
+        <error to="fail"/>
+    </action>
+    <kill name="fail">
+        <message>Java failed, error message[\${wf:errorMessage(wf:lastErrorNode())}]</message>
+    </kill>
+    <end name="end"/>
+</workflow-app>
+"""
+
+configuration = """\
+<configuration>
+    <property>
+        <name>user.name</name>
+        <value>$username</value>
+    </property>
+    <property>
+        <name>oozie.wf.application.path</name>
+        <value>hdfs://$nameNode/tmp/test</value>
+    </property>
+</configuration>
+"""
+
+hadoop = Hadoop.login( gateway, username, password )
+
+println "Delete /tmp/test " + Hdfs.rm(hadoop).file( "/tmp/test" ).recursive().now().statusCode
+println "Mkdir /tmp/test " + Hdfs.mkdir(hadoop).dir( "/tmp/test").now().statusCode
+putWorkflow = Hdfs.put(hadoop).text( definition ).to( "/tmp/test/workflow.xml" ).later() {
+  println "Put /tmp/test/workflow.xml " + it.statusCode }
+putData = Hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/FILE" ).later() {
+  println "Put /tmp/test/input/FILE " + it.statusCode }
+putJar = Hdfs.put(hadoop).file( jarFile ).to( "/tmp/test/lib/hadoop-examples.jar" ).later() {
+  println "Put /tmp/test/lib/hadoop-examples.jar " + it.statusCode }
+hadoop.waitFor( putWorkflow, putData, putJar )
+
+jobId = Workflow.submit(hadoop).text( configuration ).now().jobId
+println "Submit job " + jobId
+
+status = "UNKNOWN";
+count = 0;
+while( status != "SUCCEEDED" && count++ < 60 ) {
+  sleep( 1000 )
+  json = Workflow.status(hadoop).jobId( jobId ).now().string
+  status = JsonPath.read( json, "\$.status" )
+}
+println "Job status " + status;
+
+println "Shutdown " + hadoop.shutdown( 10, SECONDS )

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/samples/hadoop-examples.jar
----------------------------------------------------------------------
diff --git a/gateway-release/samples/hadoop-examples.jar b/gateway-release/samples/hadoop-examples.jar
new file mode 100644
index 0000000..351b77a
Binary files /dev/null and b/gateway-release/samples/hadoop-examples.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-release/templates/topology.xml
----------------------------------------------------------------------
diff --git a/gateway-release/templates/topology.xml b/gateway-release/templates/topology.xml
index c1375fb..4c2dd69 100644
--- a/gateway-release/templates/topology.xml
+++ b/gateway-release/templates/topology.xml
@@ -46,11 +46,11 @@
 
     <service>
         <role>NAMENODE</role>
-        <url>http://localhost:50070/webhdfs/v1</url>
+        <url>http://vm:50070/webhdfs/v1</url>
     </service>
     <service>
         <role>TEMPLETON</role>
-        <url>http://localhost:50111/templeton/v1</url>
+        <url>http://vm:50111/templeton/v1</url>
     </service>
 
 </topology>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-shell/pom.xml b/gateway-shell/pom.xml
index e52f2db..dd54725 100644
--- a/gateway-shell/pom.xml
+++ b/gateway-shell/pom.xml
@@ -43,7 +43,7 @@
                             <transformers>
                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                     <manifestEntries>
-                                        <Main-Class>org.apache.hadoop.gateway.shell.Shell</Main-Class>
+                                        <Main-Class>org.apache.hadoop.gateway.launcher.Launcher</Main-Class>
                                     </manifestEntries>
                                 </transformer>
                             </transformers>
@@ -64,6 +64,11 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>gateway-util-launcher</artifactId>
+            <version>0.2.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
             <groupId>org.codehaus.groovy</groupId>
             <artifactId>groovy-all</artifactId>
             <version>2.1.1</version>

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractRequest.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractRequest.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractRequest.java
index d987c4f..0f1df85 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractRequest.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractRequest.java
@@ -35,7 +35,7 @@ public abstract class AbstractRequest<T> {
 
   private Hadoop hadoop;
 
-  public AbstractRequest( Hadoop hadoop ) {
+  protected AbstractRequest( Hadoop hadoop ) {
     this.hadoop = hadoop;
   }
 
@@ -65,22 +65,27 @@ public abstract class AbstractRequest<T> {
 
   abstract protected Callable<T> callable();
 
-  public T now() throws Exception, URISyntaxException {
-    return callable().call();
+  public T now() throws HadoopException {
+    try {
+      return callable().call();
+    } catch( Exception e ) {
+      throw new HadoopException( e );
+    }
   }
 
   public Future<T> later() {
     return hadoop().executeLater( callable() );
   }
 
-  public void later( final Closure<T> closure ) {
-    hadoop().executeLater( new Callable<T>() {
+  public Future<T> later( final Closure<Void> closure ) {
+    return hadoop().executeLater( new Callable<T>() {
       @Override
       public T call() throws Exception {
-        return closure.call( callable().call() );
+        T result = callable().call();
+        closure.call( result );
+        return result;
       }
     } );
-
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractResponse.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractResponse.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractResponse.java
deleted file mode 100644
index 4dde1b2..0000000
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/AbstractResponse.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.apache.hadoop.gateway.shell;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.entity.ContentType;
-import org.apache.http.util.EntityUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * 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.
- */
-public abstract class AbstractResponse {
-
-  private HttpResponse response;
-  private boolean consumed = false;
-  private String string;
-  private InputStream stream;
-  private byte[] bytes;
-
-  protected AbstractResponse( HttpResponse response ) {
-    this.response = response;
-  }
-
-  public void consume() {
-    if( !consumed ) {
-      EntityUtils.consumeQuietly( response.getEntity() );
-      consumed = true;
-    }
-  }
-
-  public void close() {
-    consume();
-  }
-
-  protected HttpResponse response() {
-    return response;
-  }
-
-  public boolean isConsumed() {
-    return consumed;
-  }
-
-  public int getStatusCode() {
-    return response.getStatusLine().getStatusCode();
-  }
-
-  public long getContentLength() {
-    return response.getEntity().getContentLength();
-  }
-
-  public String getContentType() {
-    return ContentType.getOrDefault( response.getEntity() ).getMimeType();
-  }
-
-  public String getContentEncoding() {
-    return ContentType.getOrDefault( response.getEntity() ).getCharset().name();
-  }
-
-  public InputStream getStream() throws IOException {
-    if( !consumed && stream == null ) {
-      stream = response.getEntity().getContent();
-      consumed = true;
-    }
-    return stream;
-  }
-
-  public String getString() throws IOException {
-    if( !consumed && string == null ) {
-      string = EntityUtils.toString( response.getEntity() );
-      consumed = true;
-    }
-    return string;
-  }
-
-  public byte[] getBytes() throws IOException {
-    if( !consumed && bytes == null ) {
-      bytes = EntityUtils.toByteArray( response.getEntity() );
-      consumed = true;
-    }
-    return bytes;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/BasicResponse.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/BasicResponse.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/BasicResponse.java
new file mode 100644
index 0000000..3ea02a1
--- /dev/null
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/BasicResponse.java
@@ -0,0 +1,98 @@
+package org.apache.hadoop.gateway.shell;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.entity.ContentType;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 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.
+ */
+public class BasicResponse {
+
+  private HttpResponse response;
+  private boolean consumed = false;
+  private String string;
+  private InputStream stream;
+  private byte[] bytes;
+
+  protected BasicResponse( HttpResponse response ) {
+    this.response = response;
+  }
+
+  public void consume() {
+    if( !consumed ) {
+      EntityUtils.consumeQuietly( response.getEntity() );
+      consumed = true;
+    }
+  }
+
+  public void close() {
+    consume();
+  }
+
+  protected HttpResponse response() {
+    return response;
+  }
+
+  public boolean isConsumed() {
+    return consumed;
+  }
+
+  public int getStatusCode() {
+    return response.getStatusLine().getStatusCode();
+  }
+
+  public long getContentLength() {
+    return response.getEntity().getContentLength();
+  }
+
+  public String getContentType() {
+    return ContentType.getOrDefault( response.getEntity() ).getMimeType();
+  }
+
+  public String getContentEncoding() {
+    return ContentType.getOrDefault( response.getEntity() ).getCharset().name();
+  }
+
+  public InputStream getStream() throws IOException {
+    if( !consumed && stream == null ) {
+      stream = response.getEntity().getContent();
+      consumed = true;
+    }
+    return stream;
+  }
+
+  public String getString() throws IOException {
+    if( !consumed && string == null ) {
+      string = EntityUtils.toString( response.getEntity() );
+      consumed = true;
+    }
+    return string;
+  }
+
+  public byte[] getBytes() throws IOException {
+    if( !consumed && bytes == null ) {
+      bytes = EntityUtils.toByteArray( response.getEntity() );
+      consumed = true;
+    }
+    return bytes;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ErrorResponse.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ErrorResponse.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ErrorResponse.java
new file mode 100644
index 0000000..54c3bc9
--- /dev/null
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/ErrorResponse.java
@@ -0,0 +1,35 @@
+/**
+ * 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.hadoop.gateway.shell;
+
+import org.apache.http.HttpResponse;
+
+class ErrorResponse extends RuntimeException {
+
+  HttpResponse response;
+
+  ErrorResponse( HttpResponse response ) {
+    super( "" + response.getStatusLine() );
+    this.response = response;
+  }
+
+  public HttpResponse getReponse() {
+    return response;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Example.groovy
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Example.groovy b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Example.groovy
deleted file mode 100644
index f8f1a1d..0000000
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Example.groovy
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * 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.hadoop.gateway.shell
-
-import org.apache.hadoop.gateway.shell.hdfs.Hdfs as hdfs
-import org.apache.hadoop.gateway.shell.job.Job as job
-
-hadoop = Hadoop.login( "https://localhost:8443/gateway/sample", "mapred", "mapred-password" )
-
-println Hdfs.ls(hadoop).dir( "/" ).now().asString
-
-hdfs.rm(hadoop).file( "/tmp/test" ).recursive().now()
-
-hdfs.mkdir(hadoop).dir( "/tmp/test").now()
-
-hdfs.put(hadoop).file("LICENSE").to("/tmp/test/input/LICENSE").now()
-
-hdfs.put(hadoop).file("hadoop-examples.jar").to("/tmp/test/hadoop-examples.jar").now()
-
-println job.submitJava(hadoop) \
-  .jar("/tmp/test/hadoop-examples.jar") \
-  .app("wordcount") \
-  .input("/temp/test/input") \
-  .output("/temp/test/output") \
-  .now().jobId

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java
index 4fcd3c9..76fe88b 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Hadoop.java
@@ -40,9 +40,12 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.GeneralSecurityException;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 public class Hadoop {
 
@@ -97,11 +100,41 @@ public class Hadoop {
   }
 
   public HttpResponse executeNow( HttpRequest request ) throws IOException {
-    return client.execute( host, request, context );
+    HttpResponse response = client.execute( host, request, context );
+    if( response.getStatusLine().getStatusCode() < 400 ) {
+      return response;
+    } else {
+      throw new ErrorResponse( response );
+    }
   }
 
   public <T> Future<T> executeLater( Callable<T> callable ) {
     return executor.submit( callable );
   }
 
+  public void waitFor( Future<?>... futures ) throws ExecutionException, InterruptedException {
+    if( futures != null ) {
+      for( Future future : futures ) {
+        future.get();
+      }
+    }
+  }
+
+  public void waitFor( long timeout, TimeUnit units, Future<?>... futures ) throws ExecutionException, TimeoutException, InterruptedException {
+    if( futures != null ) {
+      timeout = TimeUnit.MILLISECONDS.convert( timeout, units );
+      long start;
+      for( Future future : futures ) {
+        start = System.currentTimeMillis();
+        future.get( timeout, TimeUnit.MILLISECONDS );
+        timeout -= ( System.currentTimeMillis() - start );
+      }
+    }
+  }
+
+  public boolean shutdown( long timeout, TimeUnit unit ) throws InterruptedException {
+    executor.shutdown();
+    return executor.awaitTermination( timeout, unit );
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HadoopException.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HadoopException.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HadoopException.java
index ebd1cb4..81a101a 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HadoopException.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/HadoopException.java
@@ -23,6 +23,10 @@ public class HadoopException extends RuntimeException {
     super( message );
   }
 
+  public HadoopException( Throwable throwable ) {
+    super( throwable );
+  }
+
   public HadoopException( String message, Throwable throwable ) {
     super( message, throwable );
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Shell.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Shell.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Shell.java
index 937c13b..271b3cf 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Shell.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/Shell.java
@@ -17,11 +17,13 @@
  */
 package org.apache.hadoop.gateway.shell;
 
+import groovy.ui.GroovyMain;
 import org.codehaus.groovy.tools.shell.AnsiDetector;
 import org.codehaus.groovy.tools.shell.Groovysh;
 import org.fusesource.jansi.Ansi;
 import org.fusesource.jansi.AnsiConsole;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 
@@ -33,16 +35,23 @@ public class Shell {
     System.setProperty( "groovysh.prompt", "knox" );
   }
 
-  public static void main( String... args ) {
-    StringWriter buffer = new StringWriter();
-    PrintWriter imports = new PrintWriter( buffer );
-    imports.println( "import org.apache.hadoop.gateway.shell.Hadoop;" );
-    imports.println( "import org.apache.hadoop.gateway.shell.hdfs.Hdfs as hdfs;" );
-    imports.println( "import org.apache.hadoop.gateway.shell.job.Job as job;" );
-    imports.println( "import org.apache.hadoop.gateway.shell.workflow.Workflow as workflow;" );
-    Groovysh shell = new Groovysh();
-    shell.execute( buffer.toString() );
-    shell.run( args );
+  public static void main( String... args ) throws IOException {
+    if( args.length > 0 ) {
+      GroovyMain.main( args );
+    } else {
+      StringWriter buffer = new StringWriter();
+      PrintWriter setup = new PrintWriter( buffer );
+      setup.println( "import org.apache.hadoop.gateway.shell.Hadoop;" );
+      setup.println( "import org.apache.hadoop.gateway.shell.hdfs.Hdfs;" );
+      setup.println( "import org.apache.hadoop.gateway.shell.job.Job;" );
+      setup.println( "import org.apache.hadoop.gateway.shell.workflow.Workflow;" );
+      setup.println( "import java.util.concurrent.TimeUnit;" );
+      //setup.println( "set verbosity QUIET;" );
+      //setup.println( "set show-last-result false;" );
+      Groovysh shell = new Groovysh();
+      shell.execute( buffer.toString() );
+      shell.run();
+    }
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Example.groovy
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Example.groovy b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Example.groovy
index 4408652..23eec1c 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Example.groovy
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Example.groovy
@@ -17,30 +17,39 @@
  */
 package org.apache.hadoop.gateway.shell.hdfs
 
-import org.apache.hadoop.gateway.shell.hdfs.Hdfs as hdfs
-
 import org.apache.hadoop.gateway.shell.Hadoop
 
+import static java.util.concurrent.TimeUnit.SECONDS
+
 gateway = "https://localhost:8443/gateway/sample"
 username = "mapred"
 password = "mapred-password"
-inputFile = "/Users/kevin.minder/Projects/gateway-0.2.0-SNAPSHOT/LICENSE"
 jarFile = "/Users/kevin.minder/Projects/gateway-0.2.0-SNAPSHOT/hadoop-examples.jar"
+inputFile = "/Users/kevin.minder/Projects/gateway-0.2.0-SNAPSHOT/LICENSE"
+outputFile = "/Users/kevin.minder/Projects/gateway-0.2.0-SNAPSHOT/OUTPUT"
 
 hadoop = Hadoop.login( gateway, username, password )
 
 println Hdfs.ls(hadoop).dir( "/" ).now().string
 
-hdfs.rm(hadoop).file( "/tmp/test" ).recursive().now()
+Hdfs.rm(hadoop).file( "/tmp/test" ).recursive().now()
+
+Hdfs.mkdir(hadoop).dir( "/tmp/test").now()
+
+Hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE" ).now()
+
+future = Hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE2" ).later()
+println "Done=" + future.isDone()
+hadoop.waitFor( future )
+println "Status=" + future.get().statusCode
 
-hdfs.mkdir(hadoop).dir( "/tmp/test").now()
+future = Hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE3" ).later() { println "Status=" + it.statusCode }
+hadoop.waitFor( future )
+println "Status=" + future.get().statusCode
 
-hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE" ).now()
+Hdfs.get(hadoop).file( outputFile ).from( "/tmp/test/input/LICENSE" ).now()
 
-future = hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE2" ).later()
-println future.get().statusCode
+hadoop.shutdown( 10, SECONDS );
 
-hdfs.put(hadoop).file( inputFile ).to( "/tmp/test/input/LICENSE3" ).later() { println it.statusCode }
 
-hdfs.get(hadoop).file( "/Users/kevin.minder/Projects/gateway-0.2.0-SNAPSHOT/OUTPUT" ).from( "/tmp/test/input/LICENSE" ).now()
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Get.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Get.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Get.java
index e9d3c41..d1114f8 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Get.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Get.java
@@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell.hdfs;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -65,7 +65,7 @@ public class Get {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response, String to ) throws IOException {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Ls.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Ls.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Ls.java
index 9e1ce27..6fc3cc0 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Ls.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Ls.java
@@ -18,7 +18,7 @@
 package org.apache.hadoop.gateway.shell.hdfs;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -55,7 +55,7 @@ class Ls {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Mkdir.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Mkdir.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Mkdir.java
index 0f7f1ba..0f63bda 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Mkdir.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Mkdir.java
@@ -18,14 +18,12 @@
 package org.apache.hadoop.gateway.shell.hdfs;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.utils.URIBuilder;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.concurrent.Callable;
 
 class Mkdir {
@@ -64,7 +62,7 @@ class Mkdir {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Put.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Put.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Put.java
index 9510a64..fd084ff 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Put.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Put.java
@@ -18,7 +18,7 @@
 package org.apache.hadoop.gateway.shell.hdfs;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.hadoop.gateway.shell.HadoopException;
 import org.apache.http.Header;
@@ -32,10 +32,7 @@ import org.apache.http.entity.StringEntity;
 import org.apache.http.util.EntityUtils;
 
 import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
 import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
 
 class Put {
 
@@ -96,7 +93,7 @@ class Put {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Rm.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Rm.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Rm.java
index 955eb9f..d54dfae 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Rm.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/hdfs/Rm.java
@@ -18,7 +18,7 @@
 package org.apache.hadoop.gateway.shell.hdfs;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpDelete;
@@ -67,7 +67,7 @@ class Rm {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) throws IOException {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Hive.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Hive.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Hive.java
index edc8474..69e21be 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Hive.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Hive.java
@@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell.job;
 
 import com.jayway.jsonpath.JsonPath;
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
@@ -83,7 +83,7 @@ public class Hive {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     protected Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Java.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Java.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Java.java
index 16b2ac4..8317965 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Java.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Java.java
@@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell.job;
 
 import com.jayway.jsonpath.JsonPath;
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
@@ -29,7 +29,6 @@ import org.apache.http.client.utils.URIBuilder;
 import org.apache.http.message.BasicNameValuePair;
 
 import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -87,7 +86,7 @@ class Java {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     public Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Pig.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Pig.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Pig.java
index d87831f..430f7cc 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Pig.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Pig.java
@@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell.job;
 
 import com.jayway.jsonpath.JsonPath;
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
@@ -28,14 +28,13 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.utils.URIBuilder;
 
 import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
 
 public class Pig {
 
-  static class Request extends AbstractRequest {
+  static class Request extends AbstractRequest<Response> {
 
     private String group;
     private String file;
@@ -86,7 +85,7 @@ public class Pig {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     protected Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Queue.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Queue.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Queue.java
index baf2bc3..08dd7ff 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Queue.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Queue.java
@@ -18,19 +18,17 @@
 package org.apache.hadoop.gateway.shell.job;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.utils.URIBuilder;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.concurrent.Callable;
 
 class Queue {
 
-  static class Request extends AbstractRequest {
+  static class Request extends AbstractRequest<Response> {
 
     public Request( Hadoop hadoop ) {
       super( hadoop );
@@ -49,7 +47,7 @@ class Queue {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     protected Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Status.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Status.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Status.java
index 5f8cb56..812c08f 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Status.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/job/Status.java
@@ -18,19 +18,17 @@
 package org.apache.hadoop.gateway.shell.job;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.utils.URIBuilder;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.concurrent.Callable;
 
 class Status {
 
-  static class Request extends AbstractRequest {
+  static class Request extends AbstractRequest<Response> {
 
     private String jobId;
 
@@ -56,7 +54,7 @@ class Status {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     protected Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Status.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Status.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Status.java
index 431f7c3..add8fee 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Status.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Status.java
@@ -18,7 +18,7 @@
 package org.apache.hadoop.gateway.shell.workflow;
 
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -28,7 +28,7 @@ import java.util.concurrent.Callable;
 
 class Status {
 
-  static class Request extends AbstractRequest {
+  static class Request extends AbstractRequest<Response> {
 
     private String jobId;
 
@@ -54,7 +54,7 @@ class Status {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Submit.java
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Submit.java b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Submit.java
index 2406e53..b508b91 100644
--- a/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Submit.java
+++ b/gateway-shell/src/main/java/org/apache/hadoop/gateway/shell/workflow/Submit.java
@@ -19,7 +19,7 @@ package org.apache.hadoop.gateway.shell.workflow;
 
 import com.jayway.jsonpath.JsonPath;
 import org.apache.hadoop.gateway.shell.AbstractRequest;
-import org.apache.hadoop.gateway.shell.AbstractResponse;
+import org.apache.hadoop.gateway.shell.BasicResponse;
 import org.apache.hadoop.gateway.shell.Hadoop;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
@@ -31,12 +31,11 @@ import org.apache.http.entity.StringEntity;
 
 import java.io.File;
 import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.concurrent.Callable;
 
 class Submit {
 
-  static class Request extends AbstractRequest {
+  static class Request extends AbstractRequest<Response> {
 
     private String text;
     private String file;
@@ -82,7 +81,7 @@ class Submit {
 
   }
 
-  static class Response extends AbstractResponse {
+  static class Response extends BasicResponse {
 
     Response( HttpResponse response ) {
       super( response );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-shell/src/main/resources/META-INF/launcher.cfg
----------------------------------------------------------------------
diff --git a/gateway-shell/src/main/resources/META-INF/launcher.cfg b/gateway-shell/src/main/resources/META-INF/launcher.cfg
new file mode 100644
index 0000000..1a377c0
--- /dev/null
+++ b/gateway-shell/src/main/resources/META-INF/launcher.cfg
@@ -0,0 +1,16 @@
+# 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.
+main.class = org.apache.hadoop.gateway.shell.Shell
+class.path = ../lib; ../lib/*.jar; ../ext; ../ext/*.jar

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/pom.xml b/gateway-util-launcher/pom.xml
new file mode 100644
index 0000000..8682a4f
--- /dev/null
+++ b/gateway-util-launcher/pom.xml
@@ -0,0 +1,39 @@
+<?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>
+    <parent>
+        <artifactId>gateway</artifactId>
+        <groupId>org.apache.hadoop</groupId>
+        <version>0.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>gateway-util-launcher</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.11</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Command.java
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Command.java b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Command.java
new file mode 100644
index 0000000..e49d348
--- /dev/null
+++ b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Command.java
@@ -0,0 +1,154 @@
+/**
+ * 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.hadoop.gateway.launcher;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+class Command {
+
+  private static String MAIN_CLASS = "main.class";
+  private static String MAIN_METHOD = "main.method";
+  private static String MAIN_ARGS = "main.args";
+  private static String CLASS_PATH = "class.path";
+  private static String FORK = "fork";
+  private static String REDIRECT = "redirect";
+  private static String RESTREAM = "restream";
+  private static String ENV_PREFIX = "env.";
+  private static int ENV_PREFIX_LENGTH = ENV_PREFIX.length();
+
+  File base;
+  Properties config;
+  String mainClass;
+  String mainMethod = "main";
+  String[] mainArgs;
+  List<URL> classPath;
+  Properties props;
+  Map<String,String> vars;
+  Boolean fork = Boolean.FALSE;
+  Boolean redirect = Boolean.FALSE; // Controls redirecting stderr to stdout if forking.
+  Boolean restream = Boolean.TRUE; // Controls creation of threads to read/write stdin, stdout, stderr of child if forking.
+
+  Command( File base, Properties config, String[] args ) throws MalformedURLException {
+    this.base = base;
+    this.config = config;
+    this.mainArgs = args ;
+    consumeConfig( config );
+  }
+
+  void consumeConfig( Properties config ) throws MalformedURLException {
+    mainClass = config.getProperty( MAIN_CLASS );
+    config.remove( MAIN_CLASS );
+    mainMethod = config.getProperty( MAIN_METHOD, mainMethod );
+    config.remove( MAIN_METHOD );
+    mainArgs = loadMainArgs( mainArgs, config.getProperty( MAIN_ARGS ) );
+    config.remove( MAIN_ARGS );
+    classPath = loadClassPath( base, config.getProperty( CLASS_PATH ) );
+    config.remove( CLASS_PATH );
+    fork = Boolean.valueOf( config.getProperty( FORK, fork.toString() ) );
+    config.remove( FORK );
+    redirect = Boolean.valueOf( config.getProperty( REDIRECT, redirect.toString() ) );
+    config.remove( REDIRECT );
+    restream = Boolean.valueOf( config.getProperty( RESTREAM, restream.toString() ) );
+    config.remove( RESTREAM );
+    consumeSysPropsAndEnvVars( config );
+  }
+
+  void consumeSysPropsAndEnvVars( Properties config ) {
+    props = new Properties();
+    vars = new HashMap<String,String>();
+    for( String name : config.stringPropertyNames() ) {
+      String value = config.getProperty( name );
+      if( name.startsWith( ENV_PREFIX ) ) {
+        vars.put( name.substring( ENV_PREFIX_LENGTH ), value );
+      } else {
+        props.setProperty( name, value );
+      }
+    }
+  }
+
+  public void run() throws InvocationTargetException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException {
+//TODO    ((URLClassLoader)this.getClass().getClassLoader()).getURLs();
+    if( fork ) {
+      Forker.fork( this );
+    } else {
+      Invoker.invoke( this );
+    }
+  }
+
+  private static String[] loadMainArgs( String[] current, String override ) {
+    String[] args = current;
+    if( args == null || args.length == 0 ) {
+      if( override != null ) {
+        args = override.split( " " );
+      }
+    }
+    return args;
+  }
+
+  private static List<URL> loadClassPath( File base, String classPath ) throws MalformedURLException {
+    List<URL> urls = new ArrayList<URL>();
+    StringTokenizer parser = new StringTokenizer( classPath, ";", false );
+    while( parser.hasMoreTokens() ) {
+      String libPath = parser.nextToken().trim();
+      File libFile = new File( base, libPath );
+      if( libFile.canRead() && ( libFile.isFile() || libFile.isDirectory() ) ) {
+        urls.add( libFile.toURI().toURL() );
+      } else if( libPath.endsWith( "*" ) || libPath.endsWith( "*.jar" ) ) {
+        File libDir = libFile.getParentFile();
+        File[] libFiles = libDir.listFiles( new WildcardFilenameFilter( libFile.getName() ) );
+        if( libFiles != null ) {
+          for( File file : libFiles ) {
+            urls.add( file.toURI().toURL() );
+          }
+        }
+      }
+    }
+    return urls;
+  }
+
+  private static class WildcardFilenameFilter implements FilenameFilter {
+
+    private static String SAFE = new String( new char[]{ (char)0 } );
+
+    private Pattern pattern;
+
+    private WildcardFilenameFilter( String filter ) {
+      filter = filter.replace( ".", SAFE );
+      filter = filter.replace( "*", ".*" );
+      filter.replace( SAFE, "\\." );
+      pattern = Pattern.compile( filter );
+    }
+
+    @Override
+    public boolean accept( File dir, String name ) {
+      return pattern.matcher( name ).matches();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Forker.java
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Forker.java b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Forker.java
new file mode 100644
index 0000000..77bf327
--- /dev/null
+++ b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Forker.java
@@ -0,0 +1,32 @@
+/**
+ * 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.hadoop.gateway.launcher;
+
+class Forker {
+
+  static void fork( Command command ) {
+    throw new UnsupportedOperationException();
+//    String[] cmd = null;
+//    String[] env = null;
+//    Runtime.getRuntime().exec( cmd, env );
+//    System.getenv();
+//    ProcessBuilder pb = new ProcessBuilder();
+//    Process process = pb.start();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Invoker.java
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Invoker.java b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Invoker.java
new file mode 100644
index 0000000..b53aab2
--- /dev/null
+++ b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Invoker.java
@@ -0,0 +1,66 @@
+/**
+ * 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.hadoop.gateway.launcher;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+import java.util.Properties;
+
+class Invoker {
+
+  private static String[] STRING_ARRAY = new String[0];
+  private static Class STRING_ARRAY_CLASS = STRING_ARRAY.getClass();
+
+  static void invoke( Command command ) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+    setSysProps( command.props );
+    ClassLoader mainLoader = createClassLoader( command.classPath );
+    Class mainClass = loadMainClass( mainLoader, command.mainClass );
+    Method mainMethod = findMainMethod( mainClass, command.mainMethod );
+    invokeMainMethod( mainMethod, command.mainArgs );
+  }
+
+  private static void setSysProps( Properties properties ) {
+    for( String name : properties.stringPropertyNames() ) {
+      System.setProperty( name, properties.getProperty( name ) );
+    }
+  }
+
+  private static ClassLoader createClassLoader( List<URL> urls ) {
+    URL[] urlArray = new URL[ urls.size() ];
+    urls.toArray( urlArray );
+    return new URLClassLoader( urlArray );
+  }
+
+  private static Class loadMainClass( ClassLoader loader, String className ) throws ClassNotFoundException {
+    Class mainClass = loader.loadClass( className );
+    return mainClass;
+  }
+
+  private static Method findMainMethod( Class mainClass, String methodName ) throws NoSuchMethodException {
+    Method method = mainClass.getMethod( methodName, STRING_ARRAY_CLASS );
+    return method;
+  }
+
+  private static void invokeMainMethod( Method method, String[] args ) throws InvocationTargetException, IllegalAccessException {
+    method.invoke( method.getClass(), (Object)args );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Launcher.java
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Launcher.java b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Launcher.java
new file mode 100644
index 0000000..5f21ccd
--- /dev/null
+++ b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Launcher.java
@@ -0,0 +1,171 @@
+/**
+ * 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.hadoop.gateway.launcher;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.util.Properties;
+
+public class Launcher {
+
+  private static String LAUNCHER_PREFIX = "launcher.";
+  private static String CFG_EXT = "cfg";
+  private static String LAUNCHER_CFG = "META-INF/" + LAUNCHER_PREFIX + CFG_EXT;
+  private static String EXTRACT = "extract";
+  private static String OVERRIDE = "override";
+
+  private URL launcherJarUrl;
+  private File launcherJarDir;
+  private String launcherName;
+  private URL embeddedConfigUrl;
+  private URL externalConfigUrl;
+  private Command command;
+
+  private Boolean extract = Boolean.TRUE;
+  private Boolean override = Boolean.TRUE;
+
+  public static void main( String[] args ) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
+    Launcher launcher = new Launcher( args );
+    launcher.run();
+  }
+
+  Launcher( String[] args ) throws IOException {
+    launcherJarUrl = findLauncherJar();
+    launcherJarDir = calcLauncherDir( launcherJarUrl );
+    launcherName = calcLauncherName( launcherJarUrl );
+    embeddedConfigUrl = findEmbeddedConfig();
+    Properties properties = new Properties();
+    loadProperties( properties, embeddedConfigUrl );
+    consumeLauncherConfig( properties );
+    if( override ) {
+      externalConfigUrl = findOrCreateExternalConfig( launcherJarDir, launcherName, properties, embeddedConfigUrl, extract );
+      if( externalConfigUrl != null ) {
+        loadProperties( properties, externalConfigUrl );
+      }
+    }
+    command = new Command( launcherJarDir, properties, args );
+  }
+
+  void run() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
+    command.run();
+  }
+
+  private static URL findLauncherJar() throws IOException {
+    URL jarUrl;
+    try {
+      jarUrl = Launcher.class.getProtectionDomain().getCodeSource().getLocation();
+    } catch( SecurityException e ) {
+      throw e;
+//      URL classUrl = Launcher.class.getResource( Launcher.class.getSimpleName() + ".class" );
+//      if( classUrl != null ) {
+//        URLConnection urlConnection = classUrl.openConnection();
+//        if( urlConnection instanceof JarURLConnection ) {
+//          JarURLConnection jarUrlConnection = (JarURLConnection)urlConnection;
+//          jarUrl = jarUrlConnection.getJarFileURL();
+//        }
+//      }
+    }
+    //System.out.println( "main.lib=" + url );
+    return jarUrl;
+  }
+
+  static String calcLauncherName( URL launcherJarUrl ) {
+    String name = launcherJarUrl.getPath();
+    name = fileName( name );
+    name = baseName( name );
+    return name;
+  }
+
+  void consumeLauncherConfig( Properties properties ) {
+    extract = Boolean.valueOf( properties.getProperty( EXTRACT, extract.toString() ) );
+    properties.remove( EXTRACT );
+    override = Boolean.valueOf( properties.getProperty( OVERRIDE, override.toString() ) );
+    properties.remove( OVERRIDE );
+  }
+
+  private static File calcLauncherDir( URL libUrl ) {
+    String libPath = libUrl.getFile();
+    File libFile = new File( libPath );
+    File dir;
+    if( libFile.isDirectory() ) {
+      dir = libFile;
+    } else {
+      dir = libFile.getParentFile();
+    }
+    //System.out.println( "main.dir=" + dir.getAbsolutePath() );
+    return dir;
+  }
+
+  private static URL findEmbeddedConfig() {
+    return ClassLoader.getSystemResource( LAUNCHER_CFG );
+  }
+
+  private static void createExternalConfig( File file, Properties config, URL src ) throws IOException {
+    if( file.createNewFile() ){
+      OutputStream output = new FileOutputStream( file );
+      try {
+        config.store( output, "Created from " + src );
+      } finally {
+        output.close();
+      }
+    }
+  }
+
+  private static URL findOrCreateExternalConfig( File launcherJarDir, String launcherName, Properties embeddedConfig, URL embeddedConfigUrl, boolean extract ) throws IOException {
+    File externalConfigFile = new File( launcherJarDir, launcherName + "." + CFG_EXT );
+    if( !externalConfigFile.exists() && extract ) {
+      createExternalConfig( externalConfigFile, embeddedConfig, embeddedConfigUrl );
+    }
+    URL externalConfigUrl = null;
+    if( externalConfigFile.isFile() && externalConfigFile.canRead() ) {
+      externalConfigUrl = externalConfigFile.toURI().toURL();
+    }
+    return externalConfigUrl;
+  }
+
+  private static Properties loadProperties( Properties properties, URL url ) throws IOException {
+    if( url != null ) {
+      InputStream stream = url.openStream();
+      try {
+        properties.load( stream );
+      } finally {
+        stream.close();
+      }
+    }
+    return properties;
+  }
+
+  static String fileName( String fullName ) {
+    int i = fullName.lastIndexOf( '/' );
+    if( i < 0 ) {
+      i = fullName.lastIndexOf( '\\' );
+    }
+    return i < 0 ? fullName : fullName.substring( i + 1 );
+  }
+
+  static String baseName( String fullName ) {
+    int i = fullName.lastIndexOf( '.' );
+    return i < 0 ? fullName : fullName.substring( 0, i );
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Streamer.java
----------------------------------------------------------------------
diff --git a/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Streamer.java b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Streamer.java
new file mode 100644
index 0000000..a78d446
--- /dev/null
+++ b/gateway-util-launcher/src/main/java/org/apache/hadoop/gateway/launcher/Streamer.java
@@ -0,0 +1,50 @@
+/**
+ * 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.hadoop.gateway.launcher;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class Streamer extends Thread {
+
+  InputStream input;
+  OutputStream output;
+  byte[] buffer;
+
+  private Streamer( String name, InputStream input, OutputStream output, int buffer, int priority ) {
+    this.buffer = new byte[ buffer ];
+    this.setName( name );
+    this.setPriority( priority );
+    this.start();
+  }
+
+  @Override
+  public void run() {
+    try {
+      int read = input.read( buffer );
+      while( read >= 0 ) {
+        output.write( buffer, 0, read );
+        read = input.read( buffer );
+      }
+    } catch( IOException e ) {
+      e.printStackTrace();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d084401b/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index ed628c0..e0eabf2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,6 +43,7 @@
     <modules>
         <module>gateway-test-utils</module>
         <module>gateway-util-common</module>
+        <module>gateway-util-launcher</module>
         <module>gateway-util-urltemplate</module>
         <module>gateway-test-ldap</module>
         <module>gateway-i18n</module>
@@ -59,10 +60,10 @@
         <module>gateway-service-templeton</module>
         <module>gateway-service-oozie</module>
         <module>gateway-server</module>
+        <module>gateway-shell</module>
         <module>gateway-release</module>
         <module>gateway-test</module>
         <module>gateway-demo</module>
-        <module>gateway-shell</module>
         <module>gateway-site</module>
     </modules>
 
@@ -248,6 +249,16 @@
             </dependency>
             <dependency>
                 <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-util-launcher</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-util-launcher</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
                 <artifactId>gateway-util-urltemplate</artifactId>
                 <version>${gateway-version}</version>
             </dependency>
@@ -323,6 +334,11 @@
             </dependency>
             <dependency>
                 <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-shell</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
                 <artifactId>gateway-release</artifactId>
                 <version>${gateway-version}</version>
             </dependency>