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/07/22 16:54:15 UTC

[3/3] incubator-eagle git commit: [EAGLE-386] Refactor Application Framework Interfaces and StreamEventMapper

[EAGLE-386] Refactor Application Framework Interfaces and StreamEventMapper

[Description]
h1. Application Framework Interfaces

Application Context (Runtime): org.apache.eagle.app.ApplicationContext
Application Metadata Entity (Persistence): org.apache.eagle.metadata.model.ApplicationEntity
Application Processing Logic (Execution): org.apache.eagle.app.Application
Application Lifecycle Listener (Installation): org.apache.eagle.app.ApplicationLifecycleListener

h1. StreamEventMapper (Flatten/Direct)
* FlattenEventMapper
* DirectEventMapper

h1. Metadata.xml Path Best Practice
/META-INF/apps/example/metadata.xml

[Changes]
Decouple Tuple to Event mapping with StreamEventMapper

Rename EventMapper and Application#buildApp

Integrate with ApplicationContext with ApplicationLifecycleListener to make sure callback onAppInstall/onAppUninstall

Clarify application framework interfaces and docs

Clarify ApplicationContext as single entrance of app metadata/processing/lifecycle

Clear application service code

Better metadata.xml practice: /META-INF/apps/example/metadata.xml

Fix ApplicationOperations json bug and MetadataStore related compile error


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

Branch: refs/heads/develop
Commit: e73e35da0fa778564fb23582478541fe390f2a0a
Parents: e21b073
Author: Chen, Hao <hc...@ebay.com>
Authored: Fri Jul 22 17:27:28 2016 +0800
Committer: Hao Chen <ha...@apache.org>
Committed: Sat Jul 23 00:50:40 2016 +0800

----------------------------------------------------------------------
 .../apache/eagle/app/AbstractApplication.java   |   4 +-
 .../java/org/apache/eagle/app/Application.java  |   2 +-
 .../apache/eagle/app/ApplicationContext.java    | 217 +++++++++++++++----
 .../eagle/app/ApplicationGuiceModule.java       |   4 +-
 .../eagle/app/ApplicationLifecycleListener.java |  39 ++++
 .../java/org/apache/eagle/app/package-info.java |  29 +++
 .../eagle/app/resource/ApplicationResource.java |  14 +-
 .../apache/eagle/app/service/AppOperations.java | 161 --------------
 .../service/ApplicationManagementService.java   |   8 +-
 .../ApplicationManagementServiceImpl.java       |  96 --------
 .../app/service/ApplicationOperations.java      | 189 ++++++++++++++++
 .../app/service/ApplicationProviderLoader.java  |   4 +-
 .../service/ApplicationProviderServiceImpl.java |  87 --------
 .../impl/ApplicationManagementServiceImpl.java  |  98 +++++++++
 .../impl/ApplicationProviderConfigLoader.java   | 128 +++++++++++
 .../impl/ApplicationProviderSPILoader.java      |  89 ++++++++
 .../impl/ApplicationProviderServiceImpl.java    |  89 ++++++++
 .../loader/ApplicationProviderConfigLoader.java | 128 -----------
 .../loader/ApplicationProviderSPILoader.java    |  89 --------
 .../eagle/app/sink/AbstractStreamSink.java      |  74 +++++++
 .../apache/eagle/app/sink/KafkaStreamSink.java  |  39 ++--
 .../eagle/app/sink/LoggingStreamSink.java       |  18 +-
 .../org/apache/eagle/app/sink/StreamSink.java   | 125 ++++-------
 .../app/sink/mapper/DirectEventMapper.java      |  19 ++
 .../mapper/FieldIndexDirectEventMapper.java     |  40 ++++
 .../sink/mapper/FieldNameDirectEventMapper.java |  40 ++++
 .../app/sink/mapper/FlattenEventMapper.java     |  78 +++++++
 .../app/sink/mapper/StreamEventMapper.java      |  33 +++
 .../app/sink/mapper/TimestampSelector.java      |  25 +++
 .../app/spi/AbstractApplicationProvider.java    |   6 +-
 .../org/apache/eagle/app/test/AppSimulator.java |  51 -----
 .../apache/eagle/app/test/AppSimulatorImpl.java |   8 +-
 .../eagle/app/test/AppTestGuiceModule.java      |   4 +-
 .../eagle/app/test/ApplicationSimulator.java    |  70 ++++++
 .../src/main/resources/applications.xml         |  42 ----
 .../app/ApplicationProviderServiceTest.java     |   3 +-
 .../apache/eagle/app/TestApplicationImpl.java   |  38 ++--
 .../eagle/app/TestApplicationTestSuite.java     |  14 +-
 .../test/resources/TestApplicationMetadata.xml  |   8 +
 .../src/test/resources/application.conf         |   4 +-
 .../eagle-metadata/eagle-metadata-base/pom.xml  |   4 +
 .../eagle/metadata/model/ApplicationEntity.java |   2 +-
 .../eagle/metadata/model/StreamSinkDesc.java    |  40 ++++
 .../persistence/MemoryMetadataStore.java        |  33 ---
 .../metadata/persistence/MetadataStore.java     |   4 +-
 .../service/memory/MemoryMetadataStore.java     |  32 +++
 eagle-examples/eagle-app-example/pom.xml        |   6 -
 .../eagle/app/example/ExampleApplication.java   |  36 ++-
 .../app/example/ExampleApplicationProvider.java |   5 +-
 .../example/ExampleApplicationProvider2.java    |   2 +-
 .../eagle/app/example/RandomEventSpout.java     |  59 -----
 .../resources/ExampleApplicationMetadata.xml    |   8 +
 .../META-INF/apps/example/metadata.xml          | 109 ++++++++++
 .../app/example/ExampleApplicationTest.java     |  28 ++-
 .../src/test/java/resources/application.conf    |  58 +++++
 .../apache/eagle/server/ServerApplication.java  |  10 +-
 .../org/apache/eagle/server/ServerConfig.java   |  22 +-
 .../src/main/resources/application.conf         |   9 +-
 .../src/main/resources/providers-disabled.xml   |  27 +++
 eagle-server/src/main/resources/providers.xml   |  27 ---
 eagle-server/src/main/webapp/WEB-INF/web.xml    |  88 ++++++++
 pom.xml                                         |  11 +
 62 files changed, 1821 insertions(+), 1013 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
