You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by tb...@apache.org on 2014/01/29 20:40:15 UTC

[2/2] git commit: AMBARI-4461 - Application Views Infrastructure and allowing new views and API extensibility - framework

AMBARI-4461 - Application Views Infrastructure and allowing new views and API extensibility - framework


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

Branch: refs/heads/trunk
Commit: a0a10fc5a98e16b8aec4717dc28af32c9f860d0e
Parents: ea420ff
Author: tbeerbower <tb...@hortonworks.com>
Authored: Wed Jan 29 12:39:29 2014 -0500
Committer: tbeerbower <tb...@hortonworks.com>
Committed: Wed Jan 29 14:38:33 2014 -0500

----------------------------------------------------------------------
 .../resources/ResourceInstanceFactoryImpl.java  |  37 ++
 .../ViewInstanceResourceDefinition.java         |  63 +++
 .../api/resources/ViewResourceDefinition.java   |  58 +++
 .../api/services/ViewInstanceService.java       | 237 ++++++++++++
 .../ambari/server/api/services/ViewService.java | 161 ++++++++
 .../api/services/ViewSubResourceService.java    |  86 +++++
 .../server/configuration/Configuration.java     |  12 +
 .../ambari/server/controller/AmbariServer.java  |  10 +-
 .../internal/DefaultProviderModule.java         |   4 +
 .../internal/ViewInstanceResourceProvider.java  | 153 ++++++++
 .../internal/ViewResourceProvider.java          | 150 ++++++++
 .../ambari/server/controller/spi/Resource.java  |   6 +-
 .../utilities/ClusterControllerHelper.java      |   3 +-
 .../ambari/server/view/ViewContextImpl.java     | 141 +++++++
 .../ambari/server/view/ViewDefinition.java      | 209 ++++++++++
 .../server/view/ViewInstanceDefinition.java     | 198 ++++++++++
 .../ambari/server/view/ViewProviderModule.java  | 100 +++++
 .../apache/ambari/server/view/ViewRegistry.java | 384 +++++++++++++++++++
 .../server/view/ViewSubResourceDefinition.java  | 101 +++++
 .../server/view/ViewSubResourceProvider.java    | 338 ++++++++++++++++
 .../ViewInstanceResourceDefinitionTest.java     |  65 ++++
 .../resources/ViewResourceDefinitionTest.java   |  51 +++
 .../ambari/server/view/ViewContextImplTest.java |  92 +++++
 .../ambari/server/view/ViewDefinitionTest.java  | 155 ++++++++
 .../server/view/ViewInstanceDefinitionTest.java | 127 ++++++
 .../ambari/server/view/ViewRegistryTest.java    |  99 +++++
 .../view/ViewSubResourceDefinitionTest.java     |  68 ++++
 .../apache/ambari/view/URLStreamProvider.java   |  40 ++
 .../org/apache/ambari/view/ViewContext.java     |   7 +
 29 files changed, 3149 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index de6307c..7dcaccb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -22,14 +22,25 @@ package org.apache.ambari.server.api.resources;
 import org.apache.ambari.server.api.query.QueryImpl;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
+import org.apache.ambari.server.view.ViewRegistry;
 
+import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Factory for creating resource instances.
  */
 public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
 
