zeppelin-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject [6/6] zeppelin git commit: [ZEPPELIN-732] Helium Application
Date Mon, 04 Jul 2016 15:33:03 GMT
[ZEPPELIN-732] Helium Application

### What is this PR for?
This PR implements pluggable Application Framework.

Here's summary of the change.

**Applicaiton**

Base class of user application. User application should extends `org.apache.zeppelin.helium.Application`.

It looks like

```java
public abstract class Application {

  /**
   * When application loaded
   * params context Application context
   */
  public Application(ApplicationContext context) {
    this.context = context;
  }

  /**
   * This method can be invoked multiple times before unload(),
   * Invoked just after application loaded or when paragraph output is updated
   * param args Required resources from paragraph
   */
  public abstract void run(ResourceSet args)
      throws ApplicationException, IOException;

  /**
   * this method is invoked just before application is removed
   */
  public abstract void unload() throws ApplicationException;
}
```

**HeliumPackage**

`org.apache.zeppelin.helium.HeliumPackage` keeps information of application package.
Package informations includes

```
{
  type : "APPLICATION",                            // type of this package
  name : "zeppelin.app",                           // application name. [organizationName].[appName] format
  description : "App description",                 // description
  artifact : "groupId:artifactId:version",         // artifact name for maven repository
  className : "org.apache.zeppelin.helium.MyApp",  // application class that extends org.apache.zeppelin.helium.Application
  resources : [[]],                                // required resource
  icon : '<i class="fa fa-clock-o"></i>'           // icon
}
```

`resources` field defines what kind of data this application requires, from ResourcePool.
"resourceName" and ":className" works in the array.
inner array combines each resourceName, :className with 'AND'
outer array combines inner array with 'OR'.

For example,

```
resources : [
    [ "name1", ":java.util.Date"],
    [ "name1", "name2"]
]
```

Then Zeppelin searches ResourcePool, first for resource name "name1" and resource type "java.util.Date" from resourcePool then resource name "name1" and "name2".

Once resources are found, they'll be passed to `Application.run()` method

**Package Registry**