index 1cb2625..5001a80 100644
--- 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
@@ -61,7 +61,7 @@ public abstract class AbstractApplication implements Application,Serializable {
         String topologyName = context.getAppEntity().getAppId();
 
         TopologyBuilder builder = new TopologyBuilder();
-        buildTopology(builder,context);
+        buildApp(builder,context);
         StormTopology topology = builder.createTopology();
         Config conf = getClusterStormConfig(context);
         if(appEntity.getMode() == ApplicationEntity.Mode.CLUSTER){
@@ -117,7 +117,7 @@ public abstract class AbstractApplication implements Application,Serializable {
         return conf;
     }
 
-    protected abstract void buildTopology(TopologyBuilder builder, ApplicationContext context);
+    protected abstract void buildApp(TopologyBuilder builder, ApplicationContext context);
 
     @Override
     public void stop(ApplicationContext context) {

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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 ffe5339..4d35e08 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
@@ -17,7 +17,7 @@
 package org.apache.eagle.app;
 
 /**
- * Application Lifecycle Interface
+ * Application Execution Interface
  */
 public interface Application {
     /**

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationContext.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationContext.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationContext.java
index 1723250..dc2a456 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationContext.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationContext.java
@@ -18,65 +18,80 @@ package org.apache.eagle.app;
 
 import com.typesafe.config.Config;
 import org.apache.eagle.alert.engine.coordinator.StreamDefinition;
+import org.apache.eagle.app.sink.AbstractStreamSink;
 import org.apache.eagle.app.sink.StreamSink;
+import org.apache.eagle.app.sink.mapper.*;
+import org.apache.eagle.app.spi.ApplicationProvider;
 import org.apache.eagle.metadata.model.ApplicationEntity;
 import org.apache.eagle.metadata.model.StreamDesc;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 /**
- * Application Execution Context
+ * Application Context Interface: org.apache.eagle.app.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.ApplicationLifecycleListener</li>
+ * </ul>
  */
-public class ApplicationContext implements Serializable {
+public class ApplicationContext implements Serializable, ApplicationLifecycleListener{
     private final Config envConfig;
     private final ApplicationEntity appEntity;
     private final static Logger LOG = LoggerFactory.getLogger(ApplicationContext.class);
-    private final Map<String, StreamSink> streamSinkMap;
+    private final Map<String, StreamDefinition> streamDefinitionMap;
     private final Map<String,StreamDesc> streamDescMap;
+    private final List<ApplicationLifecycleListener> applicationLifecycleListeners;
+    private final ApplicationProvider appProvider;
 
-    public ApplicationContext(ApplicationEntity appEntity, Config envConfig){
+    /**
+     * @param appEntity ApplicationEntity
+     * @param appProvider ApplicationProvider
+     * @param envConfig Config
+     */
+    public ApplicationContext(ApplicationEntity appEntity, ApplicationProvider appProvider, Config envConfig){
         this.appEntity = appEntity;
         this.envConfig = envConfig;
-        this.streamSinkMap = new HashMap<>();
+        this.appProvider = appProvider;
+        this.streamDefinitionMap = new HashMap<>();
         this.streamDescMap = new HashMap<>();
-
-        // TODO: Decouple out of ApplicationContext constructor
+        this.applicationLifecycleListeners = new LinkedList<>();
         doInit();
     }
 
+    public void registerListener(ApplicationLifecycleListener listener){
+        applicationLifecycleListeners.add(listener);
+    }
+
+    public List<ApplicationLifecycleListener> getListeners(){
+        return applicationLifecycleListeners;
+    }
+
     private void doInit() {
-        try {
-            Class<?> sinkClass = appEntity.getDescriptor().getSinkClass();
-            List<StreamDefinition> outputStreams = appEntity.getDescriptor().getStreams();
-            if(null != outputStreams){
-                Constructor constructor = sinkClass.getConstructor(StreamDefinition.class,ApplicationContext.class);
-                outputStreams.forEach((stream) -> {
-                    try {
-                        StreamSink streamSink = (StreamSink) constructor.newInstance(stream,this);
-                        streamSinkMap.put(stream.getStreamId(), streamSink);
-                        StreamDesc streamDesc = new StreamDesc();
-                        streamDesc.setStreamSchema(stream);
-                        streamDesc.setSinkContext(streamSink.getSinkContext());
-                        streamDesc.setSinkType(sinkClass);
-                        streamDesc.setStreamId(stream.getStreamId());
-                        streamDescMap.put(streamDesc.getStreamId(),streamDesc);
-                    } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
-                        LOG.error("Failed to initialize instance "+sinkClass.getCanonicalName()+" for application: {}",this.getAppEntity());
-                        throw new RuntimeException("Failed to initialize instance "+sinkClass.getCanonicalName()+" for application:"+this.getAppEntity(),e);
-                    }
-                });
-            }
-        } catch (NoSuchMethodException e) {
-            LOG.error(e.getMessage(),e);
-            throw new RuntimeException(e.getMessage(),e.getCause());
+        Class<?> sinkClass = appEntity.getDescriptor().getSinkClass();
+        List<StreamDefinition> outputStreams = appEntity.getDescriptor().getStreams();
+        if(null != outputStreams){
+            outputStreams.forEach((stream) -> {
+                try {
+                    StreamSink streamSink = (StreamSink) sinkClass.newInstance();
+                    streamSink.init(stream,this);
+                    StreamDesc streamDesc = new StreamDesc();
+                    streamDesc.setStreamSchema(stream);
+                    streamDesc.setSinkContext(streamSink.getSinkContext());
+                    streamDesc.setSinkType(sinkClass);
+                    streamDesc.setStreamId(stream.getStreamId());
+                    streamDescMap.put(streamDesc.getStreamId(),streamDesc);
+                    streamDefinitionMap.put(streamDesc.getStreamId(),stream);
+                    registerListener(streamSink);
+                } catch (InstantiationException | IllegalAccessException e) {
+                    LOG.error("Failed to initialize instance "+sinkClass.getCanonicalName()+" for application: {}",this.getAppEntity());
+                    throw new RuntimeException("Failed to initialize instance "+sinkClass.getCanonicalName()+" for application:"+this.getAppEntity(),e);
+                }
+            });
         }
     }
 
@@ -94,15 +109,133 @@ public class ApplicationContext implements Serializable {
      * @param streamId
      * @return
      */
-    public StreamSink getStreamSink(String streamId){
-        if(streamSinkMap.containsKey(streamId)) {
-            return streamSinkMap.get(streamId);
-        } else {
-            throw new IllegalStateException("Stream (ID: "+streamId+") was not declared in "+this.appEntity.getDescriptor().getProviderClass().getCanonicalName()+" before being called");
+    public StreamSink getFlattenStreamSink(String streamId, StreamEventMapper mapper){
+        checkStreamExists(streamId);
+        Class<?> sinkClass = appEntity.getDescriptor().getSinkClass();
+        try {
+            AbstractStreamSink abstractStreamSink = (AbstractStreamSink) sinkClass.newInstance();
+            abstractStreamSink.setEventMapper(mapper);
+            abstractStreamSink.init(streamDefinitionMap.get(streamId),this);
+            return abstractStreamSink;
+        } catch (InstantiationException | IllegalAccessException e) {
+            LOG.error("Failed to instantiate "+sinkClass,e);
+            throw new IllegalStateException("Failed to instantiate "+sinkClass,e);
+        }
+    }
+
+    /**
+     * Make sure streamId is declared in Application Providers
+     *
+     * @param streamId
+     * @return
+     */
+    public StreamSink getDirectStreamSink(String streamId, String ... fieldNames){
+        return getFlattenStreamSink(streamId,new FieldNameDirectEventMapper(fieldNames));
+    }
+
+    /**
+     * Make sure streamId is declared in Application Providers
+     *
+     * @param streamId
+     * @return
+     */
+    public StreamSink getDirectStreamSink(String streamId, int ... fieldIndexs){
+        return getFlattenStreamSink(streamId,new FieldIndexDirectEventMapper(fieldIndexs));
+    }
+
+    /**
+     * Make sure streamId is declared in Application Providers
+     *
+     * @param streamId
+     * @return
+     */
+    public StreamSink getFlattenStreamSink(String streamId, TimestampSelector timestampSelector){
+        checkStreamExists(streamId);
+        return getFlattenStreamSink(streamId,new FlattenEventMapper(streamDefinitionMap.get(streamId),timestampSelector));
+    }
+
+    /**
+     * Make sure streamId is declared in Application Providers
+     *
+     * @param streamId
+     * @return
+     */
+    public StreamSink getFlattenStreamSink(String streamId, String timestampField){
+        checkStreamExists(streamId);
+        return getFlattenStreamSink(streamId,new FlattenEventMapper(streamDefinitionMap.get(streamId),timestampField));
+    }
+
+    /**
+     * Make sure streamId is declared in Application Providers
+     *
+     * @param streamId
+     * @return
+     */
+    public StreamSink getFlattenStreamSink(String streamId){
+        checkStreamExists(streamId);
+        return getFlattenStreamSink(streamId,new FlattenEventMapper(streamDefinitionMap.get(streamId)));
+    }
+
+    private void checkStreamExists(String streamId){
+        if(! streamDefinitionMap.containsKey(streamId)){
+            LOG.error("Stream [streamId = "+streamId+"] is not defined in "
+                    + appEntity.getDescriptor().getProviderClass().getCanonicalName());
+            throw new IllegalStateException("Stream [streamId = "+streamId+"] is not defined in "
+                    + appEntity.getDescriptor().getProviderClass().getCanonicalName());
         }
     }
 
     public Collection<StreamDesc> getStreamSinkDescs(){
         return streamDescMap.values();
     }
+
+    @Override
+    public void onAppInstall() {
+        getListeners().forEach((listener)->{
+            try {
+                listener.onAppInstall();
+            }catch (Throwable throwable){
+                LOG.error("Failed to invoked onAppInstall of listener {}",listener.toString(),throwable);
+                throw throwable;
+            }
+        });
+    }
+
+    @Override
+    public void onAppUninstall() {
+        getListeners().forEach((listener)->{
+            try {
+                listener.onAppUninstall();
+            }catch (Throwable throwable){
+                LOG.error("Failed to invoked onAppUninstall of listener {}",listener.toString(),throwable);
+                throw throwable;
+            }
+        });
+    }
+
+    @Override
+    public void onAppStart() {
+        getListeners().forEach((listener)->{
+            try {
+                listener.onAppStart();
+            }catch (Throwable throwable){
+                LOG.error("Failed to invoked onAppStart of listener {}",listener.toString(),throwable);
+                throw throwable;
+            }
+        });
+        appProvider.getApplication().start(this);
+    }
+
+    @Override
+    public void onAppStop() {
+        appProvider.getApplication().stop(this);
+        getListeners().forEach((listener)->{
+            try {
+                listener.onAppStop();
+            }catch (Throwable throwable){
+                LOG.error("Failed to invoked onAppStop of listener {}",listener.toString(),throwable);
+                throw throwable;
+            }
+        });
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationGuiceModule.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationGuiceModule.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationGuiceModule.java
index 9a66b6c..ca3b8f2 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationGuiceModule.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationGuiceModule.java
@@ -19,9 +19,9 @@ package org.apache.eagle.app;
 import com.google.inject.AbstractModule;
 import com.google.inject.Singleton;
 import org.apache.eagle.app.service.ApplicationManagementService;
-import org.apache.eagle.app.service.ApplicationManagementServiceImpl;
+import org.apache.eagle.app.service.impl.ApplicationManagementServiceImpl;
 import org.apache.eagle.app.service.ApplicationProviderService;
-import org.apache.eagle.app.service.ApplicationProviderServiceImpl;
+import org.apache.eagle.app.service.impl.ApplicationProviderServiceImpl;
 import org.apache.eagle.metadata.service.ApplicationDescService;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationLifecycleListener.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationLifecycleListener.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationLifecycleListener.java
new file mode 100644
index 0000000..6ced960
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/ApplicationLifecycleListener.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;
+
+public interface ApplicationLifecycleListener {
+    /**
+     * on application installed
+     */
+    void onAppInstall();
+
+    /**
+     * on application uninstalled
+     */
+    void onAppUninstall();
+
+    /**
+     *
+     */
+    void onAppStart();
+
+    /**
+     *
+     */
+    void onAppStop();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
new file mode 100644
index 0000000..8f1fcb9
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * <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.
+ */
+
+/**
+ *
+ * <h1>Application Management Framework Interfaces</h1>
+ *
+ * <ul>
+ *     <li>Application Context (Runtime): org.apache.eagle.app.ApplicationContext</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.ApplicationLifecycleListener</li>
+ * </ul>
+ */
+package org.apache.eagle.app;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/resource/ApplicationResource.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/resource/ApplicationResource.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/resource/ApplicationResource.java
index a0654ff..b0e9988 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/resource/ApplicationResource.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/resource/ApplicationResource.java
@@ -19,7 +19,7 @@ package org.apache.eagle.app.resource;
 
 import com.google.inject.Inject;
 import org.apache.eagle.app.service.ApplicationManagementService;
-import org.apache.eagle.app.service.AppOperations;
+import org.apache.eagle.app.service.ApplicationOperations;
 import org.apache.eagle.app.service.ApplicationProviderService;
 import org.apache.eagle.metadata.model.ApplicationDesc;
 import org.apache.eagle.metadata.model.ApplicationEntity;
@@ -59,7 +59,7 @@ public class ApplicationResource {
         return providerService.getApplicationDescByType(type);
     }
 
-    @POST
+    @PUT
     @Path("/providers/reload")
     @Produces(MediaType.APPLICATION_JSON)
     public Collection<ApplicationDesc> reloadApplicationDescs(){
@@ -97,7 +97,7 @@ public class ApplicationResource {
     @Path("/install")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public ApplicationEntity installApplication(AppOperations.InstallOperation operation){
+    public ApplicationEntity installApplication(ApplicationOperations.InstallOperation operation){
         return applicationManagementService.install(operation);
     }
 
@@ -111,11 +111,11 @@ public class ApplicationResource {
      *
      * @param operation
      */
-    @POST
+    @DELETE
     @Path("/uninstall")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public ApplicationEntity uninstallApplication(AppOperations.UninstallOperation operation){
+    public ApplicationEntity uninstallApplication(ApplicationOperations.UninstallOperation operation){
         return applicationManagementService.uninstall(operation);
     }
 
@@ -132,7 +132,7 @@ public class ApplicationResource {
     @Path("/start")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public ApplicationEntity startApplication(AppOperations.StartOperation operation){
+    public ApplicationEntity startApplication(ApplicationOperations.StartOperation operation){
         return applicationManagementService.start(operation);
     }
 
@@ -149,7 +149,7 @@ public class ApplicationResource {
     @Path("/stop")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public ApplicationEntity stopApplication(AppOperations.StopOperation operation){
+    public ApplicationEntity stopApplication(ApplicationOperations.StopOperation operation){
         return applicationManagementService.stop(operation);
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/AppOperations.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/AppOperations.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/AppOperations.java
deleted file mode 100644
index f2395d6..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/AppOperations.java
+++ /dev/null
@@ -1,161 +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.metadata.model.ApplicationEntity;
-
-import java.io.Serializable;
-import java.util.Map;
-
-public class AppOperations {
-    interface Operation extends Serializable {
-        //
-    }
-
-    public static class InstallOperation implements Operation{
-        private String siteId;
-        private String appType;
-        private ApplicationEntity.Mode mode = ApplicationEntity.Mode.LOCAL;
-        private Map<String,Object> configuration;
-
-        public InstallOperation(){}
-        public InstallOperation(String siteId,String appType){
-            this.setSiteId(siteId);
-            this.setAppType(appType);
-        }
-        public InstallOperation(String siteId,String appType,ApplicationEntity.Mode mode){
-            this.setSiteId(siteId);
-            this.setAppType(appType);
-            this.setMode(mode);
-        }
-        public InstallOperation(String siteId,String appType,ApplicationEntity.Mode mode,Map<String,Object> configuration){
-            this.setSiteId(siteId);
-            this.setAppType(appType);
-            this.setMode(mode);
-            this.setConfiguration(configuration);
-        }
-
-        public String getSiteId() {
-           return siteId;
-       }
-        public void setSiteId(String siteId) {
-           this.siteId = siteId;
-       }
-        public String getAppType() {
-           return appType;
-       }
-        public void setAppType(String appType) {
-           this.appType = appType;
-       }
-
-        public Map<String, Object> getConfiguration() {
-            return configuration;
-        }
-
-        public void setConfiguration(Map<String, Object> configuration) {
-            this.configuration = configuration;
-        }
-
-        public ApplicationEntity.Mode getMode() {
-            return mode;
-        }
-
-        public void setMode(ApplicationEntity.Mode mode) {
-            this.mode = mode;
-        }
-    }
-
-    public static class UninstallOperation implements Operation{
-        private String uuid;
-        private String appId;
-        public UninstallOperation(String uuid){
-            this.setUuid(uuid);
-        }
-        public UninstallOperation(String uuid,String appId){
-            this.setUuid(uuid);
-            this.setAppId(appId);
-        }
-
-        public String getUuid() {
-            return uuid;
-        }
-        public void setUuid(String uuid) {
-            this.uuid = uuid;
-        }
-
-        public String getAppId() {
-            return appId;
-        }
-
-        public void setAppId(String appId) {
-            this.appId = appId;
-        }
-    }
-
-    public static class StartOperation implements Operation{
-        private String uuid;
-        private String appId;
-        public StartOperation(String uuid){
-            this.setUuid(uuid);
-        }
-        public StartOperation(String uuid,String appId){
-            this.setUuid(uuid);
-            this.setAppId(appId);
-        }
-        public String getUuid() {
-            return uuid;
-        }
-        public void setUuid(String uuid) {
-            this.uuid = uuid;
-        }
-
-        public String getAppId() {
-            return appId;
-        }
-
-        public void setAppId(String appId) {
-            this.appId = appId;
-        }
-    }
-
-    public static class StopOperation implements Operation{
-        private String uuid;
-        private String appId;
-
-        public StopOperation(String uuid){
-            this.setUuid(uuid);
-        }
-        public StopOperation(String uuid,String appId){
-            this.setUuid(uuid);
-            this.setAppId(appId);
-        }
-        public String getUuid() {
-            return uuid;
-        }
-        public void setUuid(String uuid) {
-            this.uuid = uuid;
-        }
-
-        public String getAppId() {
-            return appId;
-        }
-
-        public void setAppId(String appId) {
-            this.appId = appId;
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementService.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementService.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementService.java
index 965a3fa..30ae0b9 100644
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementService.java
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementService.java
@@ -24,26 +24,26 @@ public interface ApplicationManagementService {
      * @param operation
      * @return
      */
-    ApplicationEntity install(AppOperations.InstallOperation operation);
+    ApplicationEntity install(ApplicationOperations.InstallOperation operation);
 
     /**
      *
      * @param operation
      * @return
      */
-    ApplicationEntity uninstall(AppOperations.UninstallOperation operation);
+    ApplicationEntity uninstall(ApplicationOperations.UninstallOperation operation);
 
     /**
      *
      * @param operation
      * @return
      */
-    ApplicationEntity start(AppOperations.StartOperation operation);
+    ApplicationEntity start(ApplicationOperations.StartOperation operation);
 
     /**
      *
      * @param operation
      * @return
      */
-    ApplicationEntity stop(AppOperations.StopOperation operation);
+    ApplicationEntity stop(ApplicationOperations.StopOperation operation);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementServiceImpl.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementServiceImpl.java
deleted file mode 100644
index 566fb62..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationManagementServiceImpl.java
+++ /dev/null
@@ -1,96 +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 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.Application;
-import org.apache.eagle.app.ApplicationContext;
-import org.apache.eagle.metadata.model.ApplicationDesc;
-import org.apache.eagle.metadata.model.ApplicationEntity;
-import org.apache.eagle.metadata.model.SiteEntity;
-import org.apache.eagle.metadata.service.ApplicationEntityService;
-import org.apache.eagle.metadata.service.SiteEntityService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Singleton
-public class ApplicationManagementServiceImpl implements ApplicationManagementService {
-    private final SiteEntityService siteEntityService;
-    private final ApplicationProviderService applicationProviderService;
-    private final ApplicationEntityService applicationEntityService;
-    private final Config config;
-    private final static Logger LOGGER = LoggerFactory.getLogger(ApplicationManagementServiceImpl.class);
-
-    @Inject
-    public ApplicationManagementServiceImpl(
-            Config config,
-            SiteEntityService siteEntityService,
-            ApplicationProviderService applicationProviderService,
-            ApplicationEntityService applicationEntityService){
-        this.config = config;
-        this.siteEntityService = siteEntityService;
-        this.applicationProviderService = applicationProviderService;
-        this.applicationEntityService = applicationEntityService;
-    }
-
-    public ApplicationEntity install(AppOperations.InstallOperation operation) {
-        Preconditions.checkNotNull(operation.getSiteId(),"siteId is null");
-        Preconditions.checkNotNull(operation.getAppType(),"appType is null");
-        SiteEntity siteEntity = siteEntityService.getBySiteId(operation.getSiteId());
-        Preconditions.checkNotNull(siteEntity,"Site with ID: "+operation.getSiteId()+" is not found");
-        ApplicationDesc appDesc = applicationProviderService.getApplicationDescByType(operation.getAppType());
-        Preconditions.checkNotNull("Application with TYPE: "+operation.getAppType()+" is not found");
-        ApplicationEntity applicationEntity = new ApplicationEntity();
-        applicationEntity.setDescriptor(appDesc);
-        applicationEntity.setSite(siteEntity);
-        applicationEntity.setConfiguration(operation.getConfiguration());
-        applicationEntity.setMode(operation.getMode());
-        ApplicationContext applicationContext = new ApplicationContext(applicationEntity,config);
-        applicationEntity.setStreams(applicationContext.getStreamSinkDescs());
-        applicationEntityService.create(applicationEntity);
-        return applicationEntity;
-    }
-
-    public ApplicationEntity uninstall(AppOperations.UninstallOperation operation) {
-        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
-        Application application = applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication();
-        // TODO: Check status, skip stop if already STOPPED
-        try {
-            application.stop(new ApplicationContext(applicationEntity, this.config));
-        }catch (Throwable throwable){
-            LOGGER.error(throwable.getMessage(),throwable);
-        }
-        return applicationEntityService.delete(applicationEntity);
-    }
-
-    public ApplicationEntity start(AppOperations.StartOperation operation) {
-        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
-        Application application = applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication();
-        application.start(new ApplicationContext(applicationEntity,this.config));
-        return applicationEntity;
-    }
-
-    public ApplicationEntity stop(AppOperations.StopOperation operation) {
-        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
-        Application application = applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()).getApplication();
-        application.stop(new ApplicationContext(applicationEntity,this.config));
-        return applicationEntity;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperations.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperations.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperations.java
new file mode 100644
index 0000000..792b7d4
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationOperations.java
@@ -0,0 +1,189 @@
+/**
+ * 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.metadata.model.ApplicationEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public final class ApplicationOperations {
+    interface Operation extends Serializable {
+        String getType();
+    }
+
+    private final static String INSTALL = "INSTALL";
+    private final static String UNINSTALL = "UNINSTALL";
+    private final static String START = "START";
+    private final static String STOP = "STOP";
+
+    public static class InstallOperation implements Operation{
+        private String siteId;
+        private String appType;
+        private ApplicationEntity.Mode mode = ApplicationEntity.Mode.LOCAL;
+        private Map<String,Object> configuration;
+
+        public InstallOperation(){}
+        public InstallOperation(String siteId,String appType){
+            this.setSiteId(siteId);
+            this.setAppType(appType);
+        }
+        public InstallOperation(String siteId,String appType,ApplicationEntity.Mode mode){
+            this.setSiteId(siteId);
+            this.setAppType(appType);
+            this.setMode(mode);
+        }
+        public InstallOperation(String siteId,String appType,ApplicationEntity.Mode mode,Map<String,Object> configuration){
+            this.setSiteId(siteId);
+            this.setAppType(appType);
+            this.setMode(mode);
+            this.setConfiguration(configuration);
+        }
+
+        public String getSiteId() {
+           return siteId;
+       }
+        public void setSiteId(String siteId) {
+           this.siteId = siteId;
+       }
+        public String getAppType() {
+           return appType;
+       }
+        public void setAppType(String appType) {
+           this.appType = appType;
+       }
+
+        public Map<String, Object> getConfiguration() {
+            return configuration;
+        }
+
+        public void setConfiguration(Map<String, Object> configuration) {
+            this.configuration = configuration;
+        }
+
+        public ApplicationEntity.Mode getMode() {
+            return mode;
+        }
+
+        public void setMode(ApplicationEntity.Mode mode) {
+            this.mode = mode;
+        }
+
+        @Override
+        public String getType() {
+            return INSTALL;
+        }
+    }
+
+    public static class UninstallOperation implements Operation{
+        private String uuid;
+        private String appId;
+        public UninstallOperation(){}
+        public UninstallOperation(String uuid){
+            this.setUuid(uuid);
+        }
+        public UninstallOperation(String uuid,String appId){
+            this.setUuid(uuid);
+            this.setAppId(appId);
+        }
+
+        public String getUuid() {
+            return uuid;
+        }
+        public void setUuid(String uuid) {
+            this.uuid = uuid;
+        }
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(String appId) {
+            this.appId = appId;
+        }
+
+        @Override
+        public String getType() {
+            return UNINSTALL;
+        }
+    }
+
+    public static class StartOperation implements Operation{
+        private String uuid;
+        private String appId;
+        public StartOperation(){}
+        public StartOperation(String uuid){
+            this.setUuid(uuid);
+        }
+        public StartOperation(String uuid,String appId){
+            this.setUuid(uuid);
+            this.setAppId(appId);
+        }
+        public String getUuid() {
+            return uuid;
+        }
+        public void setUuid(String uuid) {
+            this.uuid = uuid;
+        }
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(String appId) {
+            this.appId = appId;
+        }
+
+        @Override
+        public String getType() {
+            return START;
+        }
+    }
+
+    public static class StopOperation implements Operation{
+        private String uuid;
+        private String appId;
+
+        public StopOperation(){}
+        public StopOperation(String uuid){
+            this.setUuid(uuid);
+        }
+        public StopOperation(String uuid,String appId){
+            this.setUuid(uuid);
+            this.setAppId(appId);
+        }
+        public String getUuid() {
+            return uuid;
+        }
+        public void setUuid(String uuid) {
+            this.uuid = uuid;
+        }
+
+        public String getAppId() {
+            return appId;
+        }
+
+        public void setAppId(String appId) {
+            this.appId = appId;
+        }
+
+        @Override
+        public String getType() {
+            return STOP;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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 8b98404..85f0709 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
@@ -17,8 +17,8 @@
 package org.apache.eagle.app.service;
 
 import com.typesafe.config.Config;
-import org.apache.eagle.app.service.loader.ApplicationProviderConfigLoader;
-import org.apache.eagle.app.service.loader.ApplicationProviderSPILoader;
+import org.apache.eagle.app.service.impl.ApplicationProviderConfigLoader;
+import org.apache.eagle.app.service.impl.ApplicationProviderSPILoader;
 import org.apache.eagle.app.spi.ApplicationProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderServiceImpl.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderServiceImpl.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderServiceImpl.java
deleted file mode 100644
index 6ce463f..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/ApplicationProviderServiceImpl.java
+++ /dev/null
@@ -1,87 +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 com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.typesafe.config.Config;
-import org.apache.eagle.app.spi.ApplicationProvider;
-import org.apache.eagle.metadata.model.ApplicationDesc;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * Support to load application provider from application.provider.config = "providers.xml" configuration file
- * or application.provider.dir = "lib/apps" with SPI Class loader
- *
- * TODO: hot-manage application provider loading
- */
-@Singleton
-public class ApplicationProviderServiceImpl implements ApplicationProviderService {
-    private final Config config;
-    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderServiceImpl.class);
-    private final ApplicationProviderLoader appProviderLoader;
-    public final static String APP_PROVIDER_LOADER_CLASS_KEY = "application.provider.loader";
-
-    @Inject
-    public ApplicationProviderServiceImpl(Config config){
-        LOG.info("Initializing {}",this.getClass().getCanonicalName());
-        this.config = config;
-        String appProviderLoaderClass = this.config.hasPath(APP_PROVIDER_LOADER_CLASS_KEY)?
-                this.config.getString(APP_PROVIDER_LOADER_CLASS_KEY):ApplicationProviderLoader.getDefaultAppProviderLoader();
-        LOG.info("Initializing {} = {}",APP_PROVIDER_LOADER_CLASS_KEY,appProviderLoaderClass);
-        appProviderLoader = initializeAppProviderLoader(appProviderLoaderClass);
-        LOG.info("Initialized {}",appProviderLoader);
-        reload();
-    }
-
-    private ApplicationProviderLoader initializeAppProviderLoader(String appProviderLoaderClass){
-        try {
-            return (ApplicationProviderLoader) Class.forName(appProviderLoaderClass).getConstructor(Config.class).newInstance(this.config);
-        } catch (Throwable e) {
-            LOG.error("Failed to initialize ApplicationProviderLoader: "+appProviderLoaderClass,e);
-            throw new IllegalStateException("Failed to initialize ApplicationProviderLoader: "+appProviderLoaderClass,e);
-        }
-    }
-
-    public synchronized void reload(){
-        appProviderLoader.reset();
-        LOG.info("Loading application providers ...");
-        appProviderLoader.load();
-        LOG.info("Loaded {} application providers",appProviderLoader.getProviders().size());
-    }
-
-    public Collection<ApplicationProvider> getProviders(){
-        return appProviderLoader.getProviders();
-    }
-
-    public Collection<ApplicationDesc> getApplicationDescs(){
-        return getProviders().stream().map(ApplicationProvider::getApplicationDesc).collect(Collectors.toList());
-    }
-
-    public ApplicationProvider<?> getApplicationProviderByType(String type) {
-        return appProviderLoader.getApplicationProviderByType(type);
-    }
-
-    @Deprecated
-    public ApplicationDesc getApplicationDescByType(String appType) {
-        return appProviderLoader.getApplicationProviderByType(appType).getApplicationDesc();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
new file mode 100644
index 0000000..9e34459
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationManagementServiceImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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.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.ApplicationContext;
+import org.apache.eagle.app.service.ApplicationOperations;
+import org.apache.eagle.app.service.ApplicationManagementService;
+import org.apache.eagle.app.service.ApplicationProviderService;
+import org.apache.eagle.metadata.model.ApplicationDesc;
+import org.apache.eagle.metadata.model.ApplicationEntity;
+import org.apache.eagle.metadata.model.SiteEntity;
+import org.apache.eagle.metadata.service.ApplicationEntityService;
+import org.apache.eagle.metadata.service.SiteEntityService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class ApplicationManagementServiceImpl implements ApplicationManagementService {
+    private final SiteEntityService siteEntityService;
+    private final ApplicationProviderService applicationProviderService;
+    private final ApplicationEntityService applicationEntityService;
+    private final Config config;
+    private final static Logger LOGGER = LoggerFactory.getLogger(ApplicationManagementServiceImpl.class);
+
+    @Inject
+    public ApplicationManagementServiceImpl(
+            Config config,
+            SiteEntityService siteEntityService,
+            ApplicationProviderService applicationProviderService,
+            ApplicationEntityService applicationEntityService){
+        this.config = config;
+        this.siteEntityService = siteEntityService;
+        this.applicationProviderService = applicationProviderService;
+        this.applicationEntityService = applicationEntityService;
+    }
+
+    public ApplicationEntity install(ApplicationOperations.InstallOperation operation) {
+        Preconditions.checkNotNull(operation.getSiteId(),"siteId is null");
+        Preconditions.checkNotNull(operation.getAppType(),"appType is null");
+        SiteEntity siteEntity = siteEntityService.getBySiteId(operation.getSiteId());
+        Preconditions.checkNotNull(siteEntity,"Site with ID: "+operation.getSiteId()+" is not found");
+        ApplicationDesc appDesc = applicationProviderService.getApplicationDescByType(operation.getAppType());
+        Preconditions.checkNotNull("Application with TYPE: "+operation.getAppType()+" is not found");
+        ApplicationEntity applicationEntity = new ApplicationEntity();
+        applicationEntity.setDescriptor(appDesc);
+        applicationEntity.setSite(siteEntity);
+        applicationEntity.setConfiguration(operation.getConfiguration());
+        applicationEntity.setMode(operation.getMode());
+        ApplicationContext applicationContext = new ApplicationContext(applicationEntity,applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()),config);
+        applicationEntity.setStreams(applicationContext.getStreamSinkDescs());
+        applicationContext.onAppInstall();
+        applicationEntityService.create(applicationEntity);
+        return applicationEntity;
+    }
+
+    public ApplicationEntity uninstall(ApplicationOperations.UninstallOperation operation) {
+        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
+        ApplicationContext applicationContext = new ApplicationContext(applicationEntity,applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()),config);
+        // TODO: Check status, skip stop if already STOPPED
+        try {
+            applicationContext.onAppStop();
+        }catch (Throwable throwable){
+            LOGGER.error(throwable.getMessage(),throwable);
+        }
+        applicationContext.onAppUninstall();
+        return applicationEntityService.delete(applicationEntity);
+    }
+
+    public ApplicationEntity start(ApplicationOperations.StartOperation operation) {
+        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
+        new ApplicationContext(applicationEntity,applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()),this.config).onAppStart();
+        return applicationEntity;
+    }
+
+    public ApplicationEntity stop(ApplicationOperations.StopOperation operation) {
+        ApplicationEntity applicationEntity = applicationEntityService.getByUUIDOrAppId(operation.getUuid(),operation.getAppId());
+        new ApplicationContext(applicationEntity,applicationProviderService.getApplicationProviderByType(applicationEntity.getDescriptor().getType()),this.config).onAppStop();
+        return applicationEntity;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
new file mode 100644
index 0000000..3b2bca9
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderConfigLoader.java
@@ -0,0 +1,128 @@
+/**
+ * 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.impl;
+
+import com.google.common.base.Preconditions;
+import com.typesafe.config.Config;
+import org.apache.eagle.app.config.ApplicationProviderConfig;
+import org.apache.eagle.app.config.ApplicationProvidersConfig;
+import org.apache.eagle.app.service.ApplicationProviderLoader;
+import org.apache.eagle.app.spi.ApplicationProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+public class ApplicationProviderConfigLoader extends ApplicationProviderLoader {
+    public final static String DEFAULT_APPLICATIONS_CONFIG_FILE = "providers.xml";
+    private final static String APPLICATIONS_CONFIG_PROPS_KEY = "application.provider.config";
+    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderConfigLoader.class);
+    public ApplicationProviderConfigLoader(Config config) {
+        super(config);
+    }
+
+    @Override
+    public void load() {
+        List<ApplicationProviderConfig> applicationProviderConfigs = loadProvidersFromProvidersConf();
+        int totalCount = applicationProviderConfigs.size();
+        int loadedCount = 0,failedCount = 0;
+        for(ApplicationProviderConfig providerConfig: applicationProviderConfigs){
+            try {
+                initializeProvider(providerConfig);
+                loadedCount ++;
+            }catch (Throwable ex){
+                LOG.warn("Failed to initialized {}, ignored",providerConfig,ex);
+                failedCount ++;
+            }
+        }
+        LOG.info("Loaded {} app providers (total: {}, failed: {})",loadedCount,totalCount,failedCount);
+    }
+
+    public static boolean appProviderConfExists(String applicationConfFile){
+        InputStream is = ApplicationProviderConfigLoader.class.getResourceAsStream(applicationConfFile);
+        if(is == null){
+            is = ApplicationProviderConfigLoader.class.getResourceAsStream("/"+applicationConfFile);
+        }
+
+        if(is != null){
+            try {
+                return true;
+            } finally {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    LOG.debug(e.getMessage());
+                }
+            }
+        } else {
+            return false;
+        }
+    }
+
+    private void initializeProvider(ApplicationProviderConfig providerConfig) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        LOG.info("Loading application provider {} from {}",providerConfig.getClassName(),providerConfig.getJarPath());
+        String providerClassName = providerConfig.getClassName();
+        if(providerClassName == null) throw new RuntimeException("provider.classname is null: "+providerConfig);
+        if(providerConfig.getJarPath() == null) throw new RuntimeException("provider.jarpath is null: "+providerConfig);
+
+        Class<?> providerClass = Class.forName(providerClassName);
+
+        if(!ApplicationProvider.class.isAssignableFrom(providerClass)){
+            throw new RuntimeException("providerClassName is not implementation of "+ApplicationProvider.class.getCanonicalName());
+        }
+        ApplicationProvider provider = (ApplicationProvider) providerClass.newInstance();
+        provider.prepare(providerConfig,this.getConfig());
+        Preconditions.checkNotNull(provider.getApplicationDesc(),"appDesc is null");
+        Preconditions.checkNotNull(provider.getApplicationDesc().getType(),"type is null");
+        registerProvider(provider);
+    }
+
+    private List<ApplicationProviderConfig> loadProvidersFromProvidersConf() {
+        String providerConfigFile = DEFAULT_APPLICATIONS_CONFIG_FILE;
+        if(getConfig().hasPath(APPLICATIONS_CONFIG_PROPS_KEY)){
+            providerConfigFile = getConfig().getString(APPLICATIONS_CONFIG_PROPS_KEY);
+            LOG.info("Set {} = {}",APPLICATIONS_CONFIG_PROPS_KEY,providerConfigFile);
+        }
+        InputStream is = null;
+        try {
+            JAXBContext jc = JAXBContext.newInstance(ApplicationProvidersConfig.class);
+            Unmarshaller unmarshaller = jc.createUnmarshaller();
+            is = ApplicationProviderConfigLoader.class.getResourceAsStream(providerConfigFile);
+            if(is == null){
+                is = ApplicationProviderConfigLoader.class.getResourceAsStream("/"+providerConfigFile);
+            }
+            if(is == null){
+                LOG.error("Application provider configuration {} is not found",providerConfigFile);
+            }
+            Preconditions.checkNotNull(is,providerConfigFile+" is not found");
+            return ((ApplicationProvidersConfig) unmarshaller.unmarshal(is)).getProviders();
+        }catch (Exception ex){
+            LOG.error("Failed to load application provider configuration: {}",providerConfigFile,ex);
+            throw new RuntimeException("Failed to load application provider configuration: "+providerConfigFile,ex);
+        } finally {
+            if(is != null) try {
+                is.close();
+            } catch (IOException e) {
+                LOG.error(e.getMessage(),e);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
new file mode 100644
index 0000000..3304286
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderSPILoader.java
@@ -0,0 +1,89 @@
+/**
+ * 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.impl;
+
+import com.typesafe.config.Config;
+import org.apache.eagle.app.config.ApplicationProviderConfig;
+import org.apache.eagle.app.service.ApplicationProviderLoader;
+import org.apache.eagle.app.spi.ApplicationProvider;
+import org.apache.eagle.app.tools.DynamicJarPathFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ServiceLoader;
+import java.util.function.Function;
+
+public class ApplicationProviderSPILoader extends ApplicationProviderLoader{
+    private final String appProviderExtDir;
+    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderSPILoader.class);
+    private final static String APPLICATIONS_DIR_PROPS_KEY = "application.provider.dir";
+
+    public ApplicationProviderSPILoader(Config config) {
+        super(config);
+        if(config.hasPath(APPLICATIONS_DIR_PROPS_KEY)) {
+            this.appProviderExtDir = config.getString(APPLICATIONS_DIR_PROPS_KEY);
+        }else{
+            this.appProviderExtDir = null;
+        }
+
+        LOG.info("Using {}: {}",APPLICATIONS_DIR_PROPS_KEY,this.appProviderExtDir);
+
+    }
+
+    @Override
+    public void load() {
+        if(appProviderExtDir != null) {
+            LOG.info("Loading application providers from class loader of jars in {}", appProviderExtDir);
+            File loc = new File(appProviderExtDir);
+            File[] jarFiles = loc.listFiles(file -> file.getPath().toLowerCase().endsWith(".jar"));
+            if (jarFiles != null) {
+                for (File jarFile : jarFiles) {
+                    try {
+                        URL jarFileUrl = jarFile.toURI().toURL();
+                        LOG.debug("Loading ApplicationProvider from jar: {}", jarFileUrl.toString());
+                        URLClassLoader jarFileClassLoader = new URLClassLoader(new URL[]{jarFileUrl});
+                        loadProviderFromClassLoader(jarFileClassLoader, (applicationProviderConfig) -> jarFileUrl.getPath());
+                    } catch (Exception e) {
+                        LOG.warn("Failed to load application provider from jar {}", jarFile,e);
+                    }
+                }
+            }
+        } else {
+            LOG.info("Loading application providers from context class loader");
+            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+            loadProviderFromClassLoader(classLoader,(applicationProviderConfig) -> DynamicJarPathFinder.findPath(applicationProviderConfig.getClass()));
+        }
+    }
+
+    private void loadProviderFromClassLoader(ClassLoader jarFileClassLoader, Function<ApplicationProviderConfig,String> jarFileSupplier){
+        ServiceLoader<ApplicationProvider> serviceLoader = ServiceLoader.load(ApplicationProvider.class, jarFileClassLoader);
+        for (ApplicationProvider applicationProvider : serviceLoader) {
+            try {
+                ApplicationProviderConfig providerConfig = new ApplicationProviderConfig();
+                providerConfig.setClassName(applicationProvider.getClass().getCanonicalName());
+                providerConfig.setJarPath(jarFileSupplier.apply(providerConfig));
+                applicationProvider.prepare(providerConfig, getConfig());
+                registerProvider(applicationProvider);
+            }catch (Throwable ex){
+                LOG.warn("Failed to register application provider {}",applicationProvider,ex);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/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
new file mode 100644
index 0000000..2297ea5
--- /dev/null
+++ b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/impl/ApplicationProviderServiceImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.impl;
+
+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.ApplicationDesc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Support to load application provider from application.provider.config = "providers.xml" configuration file
+ * or application.provider.dir = "lib/apps" with SPI Class loader
+ *
+ * TODO: hot-manage application provider loading
+ */
+@Singleton
+public class ApplicationProviderServiceImpl implements ApplicationProviderService {
+    private final Config config;
+    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderServiceImpl.class);
+    private final ApplicationProviderLoader appProviderLoader;
+    public final static String APP_PROVIDER_LOADER_CLASS_KEY = "application.provider.loader";
+
+    @Inject
+    public ApplicationProviderServiceImpl(Config config){
+        LOG.info("Initializing {}",this.getClass().getCanonicalName());
+        this.config = config;
+        String appProviderLoaderClass = this.config.hasPath(APP_PROVIDER_LOADER_CLASS_KEY)?
+                this.config.getString(APP_PROVIDER_LOADER_CLASS_KEY):ApplicationProviderLoader.getDefaultAppProviderLoader();
+        LOG.info("Initializing {} = {}",APP_PROVIDER_LOADER_CLASS_KEY,appProviderLoaderClass);
+        appProviderLoader = initializeAppProviderLoader(appProviderLoaderClass);
+        LOG.info("Initialized {}",appProviderLoader);
+        reload();
+    }
+
+    private ApplicationProviderLoader initializeAppProviderLoader(String appProviderLoaderClass){
+        try {
+            return (ApplicationProviderLoader) Class.forName(appProviderLoaderClass).getConstructor(Config.class).newInstance(this.config);
+        } catch (Throwable e) {
+            LOG.error("Failed to initialize ApplicationProviderLoader: "+appProviderLoaderClass,e);
+            throw new IllegalStateException("Failed to initialize ApplicationProviderLoader: "+appProviderLoaderClass,e);
+        }
+    }
+
+    public synchronized void reload(){
+        appProviderLoader.reset();
+        LOG.info("Loading application providers ...");
+        appProviderLoader.load();
+        LOG.info("Loaded {} application providers",appProviderLoader.getProviders().size());
+    }
+
+    public Collection<ApplicationProvider> getProviders(){
+        return appProviderLoader.getProviders();
+    }
+
+    public Collection<ApplicationDesc> getApplicationDescs(){
+        return getProviders().stream().map(ApplicationProvider::getApplicationDesc).collect(Collectors.toList());
+    }
+
+    public ApplicationProvider<?> getApplicationProviderByType(String type) {
+        return appProviderLoader.getApplicationProviderByType(type);
+    }
+
+    @Deprecated
+    public ApplicationDesc getApplicationDescByType(String appType) {
+        return appProviderLoader.getApplicationProviderByType(appType).getApplicationDesc();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderConfigLoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderConfigLoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderConfigLoader.java
deleted file mode 100644
index 11d9905..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderConfigLoader.java
+++ /dev/null
@@ -1,128 +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.loader;
-
-import com.google.common.base.Preconditions;
-import com.typesafe.config.Config;
-import org.apache.eagle.app.config.ApplicationProviderConfig;
-import org.apache.eagle.app.config.ApplicationProvidersConfig;
-import org.apache.eagle.app.service.ApplicationProviderLoader;
-import org.apache.eagle.app.spi.ApplicationProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.Unmarshaller;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-public class ApplicationProviderConfigLoader extends ApplicationProviderLoader {
-    public final static String DEFAULT_APPLICATIONS_CONFIG_FILE = "providers.xml";
-    private final static String APPLICATIONS_CONFIG_PROPS_KEY = "application.provider.config";
-    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderConfigLoader.class);
-    public ApplicationProviderConfigLoader(Config config) {
-        super(config);
-    }
-
-    @Override
-    public void load() {
-        List<ApplicationProviderConfig> applicationProviderConfigs = loadProvidersFromProvidersConf();
-        int totalCount = applicationProviderConfigs.size();
-        int loadedCount = 0,failedCount = 0;
-        for(ApplicationProviderConfig providerConfig: applicationProviderConfigs){
-            try {
-                initializeProvider(providerConfig);
-                loadedCount ++;
-            }catch (Throwable ex){
-                LOG.warn("Failed to initialized {}, ignored",providerConfig,ex);
-                failedCount ++;
-            }
-        }
-        LOG.info("Loaded {} app providers (total: {}, failed: {})",loadedCount,totalCount,failedCount);
-    }
-
-    public static boolean appProviderConfExists(String applicationConfFile){
-        InputStream is = ApplicationProviderConfigLoader.class.getResourceAsStream(applicationConfFile);
-        if(is == null){
-            is = ApplicationProviderConfigLoader.class.getResourceAsStream("/"+applicationConfFile);
-        }
-
-        if(is != null){
-            try {
-                return true;
-            } finally {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    LOG.debug(e.getMessage());
-                }
-            }
-        } else {
-            return false;
-        }
-    }
-
-    private void initializeProvider(ApplicationProviderConfig providerConfig) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        LOG.info("Loading application provider {} from {}",providerConfig.getClassName(),providerConfig.getJarPath());
-        String providerClassName = providerConfig.getClassName();
-        if(providerClassName == null) throw new RuntimeException("provider.classname is null: "+providerConfig);
-        if(providerConfig.getJarPath() == null) throw new RuntimeException("provider.jarpath is null: "+providerConfig);
-
-        Class<?> providerClass = Class.forName(providerClassName);
-
-        if(!ApplicationProvider.class.isAssignableFrom(providerClass)){
-            throw new RuntimeException("providerClassName is not implementation of "+ApplicationProvider.class.getCanonicalName());
-        }
-        ApplicationProvider provider = (ApplicationProvider) providerClass.newInstance();
-        provider.prepare(providerConfig,this.getConfig());
-        Preconditions.checkNotNull(provider.getApplicationDesc(),"appDesc is null");
-        Preconditions.checkNotNull(provider.getApplicationDesc().getType(),"type is null");
-        registerProvider(provider);
-    }
-
-    private List<ApplicationProviderConfig> loadProvidersFromProvidersConf() {
-        String providerConfigFile = DEFAULT_APPLICATIONS_CONFIG_FILE;
-        if(getConfig().hasPath(APPLICATIONS_CONFIG_PROPS_KEY)){
-            providerConfigFile = getConfig().getString(APPLICATIONS_CONFIG_PROPS_KEY);
-            LOG.info("Set {} = {}",APPLICATIONS_CONFIG_PROPS_KEY,providerConfigFile);
-        }
-        InputStream is = null;
-        try {
-            JAXBContext jc = JAXBContext.newInstance(ApplicationProvidersConfig.class);
-            Unmarshaller unmarshaller = jc.createUnmarshaller();
-            is = ApplicationProviderConfigLoader.class.getResourceAsStream(providerConfigFile);
-            if(is == null){
-                is = ApplicationProviderConfigLoader.class.getResourceAsStream("/"+providerConfigFile);
-            }
-            if(is == null){
-                LOG.error("Application provider configuration {} is not found",providerConfigFile);
-            }
-            Preconditions.checkNotNull(is,providerConfigFile+" is not found");
-            return ((ApplicationProvidersConfig) unmarshaller.unmarshal(is)).getProviders();
-        }catch (Exception ex){
-            LOG.error("Failed to load application provider configuration: {}",providerConfigFile,ex);
-            throw new RuntimeException("Failed to load application provider configuration: "+providerConfigFile,ex);
-        } finally {
-            if(is != null) try {
-                is.close();
-            } catch (IOException e) {
-                LOG.error(e.getMessage(),e);
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-eagle/blob/e73e35da/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderSPILoader.java
----------------------------------------------------------------------
diff --git a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderSPILoader.java b/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderSPILoader.java
deleted file mode 100644
index 33cb401..0000000
--- a/eagle-core/eagle-app/eagle-app-base/src/main/java/org/apache/eagle/app/service/loader/ApplicationProviderSPILoader.java
+++ /dev/null
@@ -1,89 +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.loader;
-
-import com.typesafe.config.Config;
-import org.apache.eagle.app.config.ApplicationProviderConfig;
-import org.apache.eagle.app.service.ApplicationProviderLoader;
-import org.apache.eagle.app.spi.ApplicationProvider;
-import org.apache.eagle.app.tools.DynamicJarPathFinder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ServiceLoader;
-import java.util.function.Function;
-
-public class ApplicationProviderSPILoader extends ApplicationProviderLoader{
-    private final String appProviderExtDir;
-    private final static Logger LOG = LoggerFactory.getLogger(ApplicationProviderSPILoader.class);
-    private final static String APPLICATIONS_DIR_PROPS_KEY = "application.provider.dir";
-
-    public ApplicationProviderSPILoader(Config config) {
-        super(config);
-        if(config.hasPath(APPLICATIONS_DIR_PROPS_KEY)) {
-            this.appProviderExtDir = config.getString(APPLICATIONS_DIR_PROPS_KEY);
-        }else{
-            this.appProviderExtDir = null;
-        }
-
-        LOG.info("Using {}: {}",APPLICATIONS_DIR_PROPS_KEY,this.appProviderExtDir);
-
-    }
-
-    @Override
-    public void load() {
-        if(appProviderExtDir != null) {
-            LOG.info("Loading application providers from class loader of jars in {}", appProviderExtDir);
-            File loc = new File(appProviderExtDir);
-            File[] jarFiles = loc.listFiles(file -> file.getPath().toLowerCase().endsWith(".jar"));
-            if (jarFiles != null) {
-                for (File jarFile : jarFiles) {
-                    try {
-                        URL jarFileUrl = jarFile.toURI().toURL();
-                        LOG.debug("Loading ApplicationProvider from jar: {}", jarFileUrl.toString());
-                        URLClassLoader jarFileClassLoader = new URLClassLoader(new URL[]{jarFileUrl});
-                        loadProviderFromClassLoader(jarFileClassLoader, (applicationProviderConfig) -> jarFileUrl.getPath());
-                    } catch (Exception e) {
-                        LOG.warn("Failed to load application provider from jar {}", jarFile,e);
-                    }
-                }
-            }
-        } else {
-            LOG.info("Loading application providers from context class loader");
-            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-            loadProviderFromClassLoader(classLoader,(applicationProviderConfig) -> DynamicJarPathFinder.findPath(applicationProviderConfig.getClass()));
-        }
-    }
-
-    private void loadProviderFromClassLoader(ClassLoader jarFileClassLoader, Function<ApplicationProviderConfig,String> jarFileSupplier){
-        ServiceLoader<ApplicationProvider> serviceLoader = ServiceLoader.load(ApplicationProvider.class, jarFileClassLoader);
-        for (ApplicationProvider applicationProvider : serviceLoader) {
-            try {
-                ApplicationProviderConfig providerConfig = new ApplicationProviderConfig();
-                providerConfig.setClassName(applicationProvider.getClass().getCanonicalName());
-                providerConfig.setJarPath(jarFileSupplier.apply(providerConfig));
-                applicationProvider.prepare(providerConfig, getConfig());
-                registerProvider(applicationProvider);
-            }catch (Throwable ex){
-                LOG.warn("Failed to register application provider {}",applicationProvider,ex);
-            }
-        }
-    }
-}