You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@eagle.apache.org by ha...@apache.org on 2016/09/13 12:18:48 UTC

[2/2] incubator-eagle git commit: [EAGLE-536] Support application dependency

[EAGLE-536] Support application dependency

# Changes
* Support to declare dependency descriptor and validation
* Support to export executable flag in REST API for front-end to aware whether an application can be START/STOP/STATUS or not.
* Add dependency checking logic while installing application , if required dependency is not installed, throw exception back, so that front-end can simply treat an ApplicationPackage consist of a set of Applications as a normal application.

# Use Case
JPM Application has some back-end application like MR history/running, Spark history/running, while has single Web App, so user could simply understand the application JPM as following, where right-side is tech view and left-side is product view:

~~~
JPM = JPM WEB {
    dependencies = [MR history/running, Spark history/running]
}
~~~

Author: Hao Chen <ha...@apache.org>

Closes #435 from haoch/EAGLE-536.


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

Branch: refs/heads/master
Commit: 83bd4e3d7c538052bb1f3048dfad4ad1f05a7738
Parents: 2c30276
Author: Hao Chen <ha...@apache.org>
Authored: Tue Sep 13 20:18:26 2016 +0800
Committer: Hao Chen <ha...@apache.org>
Committed: Tue Sep 13 20:18:26 2016 +0800

----------------------------------------------------------------------
 .../engine/coordinator/StreamDefinition.java    |   4 +-
 .../apache/eagle/app/AbstractApplication.java   |  28 ----
 .../java/org/apache/eagle/app/Application.java  |   2 +
 .../apache/eagle/app/ExecutableApplication.java |  33 ++++
 .../apache/eagle/app/StaticWebApplication.java  |  60 ++++++++
 .../eagle/app/StaticWebApplicationProvider.java |  34 +++++
 .../org/apache/eagle/app/StormApplication.java  |   2 +-
 .../app/config/ApplicationProviderConfig.java   |   2 +-
 .../config/ApplicationProviderDescConfig.java   |  50 +++---
 .../app/environment/AbstractEnvironment.java    |   2 +-
 .../eagle/app/environment/Environment.java      |   6 +
 .../environment/ExecutionRuntimeManager.java    |   6 +-
 .../app/environment/impl/WebEnvironment.java    |  39 +++++
 .../environment/impl/WebExecutionContainer.java |  34 +++++
 .../environment/impl/WebExecutionRuntime.java   |  66 ++++++++
 .../java/org/apache/eagle/app/package-info.java |   2 +-
 .../eagle/app/service/ApplicationContext.java   | 149 ------------------
 .../service/ApplicationOperationContext.java    | 153 +++++++++++++++++++
 .../app/service/ApplicationProviderLoader.java  |   2 +-
 .../impl/ApplicationManagementServiceImpl.java  |  74 +++++----
 .../impl/ApplicationProviderConfigLoader.java   |   4 +
 .../impl/ApplicationProviderSPILoader.java      |   3 +
 .../impl/ApplicationProviderServiceImpl.java    |  53 ++++++-
 .../app/spi/AbstractApplicationProvider.java    |  54 +------
 .../eagle/app/spi/ApplicationDescLoader.java    |  27 ++++
 .../eagle/app/spi/ApplicationProvider.java      |  37 ++++-
 .../app/spi/ApplicationXMLDescriptorLoader.java |  69 +++++++++
 .../app/ApplicationProviderDescConfigTest.java  |  30 ++--
 .../app/ApplicationProviderServiceTest.java     |  28 ++--
 .../apache/eagle/app/TestStormApplication.java  |   2 +-
 .../apache/eagle/app/TestWebApplication.java    |  27 ++++
 .../app/service/ApplicationContextTest.java     |  48 ------
 .../ApplicationOperationContextTest.java        |  48 ++++++
 ....eagle.app.TestStormApplication$Provider.xml |   1 -
 ...he.eagle.app.TestWebApplication$Provider.xml |  30 ++++
 ...org.apache.eagle.app.spi.ApplicationProvider |   3 +-
 .../eagle-embed/eagle-embed-hbase/pom.xml       |   4 -
 .../metadata/model/ApplicationDependency.java   |  56 +++++++
 .../eagle/metadata/model/ApplicationDesc.java   |  14 +-
 .../eagle/metadata/model/ApplicationEntity.java |  19 ++-
 .../ApplicationEntityServiceMemoryImpl.java     |  42 ++---
 .../example/ExampleApplicationProviderTest.java |  36 +++--
 eagle-jpm/eagle-jpm-app/pom.xml                 |  46 ------
 .../apache/eagle/app/jpm/JPMApplication.java    |  64 --------
 .../eagle/app/jpm/JPMApplicationProvider.java   |  29 ----
 ...che.eagle.app.jpm.JPMApplicationProvider.xml | 109 -------------
 ...org.apache.eagle.app.spi.ApplicationProvider |  16 --
 .../src/main/webapp/app/apps/jpm/index.html     |   6 -
 .../eagle-jpm-app/src/main/webapp/package.json  |   0
 .../eagle/app/jpm/JPMApplicationTest.java       |  86 -----------
 ....history.MRHistoryJobApplicationProvider.xml |   4 +-
 eagle-jpm/eagle-jpm-web/pom.xml                 |  59 +++++++
 .../app/jpm/JPMWebApplicationProvider.java      |  23 +++
 ....eagle.app.jpm.JPMWebApplicationProvider.xml |  43 ++++++
 ...org.apache.eagle.app.spi.ApplicationProvider |  16 ++
 .../src/main/webapp/app/apps/jpm/index.html     |   6 +
 .../eagle-jpm-web/src/main/webapp/package.json  |   0
 .../eagle/app/jpm/JPMWebApplicationTest.java    | 102 +++++++++++++
 eagle-jpm/pom.xml                               |   2 +-
 ...ecurity.auditlog.HdfsAuditLogAppProvider.xml |   1 -
 eagle-server/pom.xml                            |  91 +++++++----
 ...org.apache.eagle.app.spi.ApplicationProvider |   2 +-
 62 files changed, 1276 insertions(+), 812 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-alert-parent/eagle-alert/alert-common/src/main/java/org/apache/eagle/alert/engine/coordinator/StreamDefinition.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-alert-parent/eagle-alert/alert-common/src/main/java/org/apache/eagle/alert/engine/coordinator/StreamDefinition.java b/eagle-core/eagle-alert-parent/eagle-alert/alert-common/src/main/java/org/apache/eagle/alert/engine/coordinator/StreamDefinition.java
index 9130951..a23c963 100644
--- a/eagle-core/eagle-alert-parent/eagle-alert/alert-common/src/main/java/org/apache/eagle/alert/engine/coordinator/StreamDefinition.java
+++ b/eagle-core/eagle-alert-parent/eagle-alert/alert-common/src/main/java/org/apache/eagle/alert/engine/coordinator/StreamDefinition.java
@@ -16,11 +16,11 @@
  */
 package org.apache.eagle.alert.engine.coordinator;
 
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
 
 /**
  * This is actually a data source schema.

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/AbstractApplication.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/AbstractApplication.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/AbstractApplication.java
deleted file mode 100644
index 8943df3..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/AbstractApplication.java
+++ /dev/null
@@ -1,28 +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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.eagle.app;
-
-import org.apache.eagle.app.environment.Environment;
-import org.apache.eagle.app.environment.ExecutionRuntimeManager;
-import com.typesafe.config.Config;
-
-public abstract class AbstractApplication<E extends Environment, P> implements Application<E, P>, ApplicationTool {
-    @Override
-    public void run(Config config) {
-        ExecutionRuntimeManager.getInstance().getRuntime(getEnvironmentType(), config).start(this, config);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/Application.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/Application.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/Application.java
index 84398b1..d76e468 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/Application.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/Application.java
@@ -52,4 +52,6 @@ public interface Application<
      * @return application environment type
      */
     Class<? extends E> getEnvironmentType();