`org.apache.zeppelin.helium.HeliumRegistry` provides list of available HeliumPackages.
Currently `HeliumLocalRegistry` is implemented and it provides list by reading HeliumPackage json files under ./helium directory in the file system. Later there will be some class like `HeliumOnlineRegistry'  which reads available package from a community managed online central registry.

**Development mode**
`org.apache.zeppelin.interpreter.dev.*` package is provided for development support.
Developer can run their app inside of their IDE, that connects to running Zeppelin instance and display output.

**Application Suggestion**
Once paragraph becomes FINISHED status after run, Zeppelin searches resources from ResourcesPool that belongs to current paragraph. And compare all HeliumPackage if these resources satisfies their requirements ('resources' field). If there're available app, Helium button will be displayed.

![image](https://cloud.githubusercontent.com/assets/1540981/14518452/d8f85d5a-020f-11e6-8313-00b37eb4f077.png)

User can see and select available application for this paragraph.
![image](https://cloud.githubusercontent.com/assets/1540981/14518465/ee607fce-020f-11e6-8ad4-fe98723c7c94.png)

**Application selection**
After application is loaded, application icon will be displayed. So user can select and switch between apps.

![image](https://cloud.githubusercontent.com/assets/1540981/14518547/6f3fd766-0210-11e6-9a08-0dc2ba6d15e3.png)

if built-in visualization is available, application icon will be displayed next to built-in visualizations
![image](https://cloud.githubusercontent.com/assets/1540981/14518500/27505746-0210-11e6-9738-fb514376b906.png)

**Experimental**

While this is new feature and API and specification may change, i'd suggest mark this feature as a experimental for a while.

### What type of PR is it?
Feature

### Todos
* [x] - Helium Application framework
* [x] - App launcher
* [x] - App display and selectors
* [x] - Package registry
* [x] - Development mode
* [x] - Make CI green
* [x] - Improve comment in source codes
* [x] - Documentation
* [x] - Examples
* [x] - Mark experimental
* [ ] - Review

### What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-732

### How should this be tested?
Will be updated with examples

### Screenshots (if appropriate)
![helium](https://cloud.githubusercontent.com/assets/1540981/14518685/49c2a788-0211-11e6-81c8-6cae48bf8a48.gif)

### Questions:
* Does the licenses files need update? no
* Is there breaking changes for older versions? no
* Does this needs documentation? yes

Author: Lee moon soo <moon@apache.org>

Closes #836 from Leemoonsoo/ZEPPELIN-732-up and squashes the following commits:

3577777 [Lee moon soo] Address Ahyoung's comment
0665380 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
83b529c [Lee moon soo] Update unittest
e1b0e79 [Lee moon soo] Update unittest
6785441 [Lee moon soo] interpreter order changed
3249ddb [Lee moon soo] Remove incubating
4030fff [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
4e98cfe [Lee moon soo] Update DependencyResolver
c714a19 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
d558591 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
0467077 [Lee moon soo] update test
d43ab57 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
f999f71 [Lee moon soo] Update getParagraphXpath
eaa68c6 [Lee moon soo] print processes
5b5f6c8 [Lee moon soo] trigger ci
1bdea70 [Lee moon soo] Print error message in the test
562f083 [Lee moon soo] CLose interpreter after test
385dab3 [Lee moon soo] Fix xpath in the SparkParagraphIt test
ac963ff [Lee moon soo] Remove unnecessary stacktrace and provide more meaningful message
644add4 [Lee moon soo] Takecare csv/tsv download button position after merge
6a5a19e [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
5bef173 [Lee moon soo] Update NoteTest
e54d633 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
88dbc71 [Lee moon soo] change style
6f1343f [Lee moon soo] add license header
4571781 [Lee moon soo] double quote the keys in json
710487b [Lee moon soo] fix syntax error
6c5019e [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
3619afd [Lee moon soo] Exclude test data file from rat check
b6811a6 [Lee moon soo] set SPARK_HOME to find bin/interpreter.sh
9110897 [Lee moon soo] arrange buttons
14efb6c [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
76de11c [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
bff2217 [Lee moon soo] Fix SparkParagraphIT
e60cd8e [Lee moon soo] Add docs
7f174e3 [Lee moon soo] Add more comments
0671dfd [Lee moon soo] Fix compile error
bfcdf34 [Lee moon soo] Fix style
1dc4409 [Lee moon soo] Remove incubating from example pom.xml
e36d2fb [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
e0a2046 [Lee moon soo] Add annotation to api
93fa766 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
99dd0b0 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
e89177e [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
f782fb0 [Lee moon soo] clean pom.xml file
b974eb1 [Lee moon soo] Add horizontal bar visualization example
5225551 [Lee moon soo] let instead of var
b068065 [Lee moon soo] Replace . to _
b6e4141 [Lee moon soo] helper for printing javascript and inject $z
8186daf [Lee moon soo] Update Application Status from RemoteInterpreterProcess event
f07ada1 [Lee moon soo] Construct classpath correctly
7451479 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
ab1de03 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
51fc113 [Lee moon soo] Include examples in CI build
83eba98 [Lee moon soo] UnloadApp on interpreter restart
3b891de [Lee moon soo] Provide resource pool for testing
0730ece [Lee moon soo] Add license into package json
620f79f [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
01a1646 [Lee moon soo] Add example
1f1a3b5 [Lee moon soo] Fix test
864bea1 [Lee moon soo] Merge branch 'master' into ZEPPELIN-732-up
c30f53c [Lee moon soo] null check
03be3a1 [Lee moon soo] Pass required resource to run() method
fade3c1 [Lee moon soo] Handle output update in angular mode
0e4d81c [Lee moon soo] Remove unnecessary log
ec2fdea [Lee moon soo] Match classname correctly
b4ff52f [Lee moon soo] Put last value of scala repl into resource pool
f2ab95d [Lee moon soo] Prevent unnecessary output update
71f814d [Lee moon soo] Better way to find resource dir for InterpreterOutput watcher
024d7fc [Lee moon soo] Dev mode
98f3872 [Lee moon soo] Managed interpreter process and Running interpreter process
b47ca74 [Lee moon soo] Fix tests
5503f9c [Lee moon soo] Improved
be3a1fa [Lee moon soo] Add license header
412480a [Lee moon soo] Fix style
16f6887 [Lee moon soo] Angular object update for helium app
6223cd4 [Lee moon soo] App output display
bd0f467 [Lee moon soo] Style
94b490d [Lee moon soo] initial rest api impl
134bbe6 [Lee moon soo] Change HeliumRegistry constructor argument type
7aeb64a [Lee moon soo] Unload app on paragraph / note removal as well as interpreter unbind
4eaeea7 [Lee moon soo] sync -> async api
9f5c493 [Lee moon soo] Application output
b239f1b [Lee moon soo] Helium application factory
b891b98 [Lee moon soo] HeliumRegistry
568ee54 [Lee moon soo] ApplicationLoader
7424af2 [Lee moon soo] Remove resource on note / paragraph removal


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/9463fb85
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/9463fb85
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/9463fb85

Branch: refs/heads/master
Commit: 9463fb854764a99a5161226cb95c439bafff5f54
Parents: ebe8855
Author: Lee moon soo <moon@apache.org>
Authored: Sun Jul 3 07:58:25 2016 -0700
Committer: Lee moon soo <moon@apache.org>
Committed: Mon Jul 4 08:35:07 2016 -0700

----------------------------------------------------------------------
 .travis.yml                                     |    4 +-
 README.md                                       |    8 +
 docs/_includes/themes/zeppelin/_navigation.html |    1 +
 docs/development/writingzeppelinapplication.md  |  185 ++
 pom.xml                                         |    7 +
 .../apache/zeppelin/spark/SparkInterpreter.java |   33 +-
 .../zeppelin/spark/SparkInterpreterTest.java    |    3 +-
 .../zeppelin/spark/SparkSqlInterpreterTest.java |    3 +-
 zeppelin-examples/pom.xml                       |   65 +
 .../zeppelin-example-clock/pom.xml              |  111 +
 .../zeppelin/example/app/clock/Clock.java       |  113 +
 .../main/resources/example/app/clock/clock.html |   14 +
 .../zeppelin-example-clock.json                 |   25 +
 .../zeppelin-example-horizontalbar/pom.xml      |  121 +
 .../app/horizontalbar/HorizontalBar.java        |   85 +
 .../example/app/horizontalbar/horizontalbar.js  |   56 +
 .../horizontalbar/horizontalbar_mockdata.txt    |   10 +
 .../zeppelin-example-horizontalbar.json         |   25 +
 .../org/apache/zeppelin/helium/Application.java |  151 +
 .../zeppelin/helium/ApplicationContext.java     |   60 +
 .../helium/ApplicationEventListener.java        |   27 +
 .../zeppelin/helium/ApplicationException.java   |   34 +
 .../zeppelin/helium/ApplicationLoader.java      |  226 ++
 .../zeppelin/helium/ClassLoaderApplication.java |   72 +
 .../helium/HeliumAppAngularObjectRegistry.java  |   55 +
 .../apache/zeppelin/helium/HeliumPackage.java   |   99 +
 .../zeppelin/interpreter/InterpreterGroup.java  |    1 -
 .../zeppelin/interpreter/InterpreterOutput.java |   49 +-
 .../interpreter/dev/DevInterpreter.java         |  122 +
 .../dev/ZeppelinApplicationDevServer.java       |  162 +
 .../interpreter/dev/ZeppelinDevServer.java      |  126 +
 .../interpreter/remote/ClientFactory.java       |    5 +
 .../remote/RemoteAngularObjectRegistry.java     |    4 +-
 .../interpreter/remote/RemoteInterpreter.java   |   95 +-
 .../remote/RemoteInterpreterEventClient.java    |   51 +
 .../remote/RemoteInterpreterEventPoller.java    |   48 +-
 .../remote/RemoteInterpreterManagedProcess.java |  166 +
 .../remote/RemoteInterpreterProcess.java        |  159 +-
 .../remote/RemoteInterpreterRunningProcess.java |   67 +
 .../remote/RemoteInterpreterServer.java         |  211 +-
 .../thrift/RemoteApplicationResult.java         |  518 +++
 .../thrift/RemoteInterpreterEventType.java      |    5 +-
 .../thrift/RemoteInterpreterService.java        | 3060 +++++++++++++++++-
 .../zeppelin/resource/ResourcePoolUtils.java    |    2 +
 .../resource/WellKnownResourceName.java         |    3 +-
 .../zeppelin/scheduler/RemoteScheduler.java     |    5 +-
 .../main/thrift/RemoteInterpreterService.thrift |   12 +-
 .../zeppelin/helium/ApplicationLoaderTest.java  |  104 +
 .../zeppelin/helium/MockApplication1.java       |   52 +
 .../remote/RemoteAngularObjectTest.java         |    1 +
 .../RemoteInterpreterOutputTestStream.java      |    3 +-
 .../remote/RemoteInterpreterProcessTest.java    |   16 +-
 .../remote/RemoteInterpreterTest.java           |    9 +-
 .../resource/DistributedResourcePoolTest.java   |   18 +-
 .../zeppelin/scheduler/RemoteSchedulerTest.java |    6 +-
 .../org/apache/zeppelin/rest/HeliumRestApi.java |  108 +
 .../apache/zeppelin/server/ZeppelinServer.java  |   38 +-
 .../apache/zeppelin/socket/NotebookServer.java  |   81 +-
 .../zeppelin/integration/SparkParagraphIT.java  |    2 +-
 .../zeppelin/rest/AbstractTestRestApi.java      |    2 +-
 .../zeppelin/rest/ZeppelinSparkClusterTest.java |    6 +
 .../paragraph/paragraph-chart-selector.html     |  158 +-
 .../notebook/paragraph/paragraph-results.html   |    9 +
 .../notebook/paragraph/paragraph.controller.js  |  293 +-
 .../src/app/notebook/paragraph/paragraph.css    |    5 +
 .../websocketEvents/websocketEvents.factory.js  |    8 +
 zeppelin-web/test/spec/controllers/paragraph.js |   11 +-
 .../zeppelin/conf/ZeppelinConfiguration.java    |    9 +
 .../java/org/apache/zeppelin/helium/Helium.java |  172 +
 .../helium/HeliumApplicationFactory.java        |  480 +++
 .../org/apache/zeppelin/helium/HeliumConf.java  |   35 +
 .../zeppelin/helium/HeliumLocalRegistry.java    |   82 +
 .../helium/HeliumPackageSearchResult.java       |   43 +
 .../helium/HeliumPackageSuggestion.java         |   53 +
 .../apache/zeppelin/helium/HeliumRegistry.java  |   41 +
 .../helium/HeliumRegistrySerializer.java        |   70 +
 .../interpreter/InterpreterFactory.java         |   94 +-
 .../zeppelin/interpreter/InterpreterOption.java |   29 +-
 .../zeppelin/notebook/ApplicationState.java     |  109 +
 .../java/org/apache/zeppelin/notebook/Note.java |  100 +-
 .../zeppelin/notebook/NoteEventListener.java    |   28 +
 .../org/apache/zeppelin/notebook/Notebook.java  |   87 +-
 .../notebook/NotebookEventListener.java         |   29 +
 .../org/apache/zeppelin/notebook/Paragraph.java |  109 +-
 .../zeppelin/notebook/repo/VFSNotebookRepo.java |   10 +
 .../zeppelin/notebook/socket/Message.java       |   12 +-
 .../helium/HeliumApplicationFactoryTest.java    |  323 ++
 .../helium/HeliumLocalRegistryTest.java         |   64 +
 .../org/apache/zeppelin/helium/HeliumTest.java  |  101 +
 .../zeppelin/helium/HeliumTestApplication.java  |   45 +
 .../zeppelin/helium/HeliumTestRegistry.java     |   39 +
 .../interpreter/InterpreterFactoryTest.java     |   44 +-
 .../interpreter/mock/MockInterpreter1.java      |   32 +-
 .../notebook/NoteInterpreterLoaderTest.java     |    2 +-
 .../org/apache/zeppelin/notebook/NoteTest.java  |   19 +-
 .../apache/zeppelin/notebook/NotebookTest.java  |   63 +-
 .../notebook/repo/NotebookRepoSyncTest.java     |    2 +-
 .../notebook/repo/VFSNotebookRepoTest.java      |    2 +-
 .../zeppelin/search/LuceneSearchTest.java       |    2 +-
 99 files changed, 9196 insertions(+), 528 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 7fa8e15..19a05cb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,7 +35,7 @@ matrix:
   include:
     # Test all modules
     - jdk: "oraclejdk7"
-      env: SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.3 -Ppyspark -Psparkr -Pscalding" BUILD_FLAG="package -Pbuild-distr" TEST_FLAG="verify -Pusing-packaged-distr" TEST_PROJECTS=""
+      env: SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.3 -Ppyspark -Psparkr -Pscalding -Pexamples" BUILD_FLAG="package -Pbuild-distr" TEST_FLAG="verify -Pusing-packaged-distr" TEST_PROJECTS=""
 
     # Test spark module for 1.5.2
     - jdk: "oraclejdk7"
@@ -59,7 +59,7 @@ matrix:
 
     # Test selenium with spark module for 1.6.1
     - jdk: "oraclejdk7"
-      env: TEST_SELENIUM="true" SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Phadoop-2.3 -Ppyspark" BUILD_FLAG="package -DskipTests" TEST_FLAG="verify" TEST_PROJECTS="-pl zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
+      env: TEST_SELENIUM="true" SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Phadoop-2.3 -Ppyspark -Pexamples" BUILD_FLAG="package -DskipTests" TEST_FLAG="verify" TEST_PROJECTS="-pl zeppelin-interpreter,zeppelin-zengine,zeppelin-server,zeppelin-display,spark-dependencies,spark -Dtest=org.apache.zeppelin.AbstractFunctionalSuite -DfailIfNoTests=false"
 
 before_install:
   - "ls -la .spark-dist ${HOME}/.m2/repository/.cache/maven-download-plugin"

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 990cc9a..eee427c 100644
--- a/README.md
+++ b/README.md
@@ -201,6 +201,13 @@ Available profiles are
 -Pmapr51
 ```
 