+
+  /**
+   * Map of external resource definitions (added through views).
+   */
+  private final static Map<Resource.Type, ResourceDefinition> resourceDefinitions =
+      new HashMap<Resource.Type, ResourceDefinition>();
+
+
   @Override
   public ResourceInstance createResource(Resource.Type type, Map<Resource.Type, String> mapIds) {
 
@@ -42,6 +53,16 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
   }
 
   /**
+   * Associate an external resource definition with a type.
+   *
+   * @param type        the resource type
+   * @param definition  the resource definition
+   */
+  public static void addResourceDefinition(Resource.Type type, ResourceDefinition definition) {
+    resourceDefinitions.put(type, definition);
+  }
+
+  /**
    * Get a resource definition for the given type.
    *
    * @param type    the resource type
@@ -52,6 +73,11 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
   public static ResourceDefinition getResourceDefinition(Resource.Type type, Map<Resource.Type, String> mapIds) {
     ResourceDefinition resourceDefinition;
 
+    // Check to see if there is an external resource definition registered for the given type.
+    if (resourceDefinitions.containsKey(type)) {
+      return resourceDefinitions.get(type);
+    }
+
     //todo: consider ResourceDependencyManager : Map<Resource.Type, ResourceDefinition>
     switch (type.getInternalType()) {
       case Cluster:
@@ -167,6 +193,17 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
         resourceDefinition = new RequestScheduleResourceDefinition();
         break;
 
+      case View:
+        resourceDefinition = new ViewResourceDefinition();
+        break;
+
+      case ViewInstance:
+        Set<SubResourceDefinition> subResourceDefinitions =
+            ViewRegistry.getInstance().getSubResourceDefinitions(mapIds.get(Resource.Type.View));
+
+        resourceDefinition = new ViewInstanceResourceDefinition(subResourceDefinitions);
+        break;
+
       default:
         throw new IllegalArgumentException("Unsupported resource type: " + type);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinition.java
new file mode 100644
index 0000000..00b4264
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinition.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Set;
+
+
+/**
+ * View instance resource definition.
+ */
+public class ViewInstanceResourceDefinition extends BaseResourceDefinition {
+
+  /**
+   * The parent view name.
+   */
+  private final Set<SubResourceDefinition> subResourceDefinitions;
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view instance resource definition.
+   */
+  public ViewInstanceResourceDefinition(Set<SubResourceDefinition> subResourceDefinitions) {
+    super(Resource.Type.ViewInstance);
+    this.subResourceDefinitions = subResourceDefinitions;
+  }
+
+
+  // ----- ResourceDefinition ------------------------------------------------
+
+  @Override
+  public String getPluralName() {
+    return "instances";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "instance";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    return subResourceDefinitions;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewResourceDefinition.java
new file mode 100644
index 0000000..a068183
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewResourceDefinition.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Collections;
+import java.util.Set;
+
+
+/**
+ * View resource definition.
+ */
+public class ViewResourceDefinition extends BaseResourceDefinition {
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view resource definition.
+   */
+  public ViewResourceDefinition() {
+    super(Resource.Type.View);
+  }
+
+
+  // ----- ResourceDefinition ------------------------------------------------
+
+  @Override
+  public String getPluralName() {
+    return "views";
+  }
+
+  @Override
+  public String getSingularName() {
+    return "view";
+  }
+
+  @Override
+  public Set<SubResourceDefinition> getSubResourceDefinitions() {
+    return Collections.singleton(new SubResourceDefinition(Resource.Type.ViewInstance));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
new file mode 100644
index 0000000..96bc863
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
@@ -0,0 +1,237 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.ViewInstanceDefinition;
+import org.apache.ambari.server.view.ViewRegistry;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Service responsible for instances resource requests.
+ */
+public class ViewInstanceService extends BaseService {
+  /**
+   * Parent view name.
+   */
+  private String m_viewName;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view instance service.
+   *
+   * @param viewName  the view id
+   */
+  public ViewInstanceService(String viewName) {
+    m_viewName = viewName;
+  }
+
+  /**
+   * Handles URL: /views/{viewID}/instances/{instanceID}
+   * Get a specific instance.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param instanceName  instance id
+   *
+   * @return instance resource representation
+   */
+  @GET
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  public Response getService(@Context HttpHeaders headers, @Context UriInfo ui,
+                             @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET,
+        createServiceResource(m_viewName, instanceName));
+  }
+
+  /**
+   * Handles URL: /views/{viewID}/instances
+   * Get all instances for a view.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return instance collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getServices(@Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET,
+        createServiceResource(m_viewName, null));
+  }
+
+  /**
+   * Handles: POST /views/{viewID}/instances/{instanceId}
+   * Create a specific instance.
+   *
+   * @param body          http body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param instanceName  instance id
+   *
+   * @return information regarding the created instance
+   */
+  @POST
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createServiceResource(m_viewName, instanceName));
+  }
+
+  /**
+   * Handles: POST /views/{viewID}/instances
+   * Create multiple instances.
+   *
+   * @param body     http body
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return information regarding the created instances
+   */
+  @POST
+  @Produces("text/plain")
+  public Response createServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST,
+        createServiceResource(m_viewName, null));
+  }
+
+  /**
+   * Handles: PUT /views/{viewID}/instances/{instanceId}
+   * Update a specific instance.
+   *
+   * @param body          http body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param instanceName  instance id
+   *
+   * @return information regarding the updated instance
+   */
+  @PUT
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  public Response updateService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createServiceResource(m_viewName, instanceName));
+  }
+
+  /**
+   * Handles: PUT /views/{viewID}/instances
+   * Update multiple instances.
+   *
+   * @param body     http body
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return information regarding the updated instance
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response updateServices(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createServiceResource(m_viewName, null));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewID}/instances/{instanceId}
+   * Delete a specific instance.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param instanceName  instance id
+   *
+   * @return information regarding the deleted instance
+   */
+  @DELETE
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createServiceResource(m_viewName, instanceName));
+  }
+
+  /**
+   * Get the sub-resource
+   *
+   * @param instanceName  the instance id
+   *
+   * @return the service
+   */
+  @Path("{instanceName}/{resources}")
+  public Object getResourceHandler(@PathParam("instanceName") String instanceName,
+                                            @PathParam("resources") String resources) {
+
+    ViewInstanceDefinition instanceDefinition =
+        ViewRegistry.getInstance().getInstanceDefinition(m_viewName, instanceName);
+
+    if (instanceDefinition == null) {
+      throw new IllegalArgumentException("A view instance " +
+          m_viewName + "/" + instanceName + " can not be found.");
+    }
+
+    Object service = instanceDefinition.getService(resources);
+
+    if (service == null) {
+      throw new IllegalArgumentException("A resource type " + resources + " for view instance " +
+          m_viewName + "/" + instanceName + " can not be found.");
+    }
+    return service;
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create an view instance resource.
+   *
+   * @param viewName      view name
+   * @param instanceName  instance name
+   *
+   * @return a view instance resource
+   */
+  private ResourceInstance createServiceResource(String viewName, String instanceName) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+    return createResource(Resource.Type.ViewInstance, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
new file mode 100644
index 0000000..45d7d2f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
@@ -0,0 +1,161 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+
+
+/**
+ * Service responsible for view resource requests.
+ */
+@Path("/views/")
+public class ViewService extends BaseService {
+
+  /**
+   * Handles: GET /views/{viewID}
+   * Get a specific view.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   *
+   * @return view instance representation
+   */
+  @GET
+  @Path("{viewName}")
+  @Produces("text/plain")
+  public Response getView(@Context HttpHeaders headers, @Context UriInfo ui,
+                             @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET, createViewResource(viewName));
+  }
+
+  /**
+   * Handles: GET  /views
+   * Get all views.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return view collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getViews(@Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createViewResource(null));
+  }
+
+  /**
+   * Handles: POST /views/{viewID}
+   * Create a specific view.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   *
+   * @return information regarding the created view
+   */
+  @POST
+  @Path("{viewName}")
+  @Produces("text/plain")
+  public Response createView(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createViewResource(viewName));
+  }
+
+  /**
+   * Handles: PUT /views/{viewID}
+   * Update a specific view.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param viewName  view id
+   *
+   * @return information regarding the updated view
+   */
+  @PUT
+  @Path("{viewName}")
+  @Produces("text/plain")
+  public Response updateView(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createViewResource(viewName));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewID}
+   * Delete a specific view.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param viewName  view id
+   *
+   * @return information regarding the deleted view
+   */
+  @DELETE
+  @Path("{viewName}")
+  @Produces("text/plain")
+  public Response deleteView(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createViewResource(viewName));
+  }
+
+  /**
+   * Get the instances sub-resource
+   *
+   * @param viewName  view id
+   *
+   * @return the hosts service
+   */
+  @Path("{viewName}/instances")
+  public ViewInstanceService getInstanceHandler(@PathParam("viewName") String viewName) {
+    return new ViewInstanceService(viewName);
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a view resource.
+   *
+   * @param viewName view name
+   *
+   * @return a view resource instance
+   */
+  private ResourceInstance createViewResource(String viewName) {
+    return createResource(Resource.Type.View,
+        Collections.singletonMap(Resource.Type.View, viewName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
new file mode 100644
index 0000000..52dd608
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.view.ViewResourceHandler;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * View sub-resource service.
+ */
+public class ViewSubResourceService extends BaseService implements ViewResourceHandler {
+  /**
+   * The type of the sub-resource.
+   */
+  private final Resource.Type type;
+
+  /**
+   * The associated view name.
+   */
+  private final String viewName;
+
+  /**
+   * The associated view instance name.
+   */
+  private final String instanceName;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view sub-resource service.
+   */
+  public ViewSubResourceService(Resource.Type type, String viewName, String instanceName) {
+    this.type         = type;
+    this.viewName     = viewName;
+    this.instanceName = instanceName;
+  }
+
+
+  // ----- ViewResourceHandler -----------------------------------------------
+
+  @Override
+  public Response handleRequest(HttpHeaders headers, UriInfo ui, String resourceId) {
+    return handleRequest(headers, null, ui, Request.Type.GET,
+        createResource(resourceId));
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  // create a resource with the given id
+  private ResourceInstance createResource(String resourceId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type,String>();
+
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+
+    if (resourceId != null) {
+      mapIds.put(type, resourceId);
+    }
+    return super.createResource(type, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index b070d98..293792b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -50,6 +50,8 @@ public class Configuration {
   public static final String CONFIG_FILE = "ambari.properties";
   public static final String BOOTSTRAP_DIR = "bootstrap.dir";
   public static final String BOOTSTRAP_DIR_DEFAULT = "/var/run/ambari-server/bootstrap";
+  public static final String VIEWS_DIR = "views.dir";
+  public static final String VIEWS_DIR_DEFAULT = "/var/lib/ambari-server/resources/views";
   public static final String WEBAPP_DIR = "webapp.dir";
   public static final String BOOTSTRAP_SCRIPT = "bootstrap.script";
   public static final String BOOTSTRAP_SCRIPT_DEFAULT = "/usr/bin/ambari_bootstrap";
@@ -460,6 +462,16 @@ public class Configuration {
     return properties;
   }
 
+  /**
+   * Get the views directory.
+   *
+   * @return the views directory
+   */
+  public File getViewsDir() {
+    String fileName = properties.getProperty(VIEWS_DIR, VIEWS_DIR_DEFAULT);
+    return new File(fileName);
+  }
+
   public File getBootStrapDir() {
     String fileName = properties.getProperty(BOOTSTRAP_DIR, BOOTSTRAP_DIR_DEFAULT);
     return new File(fileName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index 00f1b74..75b6cb1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -58,11 +58,11 @@ import org.apache.ambari.server.security.authorization.AmbariLocalUserDetailsSer
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenAuthenticationFilter;
-import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage;
 import org.apache.ambari.server.security.unsecured.rest.CertificateDownload;
 import org.apache.ambari.server.security.unsecured.rest.CertificateSign;
 import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.utils.StageUtils;
+import org.apache.ambari.server.view.ViewRegistry;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.nio.SelectChannelConnector;
@@ -277,6 +277,8 @@ public class AmbariServer {
       root.addServlet(sh, "/api/v1/*");
       sh.setInitOrder(2);
 
+      ViewRegistry.readViewArchives(configs, root, springSecurityFilter);
+
       ServletHolder agent = new ServletHolder(ServletContainer.class);
       agent.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
           "com.sun.jersey.api.core.PackagesResourceConfig");
@@ -317,8 +319,8 @@ public class AmbariServer {
       if (configs.getApiSSLAuthentication()) {
         String httpsKeystore = configsMap.get(Configuration.CLIENT_API_SSL_KSTR_DIR_NAME_KEY) +
           File.separator + configsMap.get(Configuration.CLIENT_API_SSL_KSTR_NAME_KEY);
-        LOG.info("API SSL Authentication is turned on. Keystore - " + httpsKeystore);        
-        
+        LOG.info("API SSL Authentication is turned on. Keystore - " + httpsKeystore);
+
         String httpsCrtPass = configsMap.get(Configuration.CLIENT_API_SSL_CRT_PASS_KEY);
 
         SslSelectChannelConnector sapiConnector = new SslSelectChannelConnector();
@@ -332,7 +334,7 @@ public class AmbariServer {
         sapiConnector.setTruststoreType("PKCS12");
         sapiConnector.setMaxIdleTime(configs.getConnectionMaxIdleTime());
         apiConnector = sapiConnector;
-      } 
+      }
       else  {
         apiConnector = new SelectChannelConnector();
         apiConnector.setPort(configs.getClientApiPort());

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index a10835e..e8765e4 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -61,6 +61,10 @@ public class DefaultProviderModule extends AbstractProviderModule {
         return new JobResourceProvider(propertyIds, keyPropertyIds);
       case TaskAttempt:
         return new TaskAttemptResourceProvider(propertyIds, keyPropertyIds);
+      case View:
+        return new ViewResourceProvider();
+      case ViewInstance:
+        return new ViewInstanceResourceProvider();
       default:
         return AbstractControllerResourceProvider.getResourceProvider(type, propertyIds,
             keyPropertyIds, managementController);

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
new file mode 100644
index 0000000..82f2224
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.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
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.view.ViewDefinition;
+import org.apache.ambari.server.view.ViewInstanceDefinition;
+import org.apache.ambari.server.view.ViewRegistry;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for view instances.
+ */
+public class ViewInstanceResourceProvider extends AbstractResourceProvider {
+
+  /**
+   * View instance property id constants.
+   */
+  public static final String VIEW_NAME_PROPERTY_ID        = "ViewInstanceInfo/view_name";
+  public static final String INSTANCE_NAME_PROPERTY_ID    = "ViewInstanceInfo/instance_name";
+  public static final String SERVLET_MAPPINGS_PROPERTY_ID = "ViewInstanceInfo/servlet_mappings";
+
+  /**
+   * The key property ids for a view instance resource.
+   */
+  private static Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+  static {
+    keyPropertyIds.put(Resource.Type.View, VIEW_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ViewInstance, INSTANCE_NAME_PROPERTY_ID);
+  }
+
+  /**
+   * The property ids for a view instance resource.
+   */
+  private static Set<String> propertyIds = new HashSet<String>();
+  static {
+    propertyIds.add(VIEW_NAME_PROPERTY_ID);
+    propertyIds.add(INSTANCE_NAME_PROPERTY_ID);
+    propertyIds.add(SERVLET_MAPPINGS_PROPERTY_ID);
+  }
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view instance resource provider.
+   */
+  public ViewInstanceResourceProvider() {
+    super(propertyIds, keyPropertyIds);
+  }
+
+
+  // ----- ResourceProvider --------------------------------------------------
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException, UnsupportedPropertyException,
+             ResourceAlreadyExistsException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> resources    = new HashSet<Resource>();
+    ViewRegistry  viewRegistry = ViewRegistry.getInstance();
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+    if (propertyMaps.isEmpty()) {
+      propertyMaps.add(Collections.<String, Object>emptyMap());
+    }
+
+    for (Map<String, Object> propertyMap : propertyMaps) {
+
+      String viewName = (String) propertyMap.get(VIEW_NAME_PROPERTY_ID);
+      String instanceName = (String) propertyMap.get(INSTANCE_NAME_PROPERTY_ID);
+
+      for (ViewDefinition viewDefinition : viewRegistry.getDefinitions()){
+        if (viewName == null || viewName.equals(viewDefinition.getName())) {
+          for (ViewInstanceDefinition viewInstanceDefinition : viewRegistry.getInstanceDefinitions(viewDefinition)) {
+            if (instanceName == null || instanceName.equals(viewInstanceDefinition.getName())) {
+              Resource resource = new ResourceImpl(Resource.Type.ViewInstance);
+
+              setResourceProperty(resource, VIEW_NAME_PROPERTY_ID, viewDefinition.getName(), requestedIds);
+              setResourceProperty(resource, INSTANCE_NAME_PROPERTY_ID, viewInstanceDefinition.getName(), requestedIds);
+              setResourceProperty(resource, SERVLET_MAPPINGS_PROPERTY_ID,
+                  viewInstanceDefinition.getServletMappings(), requestedIds);
+
+              resources.add(resource);
+            }
+          }
+        }
+      }
+    }
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public Map<Resource.Type, String> getKeyPropertyIds() {
+    return keyPropertyIds;
+  }
+
+
+  // ----- AbstractResourceProvider ------------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return new HashSet<String>(keyPropertyIds.values());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
new file mode 100644
index 0000000..17d3b94
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.view.ViewDefinition;
+import org.apache.ambari.server.view.ViewRegistry;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for view instances.
+ */
+public class ViewResourceProvider extends AbstractResourceProvider {
+
+  /**
+   * View property id constants.
+   */
+  public static final String VIEW_NAME_PROPERTY_ID  = "ViewInfo/view_name";
+  public static final String LABEL_PROPERTY_ID      = "ViewInfo/label";
+  public static final String VERSION_PROPERTY_ID    = "ViewInfo/version";
+  public static final String PARAMETERS_PROPERTY_ID = "ViewInfo/parameters";
+
+
+  /**
+   * The key property ids for a view resource.
+   */
+  private static Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+  static {
+    keyPropertyIds.put(Resource.Type.View, VIEW_NAME_PROPERTY_ID);
+  }
+
+  /**
+   * The property ids for a view resource.
+   */
+  private static Set<String> propertyIds = new HashSet<String>();
+  static {
+    propertyIds.add(VIEW_NAME_PROPERTY_ID);
+    propertyIds.add(LABEL_PROPERTY_ID);
+    propertyIds.add(VERSION_PROPERTY_ID);
+    propertyIds.add(PARAMETERS_PROPERTY_ID);
+  }
+
+  
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view resource provider.
+   */
+  public ViewResourceProvider() {
+    super(propertyIds, keyPropertyIds);
+  }
+
+  
+  // ----- ResourceProvider --------------------------------------------------
+
+  @Override
+  public RequestStatus createResources(Request request) 
+      throws SystemException, UnsupportedPropertyException, 
+             ResourceAlreadyExistsException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    Set<Resource> resources    = new HashSet<Resource>();
+    ViewRegistry  viewRegistry = ViewRegistry.getInstance();
+    Set<String>   requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+
+    if (propertyMaps.isEmpty()) {
+      propertyMaps.add(Collections.<String, Object>emptyMap());
+    }
+
+    for (Map<String, Object> propertyMap : propertyMaps) {
+
+      String viewName = (String) propertyMap.get(VIEW_NAME_PROPERTY_ID);
+
+      for (ViewDefinition viewDefinition : viewRegistry.getDefinitions()){
+        if (viewName == null || viewName.equals(viewDefinition.getName())) {
+          Resource resource = new ResourceImpl(Resource.Type.View);
+
+          setResourceProperty(resource, VIEW_NAME_PROPERTY_ID, viewDefinition.getName(), requestedIds);
+          setResourceProperty(resource, LABEL_PROPERTY_ID, viewDefinition.getLabel(), requestedIds);
+          setResourceProperty(resource, VERSION_PROPERTY_ID, viewDefinition.getVersion(), requestedIds);
+          setResourceProperty(resource, PARAMETERS_PROPERTY_ID,
+              viewDefinition.getConfiguration().getParameters(), requestedIds);
+
+          resources.add(resource);
+        }
+      }
+    }
+    return resources;
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Not yet supported.");
+  }
+
+  @Override
+  public Map<Resource.Type, String> getKeyPropertyIds() {
+    return keyPropertyIds;
+  }
+
+  
+  // ----- AbstractResourceProvider ------------------------------------------
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return new HashSet<String>(keyPropertyIds.values());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 6a82e59..52f0cdf 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -101,7 +101,9 @@ public interface Resource {
     TaskAttempt,
     RootService,
     RootServiceComponent,
-    RootServiceHostComponent;
+    RootServiceHostComponent,
+    View,
+    ViewInstance;
 
     /**
      * Get the {@link Type} that corresponds to this InternalType.
@@ -164,6 +166,8 @@ public interface Resource {
     public static final Type RootService = InternalType.RootService.getType();
     public static final Type RootServiceComponent = InternalType.RootServiceComponent.getType();
     public static final Type RootServiceHostComponent = InternalType.RootServiceHostComponent.getType();
+    public static final Type View = InternalType.View.getType();
+    public static final Type ViewInstance = InternalType.ViewInstance.getType();
 
     /**
      * The type name.

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java
index 3b0c12a..3086eb8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.controller.utilities;
 import org.apache.ambari.server.controller.spi.ProviderModule;
 import org.apache.ambari.server.controller.internal.ClusterControllerImpl;
 import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.view.ViewProviderModule;
 
 /**
  * Temporary class to bootstrap a cluster controller.  TODO : Replace this global state with injection.
@@ -36,7 +37,7 @@ public class ClusterControllerHelper {
     if (controller == null) {
       try {
         Class<?> implClass = Class.forName(PROVIDER_MODULE_CLASS);
-        ProviderModule providerModule = (ProviderModule) implClass.newInstance();
+        ProviderModule providerModule = ViewProviderModule.getViewProviderModule((ProviderModule) implClass.newInstance());
         controller = new ClusterControllerImpl(providerModule);
 
       } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
new file mode 100644
index 0000000..0106c1d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.configuration.ComponentSSLConfiguration;
+import org.apache.ambari.view.ResourceProvider;
+import org.apache.ambari.view.URLStreamProvider;
+import org.apache.ambari.view.ViewContext;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * View context implementation.
+ */
+public class ViewContextImpl implements ViewContext {
+
+  /**
+   * The associated view definition.
+   */
+  private final ViewInstanceDefinition viewInstanceDefinition;
+
+  /**
+   * The available stream provider.
+   */
+  private final URLStreamProvider streamProvider;
+
+
+  // ---- Constructors -------------------------------------------------------
+
+  /**
+   * Construct a view context from the given view definition.
+   *
+   * @param viewInstanceDefinition  the view definition
+   */
+  public ViewContextImpl(ViewInstanceDefinition viewInstanceDefinition) {
+    this.viewInstanceDefinition = viewInstanceDefinition;
+    this.streamProvider         = new ViewURLStreamProvider();
+  }
+
+
+  // ----- ViewContext -------------------------------------------------------
+
+  @Override
+  public String getViewName() {
+    return viewInstanceDefinition.getViewDefinition().getName();
+  }
+
+  @Override
+  public String getInstanceName() {
+    return viewInstanceDefinition.getName();
+  }
+
+  @Override
+  public Map<String, String> getProperties() {
+    return viewInstanceDefinition.getProperties();
+  }
+
+  @Override
+  public ResourceProvider<?> getResourceProvider(String type) {
+    return viewInstanceDefinition.getResourceProvider(type);
+  }
+
+  @Override
+  public String getUsername() {
+    SecurityContext ctx = SecurityContextHolder.getContext();
+    Authentication authentication = ctx == null ? null : ctx.getAuthentication();
+    Object principal = authentication == null ? null : authentication.getPrincipal();
+
+    String username;
+    if (principal instanceof UserDetails) {
+      username = ((UserDetails)principal).getUsername();
+    } else {
+      username = principal == null ? "" :principal.toString();
+    }
+    return username;
+  }
+
+  @Override
+  public URLStreamProvider getURLStreamProvider() {
+    return streamProvider;
+  }
+
+
+  // ----- Inner class : ViewURLStreamProvider -------------------------------
+
+  /**
+   * Wrapper around internal URL stream provider.
+   */
+  private static class ViewURLStreamProvider implements URLStreamProvider {
+    private static final int DEFAULT_REQUEST_CONNECT_TIMEOUT = 5000;
+    private static final int DEFAULT_REQUEST_READ_TIMEOUT    = 10000;
+
+    /**
+     * Internal stream provider.
+     */
+    private final org.apache.ambari.server.controller.internal.URLStreamProvider streamProvider;
+
+
+    // ----- Constructor -----------------------------------------------------
+
+    private ViewURLStreamProvider() {
+      ComponentSSLConfiguration configuration = ComponentSSLConfiguration.instance();
+      streamProvider =
+          new org.apache.ambari.server.controller.internal.URLStreamProvider(
+              DEFAULT_REQUEST_CONNECT_TIMEOUT, DEFAULT_REQUEST_READ_TIMEOUT,
+              configuration.getTruststorePath(),
+              configuration.getTruststorePassword(),
+              configuration.getTruststoreType());
+    }
+
+
+    // ----- URLStreamProvider -----------------------------------------------
+
+    @Override
+    public InputStream readFrom(String spec, String requestMethod, String params) throws IOException {
+      return streamProvider.readFrom(spec, requestMethod, params);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDefinition.java
new file mode 100644
index 0000000..80651ad
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDefinition.java
@@ -0,0 +1,209 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.api.resources.BaseResourceDefinition;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Provides access to the attributes of a view.
+ */
+public class ViewDefinition {
+  /**
+   * The associated view configuration.
+   */
+  private final ViewConfig configuration;
+
+  /**
+   * The mapping of resource type to resource provider.
+   */
+  private final Map<Resource.Type, ResourceProvider> resourceProviders = new HashMap<Resource.Type, ResourceProvider>();
+
+  /**
+   * The mapping of resource type to resource definition.
+   */
+  private final Map<Resource.Type, BaseResourceDefinition> resourceDefinitions = new HashMap<Resource.Type, BaseResourceDefinition>();
+
+  /**
+   * The mapping of resource type to resource configuration.
+   */
+  private final Map<Resource.Type, ResourceConfig> resourceConfigurations = new HashMap<Resource.Type, ResourceConfig>();
+
+  /**
+   * The mapping of instance name to instance definition.
+   */
+  private final Map<String, ViewInstanceDefinition> instanceDefinitions = new HashMap<String, ViewInstanceDefinition>();
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view definition from the given configuration.
+   *
+   * @param configuration the view configuration
+   */
+  public ViewDefinition(ViewConfig configuration) {
+    this.configuration = configuration;
+  }
+
+
+  // ----- ViewDefinition ----------------------------------------------------
+
+  /**
+   * Get the view name.
+   *
+   * @return the view name
+   */
+  public String getName() {
+    return configuration.getName();
+  }
+
+  /**
+   * Get the view label.
+   *
+   * @return the view label
+   */
+  public String getLabel() {
+    return configuration.getLabel();
+  }
+
+  /**
+   * Get the view version.
+   *
+   * @return the version
+   */
+  public String getVersion() {
+    return configuration.getVersion();
+  }
+
+  /**
+   * Get the associated view configuration.
+   *
+   * @return the configuration
+   */
+  public ViewConfig getConfiguration() {
+    return configuration;
+  }
+
+  /**
+   * Add a resource provider for the given type.
+   *
+   * @param type      the resource type
+   * @param provider  the resource provider
+   */
+  public void addResourceProvider(Resource.Type type, ResourceProvider provider) {
+    resourceProviders.put(type, provider);
+  }
+
+  /**
+   * Get the resource provider for the given type.
+   *
+   * @param type  the resource type
+   *
+   * @return the resource provider associated with the given type
+   */
+  public ResourceProvider getResourceProvider(Resource.Type type) {
+    return resourceProviders.get(type);
+  }
+
+  /**
+   * Add a resource definition.
+   *
+   * @param definition  the resource definition
+   */
+  public void addResourceDefinition(BaseResourceDefinition definition) {
+    resourceDefinitions.put(definition.getType(), definition);
+  }
+
+  /**
+   * Get the resource definition for the given type
+   *
+   * @param type  the resource type
+   *
+   * @return the resource definition associated with the given type
+   */
+  public BaseResourceDefinition getResourceDefinition(Resource.Type type) {
+    return resourceDefinitions.get(type);
+  }
+
+  /**
+   * Add a resource configuration for the given type.
+   *
+   * @param type    the resource type
+   * @param config  the configuration
+   */
+  public void addResourceConfiguration(Resource.Type type, ResourceConfig config) {
+    resourceConfigurations.put(type, config);
+  }
+
+  /**
+   * Get a mapping of resource type to resource configurations.
+   *
+   * @return the mapping of resource types to resource configurations
+   */
+  public Map<Resource.Type, ResourceConfig> getResourceConfigurations() {
+    return resourceConfigurations;
+  }
+
+  /**
+   * Get the set of resource types for this view.
+   *
+   * @return the set of resource type
+   */
+  public Set<Resource.Type> getViewResourceTypes() {
+    return resourceConfigurations.keySet();
+  }
+
+  /**
+   * Add an instance definition.
+   *
+   * @param viewInstanceDefinition  the instance definition
+   */
+  public void addInstanceDefinition(ViewInstanceDefinition viewInstanceDefinition) {
+    instanceDefinitions.put(viewInstanceDefinition.getName(), viewInstanceDefinition);
+  }
+
+  /**
+   * Get the collection of all instance definitions for this view.
+   *
+   * @return the collection of instance definitions
+   */
+  public Collection<ViewInstanceDefinition> getInstanceDefinitions() {
+    return instanceDefinitions.values();
+  }
+
+  /**
+   * Get an instance definition for the given name.
+   *
+   * @param instanceName  the instance name
+   *
+   * @return the instance definition
+   */
+  public ViewInstanceDefinition getInstanceDefinition(String instanceName) {
+    return instanceDefinitions.get(instanceName);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/view/ViewInstanceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewInstanceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewInstanceDefinition.java
new file mode 100644
index 0000000..7a7a5eb
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewInstanceDefinition.java
@@ -0,0 +1,198 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.configuration.InstanceConfig;
+import org.apache.ambari.view.ResourceProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides access to the attributes of a view instance.
+ */
+public class ViewInstanceDefinition {
+  /**
+   * The associated configuration.
+   */
+  private final InstanceConfig instanceConfig;
+
+  /**
+   * The parent view definition.
+   */
+  private final ViewDefinition viewDefinition;
+
+  /**
+   * The view instance properties.
+   */
+  private final Map<String, String> properties = new HashMap<String, String>();
+
+  /**
+   * The mapping of resource type to resource provider.
+   */
+  private final Map<Resource.Type, ResourceProvider> resourceProviders = new HashMap<Resource.Type, ResourceProvider>();
+
+  /**
+   * The mapping of the resource plural name to service.
+   */
+  private final Map<String, Object> services = new HashMap<String, Object>();
+
+  /**
+   * The mapping of servlet name to servlet path spec.
+   */
+  private final Map<String, String> servletMappings = new HashMap<String, String>();
+
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view instance definition.
+   *
+   * @param viewDefinition  the parent view definition
+   * @param instanceConfig  the associated configuration
+   */
+  public ViewInstanceDefinition(ViewDefinition viewDefinition, InstanceConfig instanceConfig) {
+    this.instanceConfig = instanceConfig;
+    this.viewDefinition = viewDefinition;
+  }
+
+
+  // ----- ViewInstanceDefinition --------------------------------------------
+
+  /**
+   * Get the parent view definition.
+   *
+   * @return the parent view definition
+   */
+  public ViewDefinition getViewDefinition() {
+    return viewDefinition;
+  }
+
+  /**
+   * Get the associated configuration.
+   *
+   * @return the configuration
+   */
+  public InstanceConfig getConfiguration() {
+    return instanceConfig;
+  }
+
+  /**
+   * Get the view instance name.
+   *
+   * @return the instance name
+   */
+  public String getName() {
+    return instanceConfig.getName();
+  }
+
+  /**
+   * Add a mapping from servlet name to path spec.
+   *
+   * @param servletName  the servlet name
+   * @param pathSpec     the path
+   */
+  public void addServletMapping(String servletName, String pathSpec) {
+    servletMappings.put(servletName, pathSpec);
+  }
+
+  /**
+   * Get the servlet mappings.
+   *
+   * @return the servlet mappings
+   */
+  public Map<String, String> getServletMappings() {
+    return servletMappings;
+  }
+
+  /**
+   * Add a view instance property.
+   *
+   * @param key    the property key
+   * @param value  the property value
+   */
+  public void addProperty(String key, String value) {
+    properties.put(key, value);
+  }
+
+  /**
+   * Get the view instance properties.
+   *
+   * @return the view instance properties
+   */
+  public Map<String, String> getProperties() {
+    return properties;
+  }
+
+  /**
+   * Add a service for the given plural resource name.
+   *
+   * @param pluralName  the plural resource name
+   * @param service     the service
+   */
+  public void addService(String pluralName, Object service) {
+    services.put(pluralName, service);
+  }
+
+  /**
+   * Get the service associated with the given plural resource name.
+   *
+   * @param pluralName  the plural resource name
+   *
+   * @return the service associated with the given name
+   */
+  public Object getService(String pluralName) {
+    return services.get(pluralName);
+  }
+
+  /**
+   * Add a resource provider for the given resource type.
+   *
+   * @param type      the resource type
+   * @param provider  the resource provider
+   */
+  public void addResourceProvider(Resource.Type type, ResourceProvider provider) {
+    resourceProviders.put(type, provider);
+  }
+
+  /**
+   * Get the resource provider for the given resource type.
+   *
+   * @param type  the resource type
+   *
+   * @return the resource provider
+   */
+  public ResourceProvider getResourceProvider(Resource.Type type) {
+    return resourceProviders.get(type);
+  }
+
+  /**
+   * Get the resource provider for the given resource type name (scoped to this view).
+   *
+   * @param type  the resource type name
+   *
+   * @return the resource provider
+   */
+  public ResourceProvider getResourceProvider(String type) {
+    String typeName = viewDefinition.getName() + "/" + type;
+    return resourceProviders.get(Resource.Type.valueOf(typeName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/view/ViewProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewProviderModule.java
new file mode 100644
index 0000000..9cb889a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewProviderModule.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.controller.spi.PropertyProvider;
+import org.apache.ambari.server.controller.spi.ProviderModule;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Module which allows for discovery of view resource providers.
+ * This module wraps another module and delegates to it for
+ * any resource types not defined in a view.
+ */
+public class ViewProviderModule implements ProviderModule {
+  /**
+   * Mapping of view resource type to resource provider.
+   */
+  private final Map<Resource.Type, ResourceProvider> resourceProviders;
+
+  /**
+   * The delegate provider module.
+   */
+  private final ProviderModule providerModule;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view provider module.
+   *
+   * @param providerModule     the delegate provider module
+   * @param resourceProviders  the map of view resource types to resource providers
+   */
+  private ViewProviderModule(ProviderModule providerModule,
+                            Map<Resource.Type, ResourceProvider> resourceProviders) {
+    this.providerModule = providerModule;
+    this.resourceProviders = resourceProviders;
+  }
+
+
+  // ----- ProviderModule ----------------------------------------------------
+
+  @Override
+  public ResourceProvider getResourceProvider(Resource.Type type) {
+
+    if (resourceProviders.containsKey(type)) {
+      return resourceProviders.get(type);
+    }
+    return providerModule.getResourceProvider(type);
+  }
+
+  @Override
+  public List<PropertyProvider> getPropertyProviders(Resource.Type type) {
+    return providerModule.getPropertyProviders(type);
+  }
+
+
+  // ----- helper methods -----------------------------------------
+
+  /**
+   * Factory method to get a view provider module.
+   *
+   * @param module  the delegate provider module
+   *
+   * @return a view provider module
+   */
+  public static ViewProviderModule getViewProviderModule(ProviderModule module) {
+    Map<Resource.Type, ResourceProvider> resourceProviders = new HashMap<Resource.Type, ResourceProvider>();
+
+    ViewRegistry registry = ViewRegistry.getInstance();
+    for (ViewDefinition definition : registry.getDefinitions()) {
+      for (Resource.Type type : definition.getViewResourceTypes()){
+        ResourceProvider provider = definition.getResourceProvider(type);
+        resourceProviders.put(type, provider);
+      }
+    }
+    return new ViewProviderModule(module, resourceProviders);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a0a10fc5/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
new file mode 100644
index 0000000..51fe2b6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -0,0 +1,384 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.ambari.server.api.resources.BaseResourceDefinition;
+import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
+import org.apache.ambari.server.api.resources.SubResourceDefinition;
+import org.apache.ambari.server.api.services.ViewSubResourceService;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.configuration.InstanceConfig;
+import org.apache.ambari.server.view.configuration.PropertyConfig;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.ViewResourceHandler;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.http.HttpServlet;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import java.beans.IntrospectionException;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Registry for view and view instance definitions.
+ */
+public class ViewRegistry {
+
+  /**
+   * Constants
+   */
+  private static final String VIEW_XML = "view.xml";
+
+  /**
+   * Mapping of view names to view definitions.
+   */
+  private Map<String, ViewDefinition> viewDefinitions = new HashMap<String, ViewDefinition>();
+
+  /**
+   * Mapping of view instances to view definition and instance name.
+   */
+  private Map<ViewDefinition, Map<String, ViewInstanceDefinition>> viewInstanceDefinitions = new HashMap<ViewDefinition, Map<String, ViewInstanceDefinition>>();
+
+  /**
+   * Mapping of view names to sub-resources.
+   */
+  private final Map<String, Set<SubResourceDefinition>> subResourceDefinitionsMap = new HashMap<String, Set<SubResourceDefinition>>();
+
+  /**
+   * The singleton view registry instance.
+   */
+  private static final ViewRegistry singleton = new ViewRegistry();
+
+  /**
+   * The logger.
+   */
+  protected final static Logger LOG = LoggerFactory.getLogger(ViewRegistry.class);
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Hide the constructor for this singleton.
+   */
+  private ViewRegistry() {
+  }
+
+
+  // ----- ViewRegistry ------------------------------------------------------
+
+  /**
+   * Get the collection of all the view definitions.
+   *
+   * @return the collection of view definitions
+   */
+  public Collection<ViewDefinition> getDefinitions() {
+    return viewDefinitions.values();
+  }
+
+  /**
+   * Get a view definition for the given name.
+   *
+   * @param viewName  the view name
+   *
+   * @return the view definition for the given name
+   */
+  public ViewDefinition getDefinition(String viewName) {
+    return viewDefinitions.get(viewName);
+  }
+
+  /**
+   * Add a view definition to the registry.
+   *
+   * @param definition  the definition
+   */
+  public void addDefinition(ViewDefinition definition) {
+    viewDefinitions.put(definition.getName(), definition);
+  }
+
+  /**
+   * Get the collection of view instances for the given view definition.
+   *
+   * @param definition  the view definition
+   *
+   * @return the collection of view instances for the view definition
+   */
+  public Collection<ViewInstanceDefinition> getInstanceDefinitions(ViewDefinition definition) {
+    return definition == null ? null : viewInstanceDefinitions.get(definition).values();
+  }
+
+  /**
+   * Get the instance definition for the given view nam,e and instance name.
+   *
+   * @param viewName      the view name
+   * @param instanceName  the instance name
+   *
+   * @return the view instance definition for the given view and instance name
+   */
+  public ViewInstanceDefinition getInstanceDefinition(String viewName, String instanceName) {
+    Map<String, ViewInstanceDefinition> viewInstanceDefinitionMap =
+        viewInstanceDefinitions.get(getDefinition(viewName));
+
+    return viewInstanceDefinitionMap == null ? null : viewInstanceDefinitionMap.get(instanceName);
+  }
+
+  /**
+   * Add an instance definition for the given view definition.
+   *
+   * @param definition          the owning view definition
+   * @param instanceDefinition  the instance definition
+   */
+  public void addInstanceDefinition(ViewDefinition definition, ViewInstanceDefinition instanceDefinition) {
+    Map<String, ViewInstanceDefinition> instanceDefinitions = viewInstanceDefinitions.get(definition);
+    if (instanceDefinitions == null) {
+      instanceDefinitions = new HashMap<String, ViewInstanceDefinition>();
+      viewInstanceDefinitions.put(definition, instanceDefinitions);
+    }
+    instanceDefinitions.put(instanceDefinition.getName(), instanceDefinition);
+  }
+
+  /**
+   * Get the view registry singleton.
+   *
+   * @return  the view registry
+   */
+  public static ViewRegistry getInstance() {
+    return singleton;
+  }
+
+  /**
+   * Get the sub-resource definitions for the given view name.
+   *
+   * @param viewName  the instance name
+   *
+   * @return the set of sub-resource definitions
+   */
+  public synchronized Set<SubResourceDefinition> getSubResourceDefinitions(String viewName) {
+
+    Set<SubResourceDefinition> subResourceDefinitions = subResourceDefinitionsMap.get(viewName);
+
+    if (subResourceDefinitions == null) {
+      subResourceDefinitions = new HashSet<SubResourceDefinition>();
+      ViewDefinition definition = getDefinition(viewName);
+      if (definition != null) {
+        for (Resource.Type type : definition.getViewResourceTypes()) {
+          subResourceDefinitions.add(new SubResourceDefinition(type));
+        }
+      }
+      subResourceDefinitionsMap.put(viewName, subResourceDefinitions);
+    }
+    return subResourceDefinitions;
+  }
+
+  /**
+   * Read the view archives.
+   *
+   * @param configuration       Ambari configuration
+   * @param rootContextHandler  the root servlet context handler
+   * @param filterProxy         the security filter
+   */
+  public static void readViewArchives(Configuration configuration, ServletContextHandler rootContextHandler,
+                                      DelegatingFilterProxy filterProxy) {
+
+    File   viewDir = configuration.getViewsDir();
+    File[] files   = viewDir.listFiles();
+
+    if (files != null) {
+      for (final File fileEntry : files) {
+        if (!fileEntry.isDirectory()) {
+          try {
+            ClassLoader cl = URLClassLoader.newInstance(new URL[]{fileEntry.toURI().toURL()});
+
+            InputStream    configStream     = cl.getResourceAsStream(VIEW_XML);
+            JAXBContext    jaxbContext      = JAXBContext.newInstance(ViewConfig.class);
+            Unmarshaller   jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+            ViewConfig     viewConfig       = (ViewConfig) jaxbUnmarshaller.unmarshal(configStream);
+            ViewDefinition viewDefinition   = installView(viewConfig, cl);
+
+            List<InstanceConfig> instances = viewConfig.getInstances();
+
+            for (InstanceConfig instanceConfig : instances) {
+              installViewInstance(viewDefinition, instanceConfig, cl, rootContextHandler, filterProxy, configuration);
+            }
+          } catch (Exception e) {
+            LOG.error("Caught exception loading view from " + fileEntry.getAbsolutePath(), e);
+          }
+        }
+      }
+    }
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Clear the registry.
+   */
+  protected void clear() {
+    viewDefinitions.clear();
+    viewInstanceDefinitions.clear();
+    subResourceDefinitionsMap.clear();
+  }
+
+  // install a new view definition
+  private static ViewDefinition installView(ViewConfig viewConfig, ClassLoader cl)
+      throws ClassNotFoundException, IntrospectionException {
+
+    List<ResourceConfig> resourceConfigurations = viewConfig.getResources();
+
+    ViewDefinition viewDefinition = new ViewDefinition(viewConfig);
+
+    for (ResourceConfig resourceConfiguration : resourceConfigurations) {
+
+      BaseResourceDefinition resourceDefinition = new ViewSubResourceDefinition(viewDefinition, resourceConfiguration);
+      viewDefinition.addResourceDefinition(resourceDefinition);
+
+      Resource.Type type = resourceDefinition.getType();
+      ResourceInstanceFactoryImpl.addResourceDefinition(type, resourceDefinition);
+
+      viewDefinition.addResourceConfiguration(type, resourceConfiguration);
+
+      Class<?> clazz      = resourceConfiguration.getResourceClass(cl);
+      String   idProperty = resourceConfiguration.getIdProperty();
+
+      viewDefinition.addResourceProvider(type, new ViewSubResourceProvider(type, clazz, idProperty, viewDefinition));
+    }
+
+    ViewRegistry.getInstance().addDefinition(viewDefinition);
+    return viewDefinition;
+  }
+
+  // install a new view instance definition
+  private static void installViewInstance(ViewDefinition viewDefinition,
+                                   InstanceConfig instanceConfig,
+                                   ClassLoader cl,
+                                   ServletContextHandler root,
+                                   DelegatingFilterProxy springSecurityFilter,
+                                   Configuration configs) throws ClassNotFoundException {
+
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    List<PropertyConfig> propertyConfigs = instanceConfig.getProperties();
+
+    for (PropertyConfig propertyConfig : propertyConfigs) {
+      viewInstanceDefinition.addProperty(propertyConfig.getKey(), propertyConfig.getValue());
+    }
+
+    ViewContext viewInstanceContext = new ViewContextImpl(viewInstanceDefinition);
+
+    Map<Resource.Type, ResourceConfig> resourceConfigurations = viewDefinition.getResourceConfigurations();
+
+    for (Map.Entry<Resource.Type, ResourceConfig> entry : resourceConfigurations.entrySet()) {
+
+      Resource.Type  type          = entry.getKey();
+      ResourceConfig configuration = entry.getValue();
+
+      ViewResourceHandler viewResourceService =
+          new ViewSubResourceService(type, viewDefinition.getName(), instanceConfig.getName());
+      viewInstanceDefinition.addService(viewDefinition.getResourceDefinition(type).getPluralName(),
+          getService(configuration.getServiceClass(cl), viewResourceService, viewInstanceContext));
+
+      viewInstanceDefinition.addResourceProvider(type,
+          getProvider(configuration.getProviderClass(cl), viewInstanceContext));
+    }
+
+    ViewConfig viewConfig = viewDefinition.getConfiguration();
+
+    Map<String, Class<? extends HttpServlet>> servletPathMap = viewConfig.getServletPathMap(cl);
+    Map<String, String> servletURLPatternMap = viewConfig.getServletURLPatternMap();
+
+    for (Map.Entry<String, Class<? extends HttpServlet>> entry : servletPathMap.entrySet()) {
+      HttpServlet servlet = getServlet(entry.getValue(), viewInstanceContext);
+      ServletHolder sh = new ServletHolder(servlet);
+      String servletName = entry.getKey();
+      String pathSpec = "/views/" + viewDefinition.getName() + "/" +
+          viewInstanceDefinition.getName() + servletURLPatternMap.get(servletName);
+      root.addServlet(sh, pathSpec);
+      viewInstanceDefinition.addServletMapping(servletName, pathSpec);
+
+      if (configs.getApiAuthentication()) {
+        root.addFilter(new FilterHolder(springSecurityFilter), pathSpec, 1);
+      }
+    }
+    viewDefinition.addInstanceDefinition(viewInstanceDefinition);
+    ViewRegistry.getInstance().addInstanceDefinition(viewDefinition, viewInstanceDefinition);
+  }
+
+  // get the given service class from the given class loader; inject a handler and context
+  private static <T> T getService(Class<T> clazz,
+                                  final ViewResourceHandler viewResourceHandler,
+                                  final ViewContext viewInstanceContext) {
+    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(ViewResourceHandler.class)
+            .toInstance(viewResourceHandler);
+        bind(ViewContext.class)
+            .toInstance(viewInstanceContext);
+      }
+    });
+    return viewInstanceInjector.getInstance(clazz);
+  }
+
+  // get the given servlet class from the given class loader; inject a context
+  private static HttpServlet getServlet(Class<? extends HttpServlet> clazz,
+                                        final ViewContext viewInstanceContext) {
+    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(ViewContext.class)
+            .toInstance(viewInstanceContext);
+      }
+    });
+    return viewInstanceInjector.getInstance(clazz);
+  }
+
+  // get the given resource provider class from the given class loader; inject a context
+  private static org.apache.ambari.view.ResourceProvider getProvider(
+      Class<? extends org.apache.ambari.view.ResourceProvider> clazz,
+      final ViewContext viewInstanceContext) {
+    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(ViewContext.class)
+            .toInstance(viewInstanceContext);
+      }
+    });
+    return viewInstanceInjector.getInstance(clazz);
+  }
+}