+
+    boolean isExecutable();
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ExecutableApplication.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ExecutableApplication.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ExecutableApplication.java
new file mode 100644
index 0000000..6463d47
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ExecutableApplication.java
@@ -0,0 +1,33 @@
+/*
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.eagle.app;
+
+import org.apache.eagle.app.environment.Environment;
+import org.apache.eagle.app.environment.ExecutionRuntimeManager;
+import com.typesafe.config.Config;
+
+public abstract class ExecutableApplication<E extends Environment, P> implements Application<E, P>, ApplicationTool {
+    @Override
+    public void run(Config config) {
+        ExecutionRuntimeManager.getInstance().getRuntime(getEnvironmentType(), config).start(this, config);
+    }
+
+    @Override
+    public boolean isExecutable() {
+        return true;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplication.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplication.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplication.java
new file mode 100644
index 0000000..fae9393
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplication.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app;
+
+import com.typesafe.config.Config;
+import org.apache.eagle.app.environment.impl.WebExecutionContainer;
+import org.apache.eagle.app.environment.impl.WebEnvironment;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Static Web Application without executable process.
+ */
+public class StaticWebApplication implements Application<WebEnvironment, WebExecutionContainer> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(StaticWebApplication.class);
+    private final String webViewPath;
+
+    public StaticWebApplication(String webViewPath) {
+        this.webViewPath = webViewPath;
+    }
+
+    @Override
+    public WebExecutionContainer execute(Config config, WebEnvironment environment) {
+        LOGGER.warn("Executing web application");
+        return new WebExecutionContainer(this);
+    }
+
+    @Override
+    public Class<? extends WebEnvironment> getEnvironmentType() {
+        return WebEnvironment.class;
+    }
+
+    @Override
+    public boolean isExecutable() {
+        return false;
+    }
+
+    public String getWebViewPath() {
+        return webViewPath;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("StaticWebApplication(%s)",this.getWebViewPath());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplicationProvider.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplicationProvider.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplicationProvider.java
new file mode 100644
index 0000000..12d8f4e
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StaticWebApplicationProvider.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app;
+
+import org.apache.eagle.app.spi.AbstractApplicationProvider;
+
+/**
+ * Static Web Application Provider.
+ */
+public abstract class StaticWebApplicationProvider extends AbstractApplicationProvider<StaticWebApplication> {
+    @Override
+    public StaticWebApplication getApplication() {
+        return new StaticWebApplication(this.getApplicationDesc().getViewPath());
+    }
+
+    @Override
+    public final Class<StaticWebApplication> getApplicationClass() {
+        return StaticWebApplication.class;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StormApplication.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StormApplication.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StormApplication.java
index 7e70cde..05fc512 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StormApplication.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/StormApplication.java
@@ -19,7 +19,7 @@ package org.apache.eagle.app;
 import org.apache.eagle.app.environment.impl.StormEnvironment;
 import backtype.storm.generated.StormTopology;
 
-public abstract class StormApplication extends AbstractApplication<StormEnvironment, StormTopology> {
+public abstract class StormApplication extends ExecutableApplication<StormEnvironment, StormTopology> {
     @Override
     public Class<? extends StormEnvironment> getEnvironmentType() {
         return StormEnvironment.class;

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderConfig.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderConfig.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderConfig.java
index b787885..16438a0 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderConfig.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderConfig.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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.

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderDescConfig.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderDescConfig.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderDescConfig.java
index 7f0dbb0..2d2b7e2 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderDescConfig.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/config/ApplicationProviderDescConfig.java
@@ -16,27 +16,38 @@
  */
 package org.apache.eagle.app.config;
 
-
 import org.apache.eagle.alert.engine.coordinator.StreamDefinition;
+import org.apache.eagle.metadata.model.ApplicationDependency;
 import org.apache.eagle.metadata.model.ApplicationDocs;
 import org.apache.eagle.metadata.model.Configuration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.InputStream;
-import java.util.List;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.*;
+import java.io.InputStream;
+import java.util.List;
 
+/**
+ * Application Metadata Descriptor Unmarshalling POJO.
+ *
+ * @see org.apache.eagle.app.spi.ApplicationProvider
+ */
 @XmlRootElement(name = "application")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class ApplicationProviderDescConfig {
+
+    @XmlElement(required = true)
     private String type;
+
+    @XmlElement(required = true)
     private String name;
+
+    @XmlElement(required = true)
     private String version;
+
     private String description;
-    private String appClass;
     private String viewPath;
     private Configuration configuration;
     private ApplicationDocs docs;
@@ -45,6 +56,10 @@ public class ApplicationProviderDescConfig {
     @XmlElement(name = "stream")
     private List<StreamDefinition> streams;
 
+    @XmlElementWrapper(name = "dependencies")
+    @XmlElement(name = "dependency")
+    private List<ApplicationDependency> dependencies;
+
     public String getDescription() {
         return description;
     }
@@ -91,8 +106,9 @@ public class ApplicationProviderDescConfig {
 
     @Override
     public String toString() {
-        return String.format("ApplicationDesc [type=%s, name=%s, version=%s, appClass=%s, viewPath=%s, configuration= %s properties, description=%s",
-            getType(), getName(), getVersion(), getAppClass(), getViewPath(), getConfiguration() == null ? 0 : getConfiguration().size(), getDescription());
+        return String.format("ApplicationDesc [type=%s, name=%s, version=%s, viewPath=%s, configuration= %s properties, description=%s",
+            getType(), getName(), getVersion(), getViewPath(),
+            getConfiguration() == null ? 0 : getConfiguration().size(), getDescription());
     }
 
     public void setConfiguration(Configuration configuration) {
@@ -121,23 +137,15 @@ public class ApplicationProviderDescConfig {
             }
             if (is == null) {
                 LOG.error("Application descriptor configuration {} is not found", configXmlFile);
-                throw new IllegalStateException("Application descriptor configuration " + configXmlFile + " is not found");
+                throw new IllegalStateException("Application descriptor " + configXmlFile + " is not found");
             }
             return (ApplicationProviderDescConfig) unmarshaller.unmarshal(is);
         } catch (Exception ex) {
-            LOG.error("Failed to load application descriptor configuration: {}", configXmlFile, ex);
-            throw new RuntimeException("Failed to load application descriptor configuration: " + configXmlFile, ex);
+            LOG.error("Failed to load application descriptor: {}", configXmlFile, ex);
+            throw new IllegalStateException("Failed to load application descriptor: " + configXmlFile, ex);
         }
     }
 
-    public String getAppClass() {
-        return appClass;
-    }
-
-    public void setAppClass(String appClass) {
-        this.appClass = appClass;
-    }
-
     public ApplicationDocs getDocs() {
         return docs;
     }
@@ -145,4 +153,12 @@ public class ApplicationProviderDescConfig {
     public void setDocs(ApplicationDocs docs) {
         this.docs = docs;
     }
+
+    public List<ApplicationDependency> getDependencies() {
+        return dependencies;
+    }
+
+    public void setDependencies(List<ApplicationDependency> dependencies) {
+        this.dependencies = dependencies;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/AbstractEnvironment.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/AbstractEnvironment.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/AbstractEnvironment.java
index 45de7b9..02c130a 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/AbstractEnvironment.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/AbstractEnvironment.java
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public abstract class AbstractEnvironment implements Environment {
+
     private final Config config;
     private final StreamSinkProvider sinkProvider;
     private static final String APPLICATIONS_SINK_TYPE_PROPS_KEY = "application.sink.provider";
@@ -59,7 +60,6 @@ public abstract class AbstractEnvironment implements Environment {
             .append(this.config()).build();
     }
 
-    @Override
     public StreamSinkProvider streamSink() {
         return sinkProvider;
     }

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/Environment.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/Environment.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/Environment.java
index 9569c5f..29e90d9 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/Environment.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/Environment.java
@@ -25,7 +25,13 @@ import java.io.Serializable;
  * Execution Environment Context.
  */
 public interface Environment extends Serializable {
+
     Config config();
 
+    /**
+     * TODO Only useful for Storm/Spark Exeuctable Application instead of static web application.
+     *
+     * @return StreamSinkProvider.
+     */
     StreamSinkProvider streamSink();
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/ExecutionRuntimeManager.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/ExecutionRuntimeManager.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/ExecutionRuntimeManager.java
index fc1e632..96f171e 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/ExecutionRuntimeManager.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/ExecutionRuntimeManager.java
@@ -16,10 +16,7 @@
  */
 package org.apache.eagle.app.environment;
 
-import org.apache.eagle.app.environment.impl.SparkEnvironment;
-import org.apache.eagle.app.environment.impl.SparkExecutionRuntime;
-import org.apache.eagle.app.environment.impl.StormEnvironment;
-import org.apache.eagle.app.environment.impl.StormExecutionRuntime;
+import org.apache.eagle.app.environment.impl.*;
 import com.google.common.base.Preconditions;
 import com.typesafe.config.Config;
 import org.slf4j.Logger;
@@ -42,6 +39,7 @@ public class ExecutionRuntimeManager {
     static {
         getInstance().register(StormEnvironment.class, new StormExecutionRuntime.Provider());
         getInstance().register(SparkEnvironment.class, new SparkExecutionRuntime.Provider());
+        getInstance().register(WebEnvironment.class, new WebExecutionRuntime.Provider());
     }
 
     private final Map<Class<? extends Environment>, ExecutionRuntimeProvider> executionRuntimeProviders;

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebEnvironment.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebEnvironment.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebEnvironment.java
new file mode 100644
index 0000000..2bb8dc7
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebEnvironment.java
@@ -0,0 +1,39 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app.environment.impl;
+
+import com.typesafe.config.Config;
+import org.apache.eagle.app.environment.Environment;
+import org.apache.eagle.app.sink.StreamSinkProvider;
+
+public class WebEnvironment implements Environment {
+    private final Config config;
+
+    public WebEnvironment(Config config) {
+        this.config = config;
+    }
+
+    @Override
+    public Config config() {
+        return this.config;
+    }
+
+    @Override
+    public StreamSinkProvider streamSink() {
+        throw new IllegalStateException("streamSink() is not supported in " + WebEnvironment.class.getSimpleName());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionContainer.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionContainer.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionContainer.java
new file mode 100644
index 0000000..6ca7128
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionContainer.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app.environment.impl;
+
+import org.apache.eagle.app.StaticWebApplication;
+
+/**
+ * Web Application Container.
+ */
+public class WebExecutionContainer {
+    private final StaticWebApplication webApplication;
+
+    public WebExecutionContainer(StaticWebApplication webApplication) {
+        this.webApplication = webApplication;
+    }
+
+    public StaticWebApplication getWebApplication() {
+        return webApplication;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionRuntime.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionRuntime.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionRuntime.java
new file mode 100644
index 0000000..f8eecef
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/environment/impl/WebExecutionRuntime.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app.environment.impl;
+
+import com.typesafe.config.Config;
+import org.apache.eagle.app.Application;
+import org.apache.eagle.app.environment.ExecutionRuntime;
+import org.apache.eagle.app.environment.ExecutionRuntimeProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * WebExecutionRuntime.
+ */
+public class WebExecutionRuntime implements ExecutionRuntime<WebEnvironment,WebExecutionContainer> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(WebExecutionRuntime.class);
+
+    private WebEnvironment environment;
+
+    @Override
+    public void prepare(WebEnvironment environment) {
+        this.environment = environment;
+    }
+
+    @Override
+    public WebEnvironment environment() {
+        return this.environment;
+    }
+
+    @Override
+    public void start(Application<WebEnvironment, WebExecutionContainer> executor, Config config) {
+        LOGGER.warn("Starting {}, do nothing",executor);
+    }
+
+    @Override
+    public void stop(Application<WebEnvironment, WebExecutionContainer> executor, Config config) {
+        LOGGER.warn("Stopping {}, do nothing",executor);
+    }
+
+    @Override
+    public void status(Application<WebEnvironment, WebExecutionContainer> executor, Config config) {
+        LOGGER.warn("Checking status {}, do nothing",executor);
+    }
+
+    public static class Provider implements ExecutionRuntimeProvider<WebEnvironment,WebExecutionContainer> {
+        @Override
+        public ExecutionRuntime<WebEnvironment, WebExecutionContainer> get() {
+            return new WebExecutionRuntime();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java
index 13cf0c9..b91a70c 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java
@@ -20,7 +20,7 @@
  * <h1>Application Management Framework Interfaces</h1>
  *
  * <ul>
- *     <li>Application Context (Runtime): org.apache.eagle.app.service.ApplicationContext</li>
+ *     <li>Application Context (Runtime): org.apache.eagle.app.service.ApplicationOperationContext</li>
  *     <li>Application Metadata Entity (Persistence): org.apache.eagle.metadata.model.ApplicationEntity</li>
  *     <li>Application Processing Logic (Execution): org.apache.eagle.app.Application</li>
  *     <li>Application Lifecycle Listener (Callback): org.apache.eagle.app.ApplicationLifecycle</li>

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationContext.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationContext.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationContext.java
deleted file mode 100644
index f7f895e..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationContext.java
+++ /dev/null
@@ -1,149 +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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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.eagle.app.service;
-
-import org.apache.eagle.alert.coordination.model.Kafka2TupleMetadata;
-import org.apache.eagle.alert.coordination.model.Tuple2StreamMetadata;
-import org.apache.eagle.alert.engine.coordinator.StreamDefinition;
-import org.apache.eagle.alert.engine.scheme.JsonScheme;
-import org.apache.eagle.alert.engine.scheme.JsonStringStreamNameSelector;
-import org.apache.eagle.alert.metadata.IMetadataDao;
-import org.apache.eagle.app.Application;
-import org.apache.eagle.app.ApplicationLifecycle;
-import org.apache.eagle.app.environment.ExecutionRuntime;
-import org.apache.eagle.app.environment.ExecutionRuntimeManager;
-import org.apache.eagle.app.sink.KafkaStreamSinkConfig;
-import org.apache.eagle.metadata.model.ApplicationEntity;
-import org.apache.eagle.metadata.model.StreamDesc;
-import org.apache.eagle.metadata.model.StreamSinkConfig;
-import com.google.common.base.Preconditions;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.stream.Collectors;
-
-/**
- * Managed Application Interface: org.apache.eagle.app.service.ApplicationContext
- * <ul>
- * <li>Application Metadata Entity (Persistence): org.apache.eagle.metadata.model.ApplicationEntity</li>
- * <li>Application Processing Logic (Execution): org.apache.eagle.app.Application</li>
- * <li>Application Lifecycle Listener (Installation): org.apache.eagle.app.ApplicationLifecycle</li>
- * </ul>
- */
-public class ApplicationContext implements Serializable, ApplicationLifecycle {
-    private final Config config;
-    private final Application application;
-    private final ExecutionRuntime runtime;
-    private final ApplicationEntity metadata;
-    private final IMetadataDao alertMetadataService;
-
-    /**
-     * @param metadata    ApplicationEntity.
-     * @param application Application.
-     */
-    public ApplicationContext(Application application, ApplicationEntity metadata, Config envConfig, IMetadataDao alertMetadataService) {
-        Preconditions.checkNotNull(application, "Application is null");
-        Preconditions.checkNotNull(metadata, "ApplicationEntity is null");
-        this.application = application;
-        this.metadata = metadata;
-        this.runtime = ExecutionRuntimeManager.getInstance().getRuntime(application.getEnvironmentType(), envConfig);
-        Map<String, Object> executionConfig = metadata.getConfiguration();
-        if (executionConfig == null) {
-            executionConfig = Collections.emptyMap();
-        }
-
-        // TODO: Decouple hardcoded configuration key
-        executionConfig.put("siteId", metadata.getSite().getSiteId());
-        executionConfig.put("mode", metadata.getMode().name());
-        executionConfig.put("appId", metadata.getAppId());
-        executionConfig.put("jarPath", metadata.getJarPath());
-        this.config = ConfigFactory.parseMap(executionConfig).withFallback(envConfig);
-        this.alertMetadataService = alertMetadataService;
-    }
-
-    @Override
-    public void onInstall() {
-        if (metadata.getDescriptor().getStreams() != null) {
-            List<StreamDesc> streamDescCollection = metadata.getDescriptor().getStreams().stream().map((streamDefinition -> {
-                StreamSinkConfig streamSinkConfig = this.runtime.environment().streamSink().getSinkConfig(streamDefinition.getStreamId(), this.config);
-                StreamDesc streamDesc = new StreamDesc();
-                streamDesc.setSchema(streamDefinition);
-                streamDesc.setSink(streamSinkConfig);
-                streamDesc.setStreamId(streamDefinition.getStreamId());
-                return streamDesc;
-            })).collect(Collectors.toList());
-            metadata.setStreams(streamDescCollection);
-
-            // iterate each stream descriptor and create alert datasource for each
-            for (StreamDesc streamDesc : streamDescCollection) {
-                // only take care of Kafka sink
-                if (streamDesc.getSink() instanceof KafkaStreamSinkConfig) {
-                    KafkaStreamSinkConfig kafkaCfg = (KafkaStreamSinkConfig) streamDesc.getSink();
-                    Kafka2TupleMetadata datasource = new Kafka2TupleMetadata();
-                    datasource.setType("KAFKA");
-                    datasource.setName(metadata.getAppId());
-                    datasource.setTopic(kafkaCfg.getTopicId());
-                    datasource.setSchemeCls(JsonScheme.class.getCanonicalName());
-                    Tuple2StreamMetadata tuple2Stream = new Tuple2StreamMetadata();
-                    Properties prop = new Properties();
-                    prop.put(JsonStringStreamNameSelector.USER_PROVIDED_STREAM_NAME_PROPERTY, streamDesc.getStreamId());
-                    tuple2Stream.setStreamNameSelectorProp(prop);
-                    tuple2Stream.setTimestampColumn("timestamp");
-                    tuple2Stream.setStreamNameSelectorCls(JsonStringStreamNameSelector.class.getCanonicalName());
-                    datasource.setCodec(tuple2Stream);
-                    alertMetadataService.addDataSource(datasource);
-
-                    StreamDefinition sd = streamDesc.getSchema();
-                    sd.setDataSource(metadata.getAppId());
-                    alertMetadataService.createStream(streamDesc.getSchema());
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onUninstall() {
-        // we should remove alert data source and stream definition while we do uninstall
-        if (metadata.getStreams() == null) {
-            return;
-        }
-        // iterate each stream descriptor and create alert datasource for each
-        for (StreamDesc streamDesc : metadata.getStreams()) {
-            alertMetadataService.removeDataSource(metadata.getAppId());
-            alertMetadataService.removeStream(streamDesc.getStreamId());
-        }
-    }
-
-    @Override
-    public void onStart() {
-        this.runtime.start(this.application, this.config);
-    }
-
-    @Override
-    public void onStop() {
-        this.runtime.stop(this.application, this.config);
-    }
-
-    public ApplicationEntity getMetadata() {
-        return metadata;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperationContext.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperationContext.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperationContext.java
new file mode 100644
index 0000000..82ca659
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperationContext.java
@@ -0,0 +1,153 @@
+/*
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.eagle.app.service;
+
+import org.apache.eagle.alert.coordination.model.Kafka2TupleMetadata;
+import org.apache.eagle.alert.coordination.model.Tuple2StreamMetadata;
+import org.apache.eagle.alert.engine.coordinator.StreamDefinition;
+import org.apache.eagle.alert.engine.scheme.JsonScheme;
+import org.apache.eagle.alert.engine.scheme.JsonStringStreamNameSelector;
+import org.apache.eagle.alert.metadata.IMetadataDao;
+import org.apache.eagle.app.Application;
+import org.apache.eagle.app.ApplicationLifecycle;
+import org.apache.eagle.app.StaticWebApplication;
+import org.apache.eagle.app.environment.ExecutionRuntime;
+import org.apache.eagle.app.environment.ExecutionRuntimeManager;
+import org.apache.eagle.app.sink.KafkaStreamSinkConfig;
+import org.apache.eagle.metadata.model.ApplicationEntity;
+import org.apache.eagle.metadata.model.StreamDesc;
+import org.apache.eagle.metadata.model.StreamSinkConfig;
+import com.google.common.base.Preconditions;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+/**
+ * Managed Application Interface: org.apache.eagle.app.service.ApplicationOperationContext
+ * <ul>
+ * <li>Application Metadata Entity (Persistence): org.apache.eagle.metadata.model.ApplicationEntity</li>
+ * <li>Application Processing Logic (Execution): org.apache.eagle.app.Application</li>
+ * <li>Application Lifecycle Listener (Installation): org.apache.eagle.app.ApplicationLifecycle</li>
+ * </ul>
+ */
+public class ApplicationOperationContext implements Serializable, ApplicationLifecycle {
+    private final Config config;
+    private final Application application;
+    private final ExecutionRuntime runtime;
+    private final ApplicationEntity metadata;
+    private final IMetadataDao alertMetadataService;
+
+    /**
+     * @param metadata    ApplicationEntity.
+     * @param application Application.
+     */
+    public ApplicationOperationContext(Application application, ApplicationEntity metadata, Config envConfig, IMetadataDao alertMetadataService) {
+        Preconditions.checkNotNull(application, "Application is null");
+        Preconditions.checkNotNull(metadata, "ApplicationEntity is null");
+        this.application = application;
+        this.metadata = metadata;
+        this.runtime = ExecutionRuntimeManager.getInstance().getRuntime(application.getEnvironmentType(), envConfig);
+        Map<String, Object> executionConfig = metadata.getConfiguration();
+        if (executionConfig == null) {
+            executionConfig = Collections.emptyMap();
+        }
+
+        // TODO: Decouple hardcoded configuration key
+        executionConfig.put("siteId", metadata.getSite().getSiteId());
+        executionConfig.put("mode", metadata.getMode().name());
+        executionConfig.put("appId", metadata.getAppId());
+        executionConfig.put("jarPath", metadata.getJarPath());
+        this.config = ConfigFactory.parseMap(executionConfig).withFallback(envConfig);
+        this.alertMetadataService = alertMetadataService;
+    }
+
+    @Override
+    public void onInstall() {
+        metadata.setExecutable(application.isExecutable());
+        if (metadata.getDescriptor().getStreams() != null) {
+            List<StreamDesc> streamDescCollection = metadata.getDescriptor().getStreams().stream().map((streamDefinition -> {
+                StreamSinkConfig streamSinkConfig = this.runtime.environment().streamSink().getSinkConfig(streamDefinition.getStreamId(), this.config);
+                StreamDesc streamDesc = new StreamDesc();
+                streamDesc.setSchema(streamDefinition);
+                streamDesc.setSink(streamSinkConfig);
+                streamDesc.setStreamId(streamDefinition.getStreamId());
+                return streamDesc;
+            })).collect(Collectors.toList());
+            metadata.setStreams(streamDescCollection);
+
+            // iterate each stream descriptor and create alert datasource for each
+            for (StreamDesc streamDesc : streamDescCollection) {
+                // only take care of Kafka sink
+                if (streamDesc.getSink() instanceof KafkaStreamSinkConfig) {
+                    KafkaStreamSinkConfig kafkaCfg = (KafkaStreamSinkConfig) streamDesc.getSink();
+                    Kafka2TupleMetadata datasource = new Kafka2TupleMetadata();
+                    datasource.setType("KAFKA");
+                    datasource.setName(metadata.getAppId());
+                    datasource.setTopic(kafkaCfg.getTopicId());
+                    datasource.setSchemeCls(JsonScheme.class.getCanonicalName());
+                    Tuple2StreamMetadata tuple2Stream = new Tuple2StreamMetadata();
+                    Properties prop = new Properties();
+                    prop.put(JsonStringStreamNameSelector.USER_PROVIDED_STREAM_NAME_PROPERTY, streamDesc.getStreamId());
+                    tuple2Stream.setStreamNameSelectorProp(prop);
+                    tuple2Stream.setTimestampColumn("timestamp");
+                    tuple2Stream.setStreamNameSelectorCls(JsonStringStreamNameSelector.class.getCanonicalName());
+                    datasource.setCodec(tuple2Stream);
+                    alertMetadataService.addDataSource(datasource);
+
+                    StreamDefinition sd = streamDesc.getSchema();
+                    sd.setDataSource(metadata.getAppId());
+                    alertMetadataService.createStream(streamDesc.getSchema());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onUninstall() {
+        // we should remove alert data source and stream definition while we do uninstall
+        if (metadata.getStreams() == null) {
+            return;
+        }
+        // iterate each stream descriptor and create alert datasource for each
+        for (StreamDesc streamDesc : metadata.getStreams()) {
+            alertMetadataService.removeDataSource(metadata.getAppId());
+            alertMetadataService.removeStream(streamDesc.getStreamId());
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void onStart() {
+        this.runtime.start(this.application, this.config);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void onStop() {
+        this.runtime.stop(this.application, this.config);
+    }
+
+    public ApplicationEntity getMetadata() {
+        return metadata;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderLoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderLoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderLoader.java
index d526bd4..11e5dca 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderLoader.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderLoader.java
@@ -60,7 +60,7 @@ public abstract class ApplicationProviderLoader {
         if (providers.containsKey(type)) {
             return providers.get(type);
         } else {
-            throw new IllegalArgumentException("Unknown Application Type: " + type);
+            throw new IllegalArgumentException("Illegal Application Type: " + type);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java
index 14abbc3..fd8e650 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java
@@ -16,23 +16,20 @@
  */
 package org.apache.eagle.app.service.impl;
 
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.typesafe.config.Config;
 import org.apache.eagle.alert.metadata.IMetadataDao;
-import org.apache.eagle.app.service.ApplicationContext;
 import org.apache.eagle.app.service.ApplicationManagementService;
 import org.apache.eagle.app.service.ApplicationOperations;
+import org.apache.eagle.app.service.ApplicationOperationContext;
 import org.apache.eagle.app.service.ApplicationProviderService;
 import org.apache.eagle.app.spi.ApplicationProvider;
 import org.apache.eagle.metadata.exceptions.EntityNotFoundException;
-import org.apache.eagle.metadata.model.ApplicationDesc;
-import org.apache.eagle.metadata.model.ApplicationEntity;
-import org.apache.eagle.metadata.model.Property;
-import org.apache.eagle.metadata.model.SiteEntity;
+import org.apache.eagle.metadata.model.*;
 import org.apache.eagle.metadata.service.ApplicationEntityService;
 import org.apache.eagle.metadata.service.SiteEntityService;
-import com.google.common.base.Preconditions;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.typesafe.config.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -81,63 +78,80 @@ public class ApplicationManagementServiceImpl implements ApplicationManagementSe
         applicationEntity.setJarPath(operation.getJarPath());
         applicationEntity.ensureDefault();
 
-        /**
-         *  calculate application config based on
-         *   1) default values in metadata.xml
-         *   2) user's config value override default configurations
-         *   3) some metadata, for example siteId, mode, appId in ApplicationContext
-         */
+        // Calculate application config based on:
+        //
+        //  1) default values in metadata.xml.
+        //  2) user's config value override default configurations.
+        //  3) fill runtime information, for example siteId, mode, appId in ApplicationOperationContext.
+
         Map<String, Object> appConfig = new HashMap<>();
         ApplicationProvider provider = applicationProviderService.getApplicationProviderByType(operation.getAppType());
 
-        List<Property> propertyList = provider.getApplicationDesc().getConfiguration().getProperties();
-        for (Property p : propertyList) {
-            appConfig.put(p.getName(), p.getValue());
-        }
-        if (operation.getConfiguration() != null) {
-            appConfig.putAll(operation.getConfiguration());
+        ApplicationDesc applicationDesc = provider.getApplicationDesc();
+
+        if (applicationDesc.getConfiguration() != null) {
+            List<Property> propertyList = provider.getApplicationDesc().getConfiguration().getProperties();
+            for (Property p : propertyList) {
+                appConfig.put(p.getName(), p.getValue());
+            }
+            if (operation.getConfiguration() != null) {
+                appConfig.putAll(operation.getConfiguration());
+            }
         }
         applicationEntity.setConfiguration(appConfig);
-        ApplicationContext applicationContext = new ApplicationContext(
+
+        validateDependingApplicationInstalled(applicationEntity);
+
+        ApplicationOperationContext applicationOperationContext = new ApplicationOperationContext(
             applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication(),
             applicationEntity, config, alertMetadataService);
-        applicationContext.onInstall();
+        applicationOperationContext.onInstall();
         return applicationEntityService.create(applicationEntity);
     }
 
+    private void validateDependingApplicationInstalled(ApplicationEntity applicationEntity) {
+        if (applicationEntity.getDescriptor().getDependencies() != null) {
+            for (ApplicationDependency dependency : applicationEntity.getDescriptor().getDependencies()) {
+                if (dependency.isRequired() && applicationEntityService.getBySiteIdAndAppType(applicationEntity.getSite().getSiteId(), dependency.getType()) == null) {
+                    throw new IllegalStateException("Required dependency " + dependency.toString() + " of " + applicationEntity.getDescriptor().getType() + " was not installed");
+                }
+            }
+        }
+    }
+
     @Override
     public ApplicationEntity uninstall(ApplicationOperations.UninstallOperation operation) {
         ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(), operation.getAppId());
-        ApplicationContext applicationContext = new ApplicationContext(
+        ApplicationOperationContext applicationOperationContext = new ApplicationOperationContext(
             applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication(),
             applicationEntity, config, alertMetadataService);
         // TODO: Check status, skip stop if already STOPPED
         try {
-            applicationContext.onStop();
+            applicationOperationContext.onStop();
         } catch (Throwable throwable) {
             LOGGER.error(throwable.getMessage(), throwable);
         }
-        applicationContext.onUninstall();
+        applicationOperationContext.onUninstall();
         return applicationEntityService.delete(applicationEntity);
     }
 
     @Override
     public ApplicationEntity start(ApplicationOperations.StartOperation operation) {
         ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(), operation.getAppId());
-        ApplicationContext applicationContext = new ApplicationContext(
+        ApplicationOperationContext applicationOperationContext = new ApplicationOperationContext(
             applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication(),
             applicationEntity, config, alertMetadataService);
-        applicationContext.onStart();
+        applicationOperationContext.onStart();
         return applicationEntity;
     }
 
     @Override
     public ApplicationEntity stop(ApplicationOperations.StopOperation operation) {
         ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(), operation.getAppId());
-        ApplicationContext applicationContext = new ApplicationContext(
+        ApplicationOperationContext applicationOperationContext = new ApplicationOperationContext(
             applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication(),
             applicationEntity, config, alertMetadataService);
-        applicationContext.onStop();
+        applicationOperationContext.onStop();
         return applicationEntity;
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java
index 2f613c1..025bc7c 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java
@@ -31,6 +31,10 @@ import java.util.List;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.Unmarshaller;
 
+/**
+ * @deprecated unstable implementation.
+ */
+@Deprecated
 public class ApplicationProviderConfigLoader extends ApplicationProviderLoader {
     public static final String DEFAULT_APPLICATIONS_CONFIG_FILE = "providers.xml";
     private static final String APPLICATIONS_CONFIG_PROPS_KEY = "application.provider.config";

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java
index 8b73865..1e0421a 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java
@@ -30,6 +30,9 @@ import java.net.URLClassLoader;
 import java.util.ServiceLoader;
 import java.util.function.Function;
 
+/**
+ * Load Application Provider with SPI, by default from current class loader.
+ */
 public class ApplicationProviderSPILoader extends ApplicationProviderLoader {
     private final String appProviderExtDir;
     private static final Logger LOG = LoggerFactory.getLogger(ApplicationProviderSPILoader.class);

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java
index 3cb31f9..1aa4618 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java
@@ -16,17 +16,20 @@
  */
 package org.apache.eagle.app.service.impl;
 
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.typesafe.config.Config;
 import org.apache.eagle.app.service.ApplicationProviderLoader;
 import org.apache.eagle.app.service.ApplicationProviderService;
 import org.apache.eagle.app.spi.ApplicationProvider;
+import org.apache.eagle.metadata.model.ApplicationDependency;
 import org.apache.eagle.metadata.model.ApplicationDesc;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.typesafe.config.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
@@ -39,7 +42,7 @@ public class ApplicationProviderServiceImpl implements ApplicationProviderServic
     private final Config config;
     private static final Logger LOG = LoggerFactory.getLogger(ApplicationProviderServiceImpl.class);
     private final ApplicationProviderLoader appProviderLoader;
-    public static final String APP_PROVIDER_LOADER_CLASS_KEY = "application.provider.loader";
+    private static final String APP_PROVIDER_LOADER_CLASS_KEY = "application.provider.loader";
 
     @Inject
     public ApplicationProviderServiceImpl(Config config) {
@@ -67,6 +70,47 @@ public class ApplicationProviderServiceImpl implements ApplicationProviderServic
         LOG.warn("Loading application providers ...");
         appProviderLoader.load();
         LOG.warn("Loaded {} application providers", appProviderLoader.getProviders().size());
+        validate();
+    }
+
+    private void validate() {
+        for (ApplicationDesc applicationDesc : getApplicationDescs()) {
+            LOG.debug("Validating {}", applicationDesc.getType());
+
+            Preconditions.checkNotNull(applicationDesc.getType(), "type is null in " + applicationDesc);
+            Preconditions.checkNotNull(applicationDesc.getVersion(), "version is null in " + applicationDesc);
+            Preconditions.checkNotNull(applicationDesc.getName(), "name is null in " + applicationDesc);
+
+            // Validate Dependency
+            LOG.debug("Validating dependency of {}", applicationDesc.getType());
+            List<ApplicationDependency> dependencyList = applicationDesc.getDependencies();
+            if (dependencyList != null) {
+                for (ApplicationDependency dependency : dependencyList) {
+                    try {
+                        ApplicationDesc dependencyDesc = getApplicationDescByType(dependency.getType());
+                        if (dependencyDesc != null && dependency.getVersion() != null) {
+                            if (dependencyDesc.getVersion().equals(dependency.getVersion())) {
+                                LOG.debug("Loaded dependency {} -> {}", applicationDesc.getType(), dependency);
+                            } else {
+                                LOG.warn("Loaded dependency {} -> {}, but the version was mismatched, expected: {}, actual: {}",
+                                    applicationDesc.getType(), dependency, dependency.getVersion(), applicationDesc.getVersion());
+                            }
+                        } else {
+                            assert dependencyDesc != null;
+                            dependency.setVersion(dependencyDesc.getVersion());
+                        }
+                    } catch (IllegalArgumentException ex) {
+                        if (!dependency.isRequired()) {
+                            LOG.warn("Unable to load dependency {} -> {}", applicationDesc.getType(), dependency, ex);
+                        } else {
+                            LOG.error("Failed to load dependency {} -> {}", applicationDesc.getType(), dependency,ex);
+                            throw new IllegalStateException("Failed to load application providers due to dependency missing",ex);
+                        }
+                    }
+                }
+            }
+            LOG.info("Validated {} successfully", applicationDesc.getType());
+        }
     }
 
     public Collection<ApplicationProvider> getProviders() {
@@ -81,7 +125,6 @@ public class ApplicationProviderServiceImpl implements ApplicationProviderServic
         return appProviderLoader.getApplicationProviderByType(type);
     }
 
-    @Deprecated
     public ApplicationDesc getApplicationDescByType(String appType) {
         return appProviderLoader.getApplicationProviderByType(appType).getApplicationDesc();
     }

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/AbstractApplicationProvider.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/AbstractApplicationProvider.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/AbstractApplicationProvider.java
index 4a9c1ff..06ac703 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/AbstractApplicationProvider.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/AbstractApplicationProvider.java
@@ -14,73 +14,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.eagle.app.spi;
 
 import org.apache.eagle.alert.engine.coordinator.StreamDefinition;
 import org.apache.eagle.app.Application;
-import org.apache.eagle.app.config.ApplicationProviderConfig;
-import org.apache.eagle.app.config.ApplicationProviderDescConfig;
 import org.apache.eagle.common.module.ModuleRegistry;
 import org.apache.eagle.metadata.model.ApplicationDesc;
 import org.apache.eagle.metadata.model.ApplicationDocs;
 import org.apache.eagle.metadata.model.Configuration;
-import com.typesafe.config.Config;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.List;
 import javax.xml.bind.JAXBException;
+import java.util.List;
 
 /**
- * Default metadata path is:  /META-INF/providers/${ApplicationProviderClassName}.xml
- *
- * @param <T>
+ * Describe Application metadata with XML descriptor configuration in path of:  /META-INF/providers/${ApplicationProviderClassName}.xml
  */
 public abstract class AbstractApplicationProvider<T extends Application> implements ApplicationProvider<T> {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractApplicationProvider.class);
     private final ApplicationDesc applicationDesc;
 
-    private static final String METADATA_RESOURCE_PATH = "/META-INF/providers/%s.xml";
-
-    /**
-     * Default metadata path is:  /META-INF/providers/${ApplicationProviderClassName}.xml
-     *
-     * <p>You are not recommended to override this method except you could make sure the path is universal unique</p>
-     *
-     * @return metadata file path
-     */
-    protected final String getMetadata() {
-        return String.format(METADATA_RESOURCE_PATH, this.getClass().getName());
-    }
-
     protected AbstractApplicationProvider() {
-        String applicationDescConfig = getMetadata();
-        applicationDesc = new ApplicationDesc();
-        applicationDesc.setProviderClass(this.getClass());
-        ApplicationProviderDescConfig descWrapperConfig = ApplicationProviderDescConfig.loadFromXML(this.getClass(), applicationDescConfig);
-        setType(descWrapperConfig.getType());
-        setVersion(descWrapperConfig.getVersion());
-        setName(descWrapperConfig.getName());
-        setDocs(descWrapperConfig.getDocs());
-        try {
-            if (descWrapperConfig.getAppClass() != null) {
-                // setAppClass((Class<T>) Class.forName(descWrapperConfig.getAppClass()));
-                setAppClass((Class<T>) Class.forName(descWrapperConfig.getAppClass(), true, this.getClass().getClassLoader()));
-                if (!Application.class.isAssignableFrom(applicationDesc.getAppClass())) {
-                    throw new IllegalStateException(descWrapperConfig.getAppClass() + " is not sub-class of " + Application.class.getCanonicalName());
-                }
-            }
-        } catch (ClassNotFoundException e) {
-            LOG.error(e.getMessage(), e);
-            throw new RuntimeException(e.getMessage(), e.getCause());
-        }
-        setViewPath(descWrapperConfig.getViewPath());
-        setConfiguration(descWrapperConfig.getConfiguration());
-        setStreams(descWrapperConfig.getStreams());
-    }
-
-    @Override
-    public void prepare(ApplicationProviderConfig providerConfig, Config envConfig) {
+        applicationDesc = new ApplicationXMLDescriptorLoader(this.getClass(),this.getApplicationClass()).getApplicationDesc();
     }
 
     protected void setVersion(String version) {
@@ -116,7 +73,8 @@ public abstract class AbstractApplicationProvider<T extends Application> impleme
     public String toString() {
         return String.format(
             "%s[name=%s, type=%s, version=%s, viewPath=%s, appClass=%s, configuration= %s properties]", getClass().getSimpleName(),
-            applicationDesc.getName(), applicationDesc.getType(), applicationDesc.getVersion(), applicationDesc.getViewPath(), applicationDesc.getAppClass(), applicationDesc.getConfiguration().size()
+            applicationDesc.getName(), applicationDesc.getType(), applicationDesc.getVersion(), applicationDesc.getViewPath(), applicationDesc.getAppClass(),
+            applicationDesc.getConfiguration() == null ? 0 : applicationDesc.getConfiguration().size()
         );
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationDescLoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationDescLoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationDescLoader.java
new file mode 100644
index 0000000..ecab289
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationDescLoader.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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app.spi;
+
+import org.apache.eagle.metadata.model.ApplicationDesc;
+
+public interface ApplicationDescLoader {
+
+    /**
+     * @return ApplicationDesc instance.
+     */
+    ApplicationDesc getApplicationDesc();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationProvider.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationProvider.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationProvider.java
index 761cfbb..0dceb72 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationProvider.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationProvider.java
@@ -16,15 +16,27 @@
  */
 package org.apache.eagle.app.spi;
 
+import com.typesafe.config.Config;
 import org.apache.eagle.app.Application;
 import org.apache.eagle.app.config.ApplicationProviderConfig;
 import org.apache.eagle.common.module.ModuleRegistry;
 import org.apache.eagle.metadata.model.ApplicationDesc;
-import com.typesafe.config.Config;
 
+import java.lang.reflect.ParameterizedType;
+
+/**
+ * Application Service Provider Interface.
+ *
+ * @param <T> Application Type.
+ */
 public interface ApplicationProvider<T extends Application> {
 
-    void prepare(ApplicationProviderConfig providerConfig,Config envConfig);
+    /**
+     * Prepare Application Provider before loading.
+     */
+    default void prepare(ApplicationProviderConfig providerConfig, Config envConfig) {
+        // Do nothing by default.
+    }
 
     /**
      * @return application descriptor.
@@ -32,9 +44,30 @@ public interface ApplicationProvider<T extends Application> {
     ApplicationDesc getApplicationDesc();
 
     /**
+     * Get Application Instance Type, by default load from generic parameter automatically
+     *
+     * @return application class type if exists.
+     */
+    default Class<T> getApplicationClass() {
+        try {
+            String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
+            Class<?> clazz = Class.forName(className);
+            return (Class<T>) clazz;
+        } catch (Exception e) {
+            throw new IllegalStateException(
+                "Unable to get generic application class, "
+                    + "reason: class is not parametrized with generic type, "
+                    + "please provide application class by overriding getApplicationClass()");
+        }
+    }
+
+    /**
      * @return application instance.
      */
     T getApplication();
 
+    /**
+     * Extend application modules like Web Resource, Metadata Store, etc.
+     */
     void register(ModuleRegistry registry);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationXMLDescriptorLoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationXMLDescriptorLoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationXMLDescriptorLoader.java
new file mode 100644
index 0000000..bdc8a3a
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/spi/ApplicationXMLDescriptorLoader.java
@@ -0,0 +1,69 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.eagle.app.spi;
+
+import org.apache.eagle.app.Application;
+import org.apache.eagle.app.config.ApplicationProviderDescConfig;
+import org.apache.eagle.metadata.model.ApplicationDesc;
+
+/**
+ * Describe Application metadata with XML descriptor configuration in path of:  /META-INF/providers/${ApplicationProviderClassName}.xml
+ */
+class ApplicationXMLDescriptorLoader implements ApplicationDescLoader {
+    private final Class<? extends ApplicationProvider> providerClass;
+    private final Class<? extends Application> applicationClass;
+
+    private static final String METADATA_RESOURCE_PATH = "/META-INF/providers/%s.xml";
+
+    ApplicationXMLDescriptorLoader(Class<? extends ApplicationProvider> providerClass, Class<? extends Application> applicationClass) {
+        this.providerClass = providerClass;
+        this.applicationClass = applicationClass;
+    }
+
+    /**
+     * Default metadata path is:  /META-INF/providers/${ApplicationProviderClassName}.xml
+     * <p>You are not recommended to override this method except you could make sure the path is universal unique</p>
+     *
+     * @return metadata file path
+     */
+    private String generateXMLDescriptorPath() {
+        return String.format(METADATA_RESOURCE_PATH, providerClass.getName());
+    }
+
+    @Override
+    public ApplicationDesc getApplicationDesc() {
+        String descriptorPath = generateXMLDescriptorPath();
+        ApplicationDesc applicationDesc = new ApplicationDesc();
+        applicationDesc.setProviderClass(this.getClass());
+        ApplicationProviderDescConfig descWrapperConfig = ApplicationProviderDescConfig.loadFromXML(this.getClass(), descriptorPath);
+        applicationDesc.setType(descWrapperConfig.getType());
+        applicationDesc.setVersion(descWrapperConfig.getVersion());
+        applicationDesc.setName(descWrapperConfig.getName());
+        applicationDesc.setDocs(descWrapperConfig.getDocs());
+        if (applicationClass != null) {
+            applicationDesc.setAppClass(applicationClass);
+            if (!Application.class.isAssignableFrom(applicationDesc.getAppClass())) {
+                throw new IllegalStateException(applicationDesc.getAppClass() + " is not sub-class of " + Application.class.getCanonicalName());
+            }
+        }
+        applicationDesc.setDependencies(descWrapperConfig.getDependencies());
+        applicationDesc.setViewPath(descWrapperConfig.getViewPath());
+        applicationDesc.setConfiguration(descWrapperConfig.getConfiguration());
+        applicationDesc.setStreams(descWrapperConfig.getStreams());
+        return applicationDesc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderDescConfigTest.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderDescConfigTest.java b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderDescConfigTest.java
index 9285d7d..992c622 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderDescConfigTest.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderDescConfigTest.java
@@ -1,16 +1,4 @@
-package org.apache.eagle.app;
-
-import org.apache.eagle.app.config.ApplicationProviderDescConfig;
-import org.apache.eagle.app.spi.AbstractApplicationProvider;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.Unmarshaller;
-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.
@@ -26,13 +14,17 @@ import java.io.InputStream;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.eagle.app;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import java.io.InputStream;
+
+
 public class ApplicationProviderDescConfigTest {
-    @Test
-    @Ignore
-    public void testApplicationDescWrapperConfigLoadFromXML(){
-        ApplicationProviderDescConfig config = ApplicationProviderDescConfig.loadFromXML(ApplicationProviderDescConfigTest.class, "TestApplicationMetadata.xml");
-        Assert.assertNotNull(config);
-    }
 
     @Test
     public void testStreamDefinitionLoadFromXML(){

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderServiceTest.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderServiceTest.java b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderServiceTest.java
index 6f32521..57337f5 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderServiceTest.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/ApplicationProviderServiceTest.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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.
@@ -16,34 +16,36 @@
  */
 package org.apache.eagle.app;
 
+import static org.junit.Assert.*;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.typesafe.config.ConfigFactory;
-import org.apache.eagle.app.module.ApplicationGuiceModule;
+import com.google.inject.Inject;
 import org.apache.eagle.app.service.ApplicationProviderService;
-import org.apache.eagle.app.service.impl.ApplicationProviderServiceImpl;
 import org.apache.eagle.app.spi.ApplicationProvider;
-import org.apache.eagle.common.module.CommonGuiceModule;
+import org.apache.eagle.app.test.ApplicationTestBase;
 import org.apache.eagle.metadata.model.ApplicationDesc;
-import org.apache.eagle.metadata.service.memory.MemoryMetadataStore;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 
-public class ApplicationProviderServiceTest {
+public class ApplicationProviderServiceTest extends ApplicationTestBase {
     private final static Logger LOGGER = LoggerFactory.getLogger(ApplicationProviderServiceTest.class);
-    private Injector injector = Guice.createInjector(new CommonGuiceModule(),new ApplicationGuiceModule(new ApplicationProviderServiceImpl(ConfigFactory.load())), new MemoryMetadataStore());
+
+    @Inject
+    private
+    ApplicationProviderService providerManager;
 
     @Test
-    public void testApplicationProviderManagerInit(){
-        ApplicationProviderService providerManager = injector.getInstance(ApplicationProviderService.class);
+    public void testApplicationProviderLoaderService(){
         Collection<ApplicationDesc> applicationDescs = providerManager.getApplicationDescs();
         Collection<ApplicationProvider> applicationProviders = providerManager.getProviders();
-
         applicationDescs.forEach((d)-> LOGGER.debug(d.toString()));
         applicationProviders.forEach((d)-> LOGGER.debug(d.toString()));
+        assertNull(providerManager.getApplicationDescByType("TEST_APPLICATION").getViewPath());
+        assertEquals("/apps/test_web_app",providerManager.getApplicationDescByType("TEST_WEB_APPLICATION").getViewPath());
+        assertNotNull(providerManager.getApplicationDescByType("TEST_WEB_APPLICATION").getDependencies());
+        assertEquals(1,providerManager.getApplicationDescByType("TEST_WEB_APPLICATION").getDependencies().size());
+        assertEquals("TEST_APPLICATION",providerManager.getApplicationDescByType("TEST_WEB_APPLICATION").getDependencies().get(0).getType());
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/83bd4e3d/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/TestStormApplication.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/TestStormApplication.java b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/TestStormApplication.java
index 5668e6f..c6ac5db 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/TestStormApplication.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/test/java/org/apache/eagle/app/TestStormApplication.java
@@ -86,7 +86,7 @@ public class TestStormApplication extends StormApplication{
         Class<? extends ExtendedDao> getType();
     }
 
-    private class ExtendedDaoImpl implements ExtendedDao {
+    private static class ExtendedDaoImpl implements ExtendedDao {
         private final Config config;
 
         @Inject