+#### -Pexamples (optional)
+
+Bulid examples under zeppelin-examples directory
+
+
+
+
 
 Here're some examples:
 
@@ -231,6 +238,7 @@ mvn clean package -Dignite.version=1.6.0 -DskipTests
 mvn clean package -Pscalding -DskipTests
 ```
 
+
 ### Configure
 If you wish to configure Zeppelin option (like port number), configure the following files:
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/docs/_includes/themes/zeppelin/_navigation.html
----------------------------------------------------------------------
diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html
index fce8cee..8a99c84 100644
--- a/docs/_includes/themes/zeppelin/_navigation.html
+++ b/docs/_includes/themes/zeppelin/_navigation.html
@@ -104,6 +104,7 @@
                 <li role="separator" class="divider"></li>
                 <li class="title"><span><b>Contibute</b><span></li>
                 <li><a href="{{BASE_PATH}}/development/writingzeppelininterpreter.html">Writing Zeppelin Interpreter</a></li>
+                <li><a href="{{BASE_PATH}}/development/writingzeppelinapplication.html">Writing Zeppelin Application</a></li>                
                 <li><a href="{{BASE_PATH}}/development/howtocontribute.html">How to contribute (code)</a></li>
                 <li><a href="{{BASE_PATH}}/development/howtocontributewebsite.html">How to contribute (website)</a></li>
               </ul>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/docs/development/writingzeppelinapplication.md
----------------------------------------------------------------------
diff --git a/docs/development/writingzeppelinapplication.md b/docs/development/writingzeppelinapplication.md
new file mode 100644
index 0000000..1256d1b
--- /dev/null
+++ b/docs/development/writingzeppelinapplication.md
@@ -0,0 +1,185 @@
+---
+layout: page
+title: "Writing Zeppelin Application"
+description: ""
+group: development
+---
+<!--
+Licensed 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.
+-->
+{% include JB/setup %}
+
+# What is Zeppelin Application (Experimental)
+
+Apache Zeppelin Application is a package that runs on Interpreter process and displays it's output inside of the notebook. While application runs on Interpreter process, it's able to access resources provided by Interpreter through ResourcePool. Output is always rendered by AngularDisplaySystem. Therefore application provides all the possiblities of making interactive graphical application that uses data and processing power of any Interpreter.
+
+
+
+## Writing your own Application
+
+Writing Application means extending `org.apache.zeppelin.helium.Application`. You can use your favorite IDE and language while Java class files are packaged into jar. `Application` class looks like
+
+```java
+
+/**
+ * Constructor. Invoked when application is loaded
+ */
+public Application(ApplicationContext context);
+
+/**
+ * Invoked when there're (possible) updates in required resource set.
+ * i.e. invoked after application load and after paragraph finishes.
+ */
+public abstract void run(ResourceSet args);
+
+/**
+ * Invoked before application unload.
+ * Application is automatically unloaded with paragraph/notebook removal
+ */
+public abstract void unload();
+```
+
+
+You can check example applications under [./zeppelin-examples](https://github.com/apache/incubator-zeppelin/tree/master/zeppelin-examples) directory.
+
+
+## Development mode
+
+In the development mode, you can run your Application in your IDE as a normal java application and see the result inside of Zeppelin notebook.
+
+org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer can run Zeppelin Application in development mode.
+
+```java
+
+// entry point for development mode
+public static void main(String[] args) throws Exception {
+
+  // add resources for development mode
+  LocalResourcePool pool = new LocalResourcePool("dev");
+  pool.put("date", new Date());
+
+  // run application in devlopment mode with give resource
+  // in this case, Clock.class.getName() will be the application class name  
+  ZeppelinApplicationDevServer devServer = new ZeppelinApplicationDevServer(
+      Clock.class.getName(),
+      pool.getAll());
+
+  // start development mode
+  devServer.start();
+  devServer.join();
+}
+```
+
+
+In the Zeppelin notebook, run `%dev run` will connect to application running in development mode.
+
+
+
+
+## Package file
+
+Package file is a json file that provides information about the application.
+Json file contains following informations
+
+```
+{
+  name : "[organization].[name]",
+  description : "Description",
+  artifact : "groupId:artifactId:version",
+  className : "your.package.name.YourApplicationClass",
+  resources : [
+    ["resource.name", ":resource.class.name"],
+    ["alternative.resource.name", ":alternative.class.name"]
+  ],
+  icon : "<i class="icon"></i>"
+}
+
+```
+
+#### name
+
+Name is a string in '[group].[name]' format.
+[group] and [name] allows only [A-Za-z0-9_].
+Group is normally organization name who creates this application.
+
+#### description
+
+Short description. about application
+
+#### artifact
+
+Location of the jar artifact.
+"groupId:artifactId:version" will make load artifact from maven repository.
+If jar is in local filesystem, absolute/relative can be used.
+
+e.g.
+
+When artifact exists in Maven repository
+
+`artifact: "org.apache.zeppelin:zeppelin-examples:0.6.0"`
+
+When artifact exists in local filesystem
+
+`artifact: "zeppelin-example/target/zeppelin-example-0.6.0.jar"`
+
+
+#### className
+
+Entry point. Class that extends `org.apache.zeppelin.helium.Application`
+
+
+#### resources
+
+Two dimensional array that defines required resources by name or by className. Helium Application launcher will compare resources in the ResourcePool with informations in this field and suggest application only when all required resources are available in the ResourcePool.
+
+Resouce name is a string which will be compared with name of objects in the ResourcePool. className is a string with ":" prepended, which will be compared with className of the objects in the ResourcePool.
+
+Application may require two or more resources. Required resource can be listed inside of json array. For example, if application requires object "name1", "name2" and "className1" type of object to run, resources field can be
+
+```
+resources: [
+  [ "name1", "name2", ":className1", ...]
+]
+```
+
+If Application can handle alternative combination of required resource, alternative set can be listed as below.
+
+```
+resources: [
+  [ "name", ":className"],
+  [ "altName", ":altClassName1"],
+  ...
+]
+```
+
+Easier way of understanding this scheme is
+
+```
+resources: [
+   [ 'resource' AND 'resource' AND ... ] OR
+   [ 'resource' AND 'resource' AND ... ] OR
+   ...
+]
+```
+
+
+#### icon
+
+Icon to be used on the application button. String in this field will be rendered as a html.
+
+e.g.
+
+```
+icon: "<i class='fa fa-clock-o'></i>"
+```
+

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 602b06e..d1dda13 100755
--- a/pom.xml
+++ b/pom.xml
@@ -668,6 +668,13 @@
     </profile>
 
     <profile>
+      <id>examples</id>
+      <modules>
+        <module>zeppelin-examples</module>
+      </modules>
+    </profile>
+
+    <profile>
       <id>build-distr</id>
       <activation>
         <activeByDefault>false</activeByDefault>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java b/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
index 6783378..53bfc02 100644
--- a/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
+++ b/spark/src/main/java/org/apache/zeppelin/spark/SparkInterpreter.java
@@ -50,6 +50,8 @@ import org.apache.zeppelin.interpreter.InterpreterResult;
 import org.apache.zeppelin.interpreter.InterpreterResult.Code;
 import org.apache.zeppelin.interpreter.InterpreterUtils;
 import org.apache.zeppelin.interpreter.WrappedInterpreter;
+import org.apache.zeppelin.resource.ResourcePool;
+import org.apache.zeppelin.resource.WellKnownResourceName;
 import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
 import org.apache.zeppelin.scheduler.Scheduler;
 import org.apache.zeppelin.scheduler.SchedulerFactory;
@@ -533,7 +535,9 @@ public class SparkInterpreter extends Interpreter {
       binder.put("sc", sc);
       binder.put("sqlc", sqlc);
       binder.put("z", z);
-
+      binder.put("intp", intp);
+      intp.interpret("@transient val intp = _binder.get(\"intp\").asInstanceOf[org.apache.spark" +
+          ".repl.SparkIMain]");
       intp.interpret("@transient val z = "
               + "_binder.get(\"z\").asInstanceOf[org.apache.zeppelin.spark.ZeppelinContext]");
       intp.interpret("@transient val sc = "
@@ -759,13 +763,10 @@ public class SparkInterpreter extends Interpreter {
   public InterpreterResult interpretInput(String[] lines, InterpreterContext context) {
     SparkEnv.set(env);
 
-    // add print("") to make sure not finishing with comment
-    // see https://github.com/NFLabs/zeppelin/issues/151
-    String[] linesToRun = new String[lines.length + 1];
+    String[] linesToRun = new String[lines.length];
     for (int i = 0; i < lines.length; i++) {
       linesToRun[i] = lines[i];
     }
-    linesToRun[lines.length] = "print(\"\")";
 
     Console.setOut(context.out);
     out.setInterpreterOutput(context.out);
@@ -828,17 +829,39 @@ public class SparkInterpreter extends Interpreter {
       }
     }
 
+    // make sure code does not finish with comment
+    if (r == Code.INCOMPLETE) {
+      scala.tools.nsc.interpreter.Results.Result res;
+      res = intp.interpret(incomplete + "\nprint(\"\")");
+      r = getResultCode(res);
+    }
+
     if (r == Code.INCOMPLETE) {
       sc.clearJobGroup();
       out.setInterpreterOutput(null);
       return new InterpreterResult(r, "Incomplete expression");
     } else {
       sc.clearJobGroup();
+      putLatestVarInResourcePool(context);
       out.setInterpreterOutput(null);
       return new InterpreterResult(Code.SUCCESS);
     }
   }
 
+  private void putLatestVarInResourcePool(InterpreterContext context) {
+    String varName = intp.mostRecentVar();
+    if (varName == null || varName.isEmpty()) {
+      return;
+    }
+
+    Object lastObj = getValue(varName);
+    if (lastObj != null) {
+      ResourcePool resourcePool = context.getResourcePool();
+      resourcePool.put(context.getNoteId(), context.getParagraphId(),
+          WellKnownResourceName.ZeppelinReplResult.toString(), lastObj);
+    }
+  };
+
 
   @Override
   public void cancel(InterpreterContext context) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
index eb8d876..90f311e 100644
--- a/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
+++ b/spark/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java
@@ -29,6 +29,7 @@ import org.apache.spark.SecurityManager;
 import org.apache.spark.SparkConf;
 import org.apache.spark.SparkContext;
 import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.resource.LocalResourcePool;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.display.GUI;
 import org.apache.zeppelin.interpreter.*;
@@ -95,7 +96,7 @@ public class SparkInterpreterTest {
         new HashMap<String, Object>(),
         new GUI(),
         new AngularObjectRegistry(intpGroup.getId(), null),
-        null,
+        new LocalResourcePool("id"),
         new LinkedList<InterpreterContextRunner>(),
         new InterpreterOutput(new InterpreterOutputListener() {
           @Override

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
----------------------------------------------------------------------
diff --git a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java b/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
index 3196cf5..73d5e8a 100644
--- a/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
+++ b/spark/src/test/java/org/apache/zeppelin/spark/SparkSqlInterpreterTest.java
@@ -24,6 +24,7 @@ import java.util.LinkedList;
 import java.util.Properties;
 
 import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.resource.LocalResourcePool;
 import org.apache.zeppelin.user.AuthenticationInfo;
 import org.apache.zeppelin.display.GUI;
 import org.apache.zeppelin.interpreter.*;
@@ -77,7 +78,7 @@ public class SparkSqlInterpreterTest {
     context = new InterpreterContext("note", "id", "title", "text", new AuthenticationInfo(),
         new HashMap<String, Object>(), new GUI(),
         new AngularObjectRegistry(intpGroup.getId(), null),
-        null,
+        new LocalResourcePool("id"),
         new LinkedList<InterpreterContextRunner>(), new InterpreterOutput(new InterpreterOutputListener() {
       @Override
       public void onAppend(InterpreterOutput out, byte[] line) {

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-examples/pom.xml b/zeppelin-examples/pom.xml
new file mode 100644
index 0000000..a017d3c
--- /dev/null
+++ b/zeppelin-examples/pom.xml
@@ -0,0 +1,65 @@
+<?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>zeppelin</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.6.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-examples</artifactId>
+  <packaging>pom</packaging>
+  <version>0.6.0-SNAPSHOT</version>
+  <name>Zeppelin: Examples</name>
+  <description>Zeppelin examples</description>
+  <url>http://zeppelin.apache.org</url>
+
+  <modules>
+    <module>zeppelin-example-clock</module>
+    <module>zeppelin-example-horizontalbar</module>
+  </modules>
+  
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <version>2.7</version>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>1.3.1</version>
+        <executions>
+          <execution>
+            <id>enforce</id>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-clock/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-clock/pom.xml b/zeppelin-examples/zeppelin-example-clock/pom.xml
new file mode 100644
index 0000000..7ed5fce
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-clock/pom.xml
@@ -0,0 +1,111 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>zeppelin-examples</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.6.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-example-clock</artifactId>
+  <packaging>jar</packaging>
+  <version>0.6.0-SNAPSHOT</version>
+  <name>Zeppelin: Example application - Clock</name>
+  <url>http://zeppelin.apache.org</url>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-interpreter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <version>2.7</version>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-clean-plugin</artifactId>
+        <configuration>
+          <filesets>
+            <fileset>
+              <directory>${project.basedir}/../../helium</directory>
+              <includes>
+                <include>${project.artifactId}.json</include>
+              </includes>
+            </fileset>
+          </filesets>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.7</version>
+        <executions>
+          <execution>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+
+            <configuration>
+              <outputDirectory>${project.basedir}/../../helium/</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>${project.basedir}</directory>
+                  <includes>
+                    <include>${project.artifactId}.json</include>
+                  </includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-clock/src/main/java/org/apache/zeppelin/example/app/clock/Clock.java
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-clock/src/main/java/org/apache/zeppelin/example/app/clock/Clock.java b/zeppelin-examples/zeppelin-example-clock/src/main/java/org/apache/zeppelin/example/app/clock/Clock.java
new file mode 100644
index 0000000..632b35f
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-clock/src/main/java/org/apache/zeppelin/example/app/clock/Clock.java
@@ -0,0 +1,113 @@
+/*
+ * 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.zeppelin.example.app.clock;
+
+import org.apache.zeppelin.helium.Application;
+import org.apache.zeppelin.helium.ApplicationContext;
+import org.apache.zeppelin.helium.ApplicationException;
+import org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer;
+import org.apache.zeppelin.resource.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Basic example application.
+ * Get java.util.Date from resource pool and display it
+ */
+public class Clock extends Application {
+  private final Logger logger = LoggerFactory.getLogger(Clock.class);
+
+  Date date;
+  boolean shutdown = false;
+  private Thread updateThread;
+
+  public Clock(ApplicationContext context) {
+    super(context);
+  }
+
+  @Override
+  public void run(ResourceSet resources) throws ApplicationException {
+    // Get data from resource args
+    date = (Date) resources.get(0).get();
+
+    // print view template
+    try {
+      context().out.writeResource("example/app/clock/clock.html");
+    } catch (IOException e) {
+      throw new ApplicationException(e);
+    }
+
+    if (updateThread == null) {
+      start();
+    }
+  }
+
+
+  public void start() {
+    updateThread = new Thread() {
+      public void run() {
+        while (!shutdown) {
+          // format date
+          SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+          // put formatted string to angular object.
+          context().getAngularObjectRegistry().add("date", df.format(date));
+
+          try {
+            Thread.sleep(1000);
+          } catch (InterruptedException e) {
+            // nothing todo
+          }
+          date = new Date(date.getTime() + 1000);
+        }
+      }
+    };
+
+    updateThread.start();
+  }
+
+
+  @Override
+  public void unload() throws ApplicationException {
+    shutdown = true;
+    try {
+      updateThread.join();
+    } catch (InterruptedException e) {
+      // nothing to do
+    }
+    context().getAngularObjectRegistry().remove("date");
+  }
+
+  /**
+   * Development mode
+   */
+  public static void main(String[] args) throws Exception {
+    LocalResourcePool pool = new LocalResourcePool("dev");
+    pool.put("date", new Date());
+
+    ZeppelinApplicationDevServer devServer = new ZeppelinApplicationDevServer(
+        Clock.class.getName(),
+        pool.getAll());
+
+    devServer.start();
+    devServer.join();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-clock/src/main/resources/example/app/clock/clock.html
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-clock/src/main/resources/example/app/clock/clock.html b/zeppelin-examples/zeppelin-example-clock/src/main/resources/example/app/clock/clock.html
new file mode 100644
index 0000000..ff492f0
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-clock/src/main/resources/example/app/clock/clock.html
@@ -0,0 +1,14 @@
+<!--
+Licensed 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.
+-->
+<h3>{{date}}</h3>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-clock/zeppelin-example-clock.json
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-clock/zeppelin-example-clock.json b/zeppelin-examples/zeppelin-example-clock/zeppelin-example-clock.json
new file mode 100644
index 0000000..7cb05fe
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-clock/zeppelin-example-clock.json
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+{
+  "type" : "APPLICATION",
+  "name" : "zeppelin.clock",
+  "description" : "Clock (example)",
+  "artifact" : "zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.6.0-SNAPSHOT.jar",
+  "className" : "org.apache.zeppelin.example.app.clock.Clock",
+  "resources" : [[":java.util.Date"]],
+  "icon" : '<i class="fa fa-clock-o"></i>'
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-horizontalbar/pom.xml
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-horizontalbar/pom.xml b/zeppelin-examples/zeppelin-example-horizontalbar/pom.xml
new file mode 100644
index 0000000..f34c55e
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-horizontalbar/pom.xml
@@ -0,0 +1,121 @@
+<?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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>zeppelin-examples</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.6.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-example-horizontalbar</artifactId>
+  <packaging>jar</packaging>
+  <version>0.6.0-SNAPSHOT</version>
+  <name>Zeppelin: Example application - Horizontal Bar chart</name>
+  <url>http://zeppelin.apache.org</url>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-interpreter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <version>2.7</version>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-clean-plugin</artifactId>
+        <configuration>
+          <filesets>
+            <fileset>
+              <directory>${project.basedir}/../../helium</directory>
+              <includes>
+                <include>${project.artifactId}.json</include>
+              </includes>
+            </fileset>
+          </filesets>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.7</version>
+        <executions>
+          <execution>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>copy-resources</goal>
+            </goals>
+
+            <configuration>
+              <outputDirectory>${project.basedir}/../../helium/</outputDirectory>
+              <resources>
+                <resource>
+                  <directory>${project.basedir}</directory>
+                  <includes>
+                    <include>${project.artifactId}.json</include>
+                  </includes>
+                </resource>
+              </resources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/horizontalbar_mockdata.txt</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-horizontalbar/src/main/java/org/apache/zeppelin/example/app/horizontalbar/HorizontalBar.java
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-horizontalbar/src/main/java/org/apache/zeppelin/example/app/horizontalbar/HorizontalBar.java b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/java/org/apache/zeppelin/example/app/horizontalbar/HorizontalBar.java
new file mode 100644
index 0000000..fa209f6
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/java/org/apache/zeppelin/example/app/horizontalbar/HorizontalBar.java
@@ -0,0 +1,85 @@
+/*
+ * 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.zeppelin.example.app.horizontalbar;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.zeppelin.helium.Application;
+import org.apache.zeppelin.helium.ApplicationContext;
+import org.apache.zeppelin.helium.ApplicationException;
+import org.apache.zeppelin.interpreter.InterpreterResult;
+import org.apache.zeppelin.interpreter.dev.ZeppelinApplicationDevServer;
+import org.apache.zeppelin.resource.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+/**
+ * Basic example application.
+ * TableData for input
+ */
+public class HorizontalBar extends Application {
+  private final Logger logger = LoggerFactory.getLogger(HorizontalBar.class);
+
+  InterpreterResult result;
+
+  public HorizontalBar(ApplicationContext context) {
+    super(context);
+  }
+
+  @Override
+  public void run(ResourceSet resources) throws ApplicationException, IOException {
+    // Get data from resource args
+    result = (InterpreterResult) resources.get(0).get();
+
+    // create element
+    println(String.format(
+        "<div id=\"horizontalbar_%s\" style=\"height:400px\"><svg></svg></div>",
+        context().getApplicationInstanceId()));
+    // write js
+    printResourceAsJavascript("example/app/horizontalbar/horizontalbar.js");
+  }
+
+  @Override
+  public void unload() throws ApplicationException {
+  }
+
+  /**
+   * Development mode
+   */
+  public static void main(String[] args) throws Exception {
+    LocalResourcePool pool = new LocalResourcePool("dev");
+    InputStream ins = ClassLoader.getSystemResourceAsStream(
+        "example/app/horizontalbar/horizontalbar_mockdata.txt");
+    InterpreterResult result = new InterpreterResult(
+        InterpreterResult.Code.SUCCESS,
+        InterpreterResult.Type.TABLE,
+        IOUtils.toString(ins));
+    pool.put(WellKnownResourceName.ZeppelinTableResult.name(), result);
+
+    ZeppelinApplicationDevServer devServer = new ZeppelinApplicationDevServer(
+        HorizontalBar.class.getName(),
+        pool.getAll());
+
+    devServer.start();
+    devServer.join();
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar.js
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar.js b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar.js
new file mode 100644
index 0000000..fac2c8e
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar.js
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+var data = [];
+_.forEach($z.result.columnNames, function(col, series) {
+   if (series == 0) return;
+   var values = _.map($z.result.rows, function(row) {
+       return {
+           label: row[0],
+           value : parseFloat(row[series])
+       }
+   });
+
+   data.push({
+       key : col.name,
+       values : values
+   })
+});
+
+nv.addGraph(function() {
+    var chart = nv.models.multiBarHorizontalChart()
+        .x(function(d) { return d.label })
+        .y(function(d) { return d.value })
+        .margin({top: 30, right: 20, bottom: 50, left: 175})
+        .showValues(true)           //Show bar value next to each bar.
+        .tooltips(true)             //Show tooltips on hover.
+        .showControls(true);        //Allow user to switch between "Grouped" and "Stacked" mode.
+
+    chart.yAxis
+        .tickFormat(d3.format(',.2f'));
+
+    d3.select('#horizontalbar_' + $z.id + ' svg')
+        .datum(data)
+        .call(chart);
+
+    nv.utils.windowResize(chart.update);
+
+    return chart;
+});
+
+
+

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar_mockdata.txt
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar_mockdata.txt b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar_mockdata.txt
new file mode 100644
index 0000000..adf322d
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-horizontalbar/src/main/resources/example/app/horizontalbar/horizontalbar_mockdata.txt
@@ -0,0 +1,10 @@
+Label	Series1	Series2
+GroupA	-1.8746444827653	25.307646510375
+GroupB	-8.0961543492239	16.756779544553
+GroupC	-0.57072943117674	18.451534877007
+GroupD	-2.4174010336624	8.6142352811805
+GroupE	-0.72009071426284	7.8082472075876
+GroupF	-0.77154485523777	5.259101026956
+GroupG	-0.90152097798131	0.30947953487127
+GroupH	-0.91445417330854	0
+GroupI	-0.055746319141851	0

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-examples/zeppelin-example-horizontalbar/zeppelin-example-horizontalbar.json
----------------------------------------------------------------------
diff --git a/zeppelin-examples/zeppelin-example-horizontalbar/zeppelin-example-horizontalbar.json b/zeppelin-examples/zeppelin-example-horizontalbar/zeppelin-example-horizontalbar.json
new file mode 100644
index 0000000..afac737
--- /dev/null
+++ b/zeppelin-examples/zeppelin-example-horizontalbar/zeppelin-example-horizontalbar.json
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+{
+  "type" : "APPLICATION",
+  "name" : "zeppelin.horizontalbar",
+  "description" : "Horizontal Bar chart (example)",
+  "artifact" : "zeppelin-examples/zeppelin-example-horizontalbar/target/zeppelin-example-horizontalbar-0.6.0-SNAPSHOT.jar",
+  "className" : "org.apache.zeppelin.example.app.horizontalbar.HorizontalBar",
+  "resources" : [[":org.apache.zeppelin.interpreter.InterpreterResult"]],
+  "icon" : '<i class="fa fa-bar-chart" style="-webkit-transform: rotate(90deg) scaleX(-1);-moz-transform: rotate(90deg) scaleX(-1);-ms-transform: rotate(90deg) scaleX(-1);"></i>'
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/Application.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/Application.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/Application.java
new file mode 100644
index 0000000..2918998
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/Application.java
@@ -0,0 +1,151 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.annotation.Experimental;
+import org.apache.zeppelin.interpreter.InterpreterContext;
+import org.apache.zeppelin.resource.ResourceSet;
+
+import java.io.IOException;
+
+/**
+ * Base class for pluggable application (e.g. visualization)
+ * Application can access resources from ResourcePool and interact with front-end using
+ * AngularDisplay system
+ */
+@Experimental
+public abstract class Application {
+
+  private final ApplicationContext context;
+
+  public Application(ApplicationContext context) {
+    this.context = context;
+  }
+
+  public ApplicationContext context() {
+    return context;
+  }
+
+  /**
+   * This method can be invoked multiple times before unload(),
+   * Either just after application selected or when paragraph re-run after application load
+   */
+  @Experimental
+  public abstract void run(ResourceSet args)
+      throws ApplicationException, IOException;
+
+
+  /**
+   * this method is invoked just before application is removed
+   */
+  @Experimental
+  public abstract void unload() throws ApplicationException;
+
+  /**
+   * Print string on the notebook
+   * @param string
+   * @throws IOException
+   */
+  @Experimental
+  public void print(String string) throws IOException {
+    context.out.write(string);
+  }
+
+  /**
+   * Print string on the notebook with newline
+   * @param string
+   * @throws IOException
+   */
+  @Experimental
+  public void println(String string) throws IOException {
+    print(string + "\n");
+  }
+
+  /**
+   * Print resource on the notebook
+   * @param resourceName
+   * @throws IOException
+   */
+  @Experimental
+  public void printResource(String resourceName) throws IOException {
+    context.out.writeResource(resourceName);
+  }
+
+  /**
+   * Print resource as a javascript
+   *
+   * Using this method does not require print javascript inside of <script></script> tag.
+   * Javascript printed using this method will be run in the un-named function.
+   * i.e. each method call will creates different variable scope for the javascript code.
+   *
+   * This method inject '$z' into the variable scope for convenience.
+   *
+   * $z.scope : angularjs scope object for this application
+   * $z.id : unique id for this application instance
+   *
+   * @param resourceName
+   * @throws IOException
+   */
+  @Experimental
+  public void printResourceAsJavascript(String resourceName) throws IOException {
+    beginJavascript();
+    context.out.writeResource(resourceName);
+    endJavascript();
+  }
+
+  /**
+   * Print string as a javascript
+   *
+   * Using this method does not require print javascript inside of <script></script> tag.
+   * Javascript printed using this method will be run in the un-named function.
+   * i.e. each method call will creates different variable scope for the javascript code.
+   *
+   * This method inject '$z' into the variable scope for convenience.
+   *
+   * $z.scope : angularjs scope object for this application
+   * $z.id : unique id for this application instance
+   *
+   * @param js
+   * @throws IOException
+   */
+  @Experimental
+  public void printStringAsJavascript(String js) throws IOException {
+    beginJavascript();
+    context.out.write(js);
+    endJavascript();
+  }
+
+  private void beginJavascript() throws IOException {
+    StringBuffer js = new StringBuffer();
+    js.append("\n<script id=\"app_js_" + js.hashCode() + "\">\n");
+    js.append("(function() {\n");
+    js.append("let $z = {\n");
+    js.append("id : \"" + context.getApplicationInstanceId() + "\",\n");
+    js.append("scope : angular.element(\"#app_js_" + js.hashCode() + "\").scope()\n");
+    js.append("};\n");
+    js.append("$z.result = ($z.scope._devmodeResult) ? " +
+        "$z.scope._devmodeResult : $z.scope.$parent.paragraph.result;\n");
+    context.out.write(js.toString());
+  }
+
+  private void endJavascript() throws IOException {
+    StringBuffer js = new StringBuffer();
+    js.append("\n})();\n");
+    js.append("</script>\n");
+    context.out.write(js.toString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationContext.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationContext.java
new file mode 100644
index 0000000..e0ea94c
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationContext.java
@@ -0,0 +1,60 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.interpreter.InterpreterOutput;
+
+/**
+ * ApplicationContext
+ */
+public class ApplicationContext {
+  private final String noteId;
+  private final String paragraphId;
+  private final String applicationInstanceId;
+  private final HeliumAppAngularObjectRegistry angularObjectRegistry;
+  public final InterpreterOutput out;
+
+
+  public ApplicationContext(String noteId,
+                            String paragraphId,
+                            String applicationInstanceId,
+                            HeliumAppAngularObjectRegistry angularObjectRegistry,
+                            InterpreterOutput out) {
+    this.noteId = noteId;
+    this.paragraphId = paragraphId;
+    this.applicationInstanceId = applicationInstanceId;
+    this.angularObjectRegistry = angularObjectRegistry;
+    this.out = out;
+  }
+
+  public String getNoteId() {
+    return noteId;
+  }
+
+  public String getParagraphId() {
+    return paragraphId;
+  }
+
+  public String getApplicationInstanceId() {
+    return applicationInstanceId;
+  }
+
+  public HeliumAppAngularObjectRegistry getAngularObjectRegistry() {
+    return angularObjectRegistry;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationEventListener.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationEventListener.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationEventListener.java
new file mode 100644
index 0000000..f89bb21
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationEventListener.java
@@ -0,0 +1,27 @@
+/*
+ * 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.zeppelin.helium;
+
+/**
+ * Event from HeliumApplication running on remote interpreter process
+ */
+public interface ApplicationEventListener {
+  public void onOutputAppend(String noteId, String paragraphId, String appId, String output);
+  public void onOutputUpdated(String noteId, String paragraphId, String appId, String output);
+  public void onLoad(String noteId, String paragraphId, String appId, HeliumPackage pkg);
+  public void onStatusChange(String noteId, String paragraphId, String appId, String status);
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationException.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationException.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationException.java
new file mode 100644
index 0000000..4bf0ac2
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationException.java
@@ -0,0 +1,34 @@
+/*
+ * 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.zeppelin.helium;
+
+/**
+ * Application exception
+ */
+public class ApplicationException extends Exception {
+  public ApplicationException(String s) {
+    super(s);
+  }
+
+  public ApplicationException(Exception e) {
+    super(e);
+  }
+
+  public ApplicationException() {
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationLoader.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationLoader.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationLoader.java
new file mode 100644
index 0000000..be36ad9
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ApplicationLoader.java
@@ -0,0 +1,226 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.dep.DependencyResolver;
+import org.apache.zeppelin.resource.DistributedResourcePool;
+import org.apache.zeppelin.resource.Resource;
+import org.apache.zeppelin.resource.ResourcePool;
+import org.apache.zeppelin.resource.ResourceSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+
+/**
+ * Load application
+ */
+public class ApplicationLoader {
+  Logger logger = LoggerFactory.getLogger(ApplicationLoader.class);
+
+  private final DependencyResolver depResolver;
+  private final ResourcePool resourcePool;
+  private final Map<HeliumPackage, Class<Application>> cached;
+
+  public ApplicationLoader(ResourcePool resourcePool, DependencyResolver depResolver) {
+    this.depResolver = depResolver;
+    this.resourcePool = resourcePool;
+    cached = Collections.synchronizedMap(
+        new HashMap<HeliumPackage, Class<Application>>());
+  }
+
+  /**
+   * Information of loaded application
+   */
+  private static class RunningApplication {
+    HeliumPackage packageInfo;
+    String noteId;
+    String paragraphId;
+
+    public RunningApplication(HeliumPackage packageInfo, String noteId, String paragraphId) {
+      this.packageInfo = packageInfo;
+      this.noteId = noteId;
+      this.paragraphId = paragraphId;
+    }
+
+    public HeliumPackage getPackageInfo() {
+      return packageInfo;
+    }
+
+    public String getNoteId() {
+      return noteId;
+    }
+
+    public String getParagraphId() {
+      return paragraphId;
+    }
+
+    @Override
+    public int hashCode() {
+      return (paragraphId + noteId + packageInfo.getArtifact() + packageInfo.getClassName())
+          .hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (!(o instanceof RunningApplication)) {
+        return false;
+      }
+
+      RunningApplication r = (RunningApplication) o;
+      return packageInfo.equals(r.getPackageInfo()) && paragraphId.equals(r.getParagraphId()) &&
+          noteId.equals(r.getNoteId());
+    }
+  }
+
+  /**
+   *
+   * Instantiate application
+   *
+   * @param packageInfo
+   * @param context
+   * @return
+   * @throws Exception
+   */
+  public Application load(HeliumPackage packageInfo, ApplicationContext context)
+      throws Exception {
+    if (packageInfo.getType() != HeliumPackage.Type.APPLICATION) {
+      throw new ApplicationException(
+          "Can't instantiate " + packageInfo.getType() + " package using ApplicationLoader");
+    }
+
+    // check if already loaded
+    RunningApplication key =
+        new RunningApplication(packageInfo, context.getNoteId(), context.getParagraphId());
+
+    // get resource required by this package
+    ResourceSet resources = findRequiredResourceSet(packageInfo.getResources(),
+        context.getNoteId(), context.getParagraphId());
+
+    // load class
+    Class<Application> appClass = loadClass(packageInfo);
+
+    // instantiate
+    ClassLoader oldcl = Thread.currentThread().getContextClassLoader();
+    ClassLoader cl = appClass.getClassLoader();
+    Thread.currentThread().setContextClassLoader(cl);
+    try {
+      Constructor<Application> constructor = appClass.getConstructor(ApplicationContext.class);
+
+      Application app = new ClassLoaderApplication(constructor.newInstance(context), cl);
+      return app;
+    } catch (Exception e) {
+      throw new ApplicationException(e);
+    } finally {
+      Thread.currentThread().setContextClassLoader(oldcl);
+    }
+  }
+
+  public ResourceSet findRequiredResourceSet(
+      String [][] requiredResources, String noteId, String paragraphId) {
+    if (requiredResources == null || requiredResources.length == 0) {
+      return new ResourceSet();
+    }
+
+    ResourceSet allResources;
+    if (resourcePool instanceof DistributedResourcePool) {
+      allResources = ((DistributedResourcePool) resourcePool).getAll(false);
+    } else {
+      allResources = resourcePool.getAll();
+    }
+
+    return findRequiredResourceSet(requiredResources, noteId, paragraphId, allResources);
+  }
+
+  static ResourceSet findRequiredResourceSet(String [][] requiredResources,
+                                             String noteId,
+                                             String paragraphId,
+                                             ResourceSet resources) {
+    ResourceSet args = new ResourceSet();
+    if (requiredResources == null || requiredResources.length == 0) {
+      return args;
+    }
+
+    resources = resources.filterByNoteId(noteId).filterByParagraphId(paragraphId);
+
+    for (String [] requires : requiredResources) {
+      args.clear();
+
+      for (String require : requires) {
+        boolean found = false;
+
+        for (Resource r : resources) {
+          if (require.startsWith(":") && r.getClassName().equals(require.substring(1))) {
+            found = true;
+          } else if (r.getResourceId().getName().equals(require)) {
+            found = true;
+          }
+
+          if (found) {
+            args.add(r);
+            break;
+          }
+        }
+
+        if (found == false) {
+          break;
+        }
+      }
+
+      if (args.size() == requires.length) {
+        return args;
+      }
+    }
+
+    return null;
+  }
+
+
+  private Class<Application> loadClass(HeliumPackage packageInfo) throws Exception {
+    if (cached.containsKey(packageInfo)) {
+      return cached.get(packageInfo);
+    }
+
+    // Create Application classloader
+    List<URL> urlList = new LinkedList<URL>();
+
+    // load artifact
+    if (packageInfo.getArtifact() != null) {
+      List<File> paths = depResolver.load(packageInfo.getArtifact());
+
+      if (paths != null) {
+
+        for (File path : paths) {
+          urlList.add(path.toURI().toURL());
+        }
+      }
+    }
+    URLClassLoader applicationClassLoader =
+        new URLClassLoader(
+            urlList.toArray(new URL[]{}),
+            Thread.currentThread().getContextClassLoader());
+
+    Class<Application> cls =
+        (Class<Application>) applicationClassLoader.loadClass(packageInfo.getClassName());
+    cached.put(packageInfo, cls);
+    return cls;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ClassLoaderApplication.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ClassLoaderApplication.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ClassLoaderApplication.java
new file mode 100644
index 0000000..272a152
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/ClassLoaderApplication.java
@@ -0,0 +1,72 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.resource.ResourceSet;
+
+/**
+ * Application wrapper
+ */
+public class ClassLoaderApplication extends Application {
+  Application app;
+  ClassLoader cl;
+  public ClassLoaderApplication(Application app, ClassLoader cl) throws ApplicationException {
+    super(app.context());
+    this.app = app;
+    this.cl = cl;
+  }
+
+  @Override
+  public void run(ResourceSet args) throws ApplicationException {
+    // instantiate
+    ClassLoader oldcl = Thread.currentThread().getContextClassLoader();
+    Thread.currentThread().setContextClassLoader(cl);
+    try {
+      app.run(args);
+    } catch (ApplicationException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new ApplicationException(e);
+    } finally {
+      Thread.currentThread().setContextClassLoader(oldcl);
+    }
+  }
+
+  @Override
+  public void unload() throws ApplicationException {
+    // instantiate
+    ClassLoader oldcl = Thread.currentThread().getContextClassLoader();
+    Thread.currentThread().setContextClassLoader(cl);
+    try {
+      app.unload();
+    } catch (ApplicationException e) {
+      throw e;
+    } catch (Exception e) {
+      throw new ApplicationException(e);
+    } finally {
+      Thread.currentThread().setContextClassLoader(oldcl);
+    }
+  }
+
+  public ClassLoader getClassLoader() {
+    return cl;
+  }
+
+  public Application getInnerApplication() {
+    return app;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumAppAngularObjectRegistry.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumAppAngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumAppAngularObjectRegistry.java
new file mode 100644
index 0000000..dedb603
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumAppAngularObjectRegistry.java
@@ -0,0 +1,55 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.display.AngularObject;
+import org.apache.zeppelin.display.AngularObjectRegistry;
+
+import java.util.List;
+
+/**
+ * Angular Registry for helium app
+ */
+public class HeliumAppAngularObjectRegistry {
+  private final String noteId;
+  private final String appId;
+  private final AngularObjectRegistry angularObjectRegistry;
+
+  public HeliumAppAngularObjectRegistry(AngularObjectRegistry angularObjectRegistry,
+                                        String noteId,
+                                        String appId) {
+    this.angularObjectRegistry = angularObjectRegistry;
+    this.noteId = noteId;
+    this.appId = appId;
+  }
+
+  public AngularObject add(String name, Object o) {
+    return angularObjectRegistry.add(name, o, noteId, appId);
+  }
+
+  public AngularObject remove(String name) {
+    return angularObjectRegistry.remove(name, noteId, appId);
+  }
+
+  public AngularObject get(String name) {
+    return angularObjectRegistry.get(name, noteId, appId);
+  }
+
+  public List<AngularObject> getAll() {
+    return angularObjectRegistry.getAll(noteId, appId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumPackage.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumPackage.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumPackage.java
new file mode 100644
index 0000000..1352642
--- /dev/null
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/helium/HeliumPackage.java
@@ -0,0 +1,99 @@
+/*
+ * 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.zeppelin.helium;
+
+import org.apache.zeppelin.annotation.Experimental;
+
+/**
+ * Helium package definition
+ */
+@Experimental
+public class HeliumPackage {
+  private Type type;
+  private String name;           // user friendly name of this application
+  private String description;    // description
+  private String artifact;       // artifact name e.g) groupId:artifactId:versionId
+  private String className;      // entry point
+  private String [][] resources; // resource classnames that requires
+                                 // [[ .. and .. and .. ] or [ .. and .. and ..] ..]
+  private String icon;
+  /**
+   * Type of package
+   */
+  public static enum Type {
+    INTERPRETER,
+    NOTEBOOK_REPO,
+    APPLICATION
+  }
+
+  public HeliumPackage(Type type,
+                       String name,
+                       String description,
+                       String artifact,
+                       String className,
+                       String[][] resources) {
+    this.type = type;
+    this.name = name;
+    this.description = description;
+    this.artifact = artifact;
+    this.className = className;
+    this.resources = resources;
+  }
+
+  @Override
+  public int hashCode() {
+    return (type.toString() + artifact + className).hashCode();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof HeliumPackage)) {
+      return false;
+    }
+
+    HeliumPackage info = (HeliumPackage) o;
+    return type == info.type && artifact.equals(info.artifact) && className.equals(info.className);
+  }
+
+  public Type getType() {
+    return type;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public String getArtifact() {
+    return artifact;
+  }
+
+  public String getClassName() {
+    return className;
+  }
+
+  public String[][] getResources() {
+    return resources;
+  }
+
+  public String getIcon() {
+    return icon;
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/9463fb85/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java
index b5d5863..bc56784 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java
@@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.log4j.Logger;
 import org.apache.zeppelin.display.AngularObjectRegistry;
 import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess;
-import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService;
 import org.apache.zeppelin.resource.ResourcePool;
 import org.apache.zeppelin.scheduler.Scheduler;
 import org.apache.zeppelin.scheduler.SchedulerFactory;


Mime
View raw message