Browse Source

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

tbeerbower 11 years ago
parent
commit
a0a10fc5a9
29 changed files with 3149 additions and 6 deletions
  1. 37 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
  2. 63 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinition.java
  3. 58 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewResourceDefinition.java
  4. 237 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewInstanceService.java
  5. 161 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewService.java
  6. 86 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewSubResourceService.java
  7. 12 0
      ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
  8. 6 4
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
  9. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
  10. 153 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
  11. 150 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewResourceProvider.java
  12. 5 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
  13. 2 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/ClusterControllerHelper.java
  14. 141 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
  15. 209 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewDefinition.java
  16. 198 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewInstanceDefinition.java
  17. 100 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewProviderModule.java
  18. 384 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
  19. 101 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewSubResourceDefinition.java
  20. 338 0
      ambari-server/src/main/java/org/apache/ambari/server/view/ViewSubResourceProvider.java
  21. 65 0
      ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinitionTest.java
  22. 51 0
      ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewResourceDefinitionTest.java
  23. 92 0
      ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java
  24. 155 0
      ambari-server/src/test/java/org/apache/ambari/server/view/ViewDefinitionTest.java
  25. 127 0
      ambari-server/src/test/java/org/apache/ambari/server/view/ViewInstanceDefinitionTest.java
  26. 99 0
      ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
  27. 68 0
      ambari-server/src/test/java/org/apache/ambari/server/view/ViewSubResourceDefinitionTest.java
  28. 40 0
      ambari-views/src/main/java/org/apache/ambari/view/URLStreamProvider.java
  29. 7 0
      ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java

+ 37 - 0
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) {
 
@@ -41,6 +52,16 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
     return new QueryImpl(mapIds, resourceDefinition, ClusterControllerHelper.getClusterController());
   }
 
+  /**
+   * 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.
    *
@@ -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);
     }

+ 63 - 0
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;
+  }
+}

+ 58 - 0
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));
+  }
+}

+ 237 - 0
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);
+  }
+}

+ 161 - 0
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));
+  }
+}

+ 86 - 0
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);
+  }
+}

+ 12 - 0
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);

+ 6 - 4
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());

+ 4 - 0
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);

+ 153 - 0
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());
+  }
+}

+ 150 - 0
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());
+  }
+}

+ 5 - 1
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.

+ 2 - 1
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) {

+ 141 - 0
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);
+    }
+  }
+}

+ 209 - 0
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);
+  }
+}

+ 198 - 0
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));
+  }
+}

+ 100 - 0
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);
+  }
+}

+ 384 - 0
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);
+  }
+}

+ 101 - 0
ambari-server/src/main/java/org/apache/ambari/server/view/ViewSubResourceDefinition.java

@@ -0,0 +1,101 @@
+/**
+ * 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.api.resources.SubResourceDefinition;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * View sub-resource definition based on a view resource configuration.
+ */
+public class ViewSubResourceDefinition extends BaseResourceDefinition {
+  /**
+   * The associated view definition.
+   */
+  private final ViewDefinition viewDefinition;
+
+  /**
+   * The configuration.
+   */
+  private final ResourceConfig resourceConfiguration;
+
+  /**
+   * The sub resource definitions.
+   */
+  Set<SubResourceDefinition> definitions;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a sub-resource definition.
+   *
+   * @param viewDefinition         the view definition
+   * @param resourceConfiguration  the resource configuration
+   */
+  public ViewSubResourceDefinition(ViewDefinition viewDefinition, ResourceConfig resourceConfiguration) {
+    super(new Resource.Type(getQualifiedResourceTypeName(viewDefinition.getName(), resourceConfiguration.getName())));
+
+    this.viewDefinition        = viewDefinition;
+    this.resourceConfiguration = resourceConfiguration;
+  }
+
+
+  // ----- ResourceDefinition ------------------------------------------------
+
+  @Override
+  public String getPluralName() {
+    return resourceConfiguration.getPluralName();
+  }
+
+  @Override
+  public String getSingularName() {
+    return resourceConfiguration.getName();
+  }
+
+  @Override
+  public synchronized Set<SubResourceDefinition> getSubResourceDefinitions() {
+    if (definitions == null) {
+      definitions = new HashSet<SubResourceDefinition>();
+      List<String> subResourceNames = resourceConfiguration.getSubResourceNames();
+      if (subResourceNames != null) {
+        for (String subType : subResourceNames) {
+          Resource.Type type = Resource.Type.valueOf(
+              getQualifiedResourceTypeName(viewDefinition.getName(), subType));
+          definitions.add(new SubResourceDefinition(type));
+        }
+      }
+    }
+    return definitions;
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  // qualify the resource type name with the view name
+  private static String getQualifiedResourceTypeName(String viewName, String resourceTypeName) {
+    return viewName + "/" + resourceTypeName;
+  }
+}

+ 338 - 0
ambari-server/src/main/java/org/apache/ambari/server/view/ViewSubResourceProvider.java

@@ -0,0 +1,338 @@
+/**
+ * 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.internal.AbstractResourceProvider;
+import org.apache.ambari.server.controller.internal.RequestStatusImpl;
+import org.apache.ambari.server.controller.internal.ResourceImpl;
+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.controller.utilities.PropertyHelper;
+import org.apache.ambari.view.ReadRequest;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An SPI resource provider implementation used to adapt a
+ * view resource provider to the SPI interfaces for view
+ * sub-resources.
+ */
+public class ViewSubResourceProvider extends AbstractResourceProvider {
+
+  private static final String VIEW_NAME_PROPERTY_ID = "view_name";
+  private static final String INSTANCE_NAME_PROPERTY_ID = "instance_name";
+
+  private final ViewDefinition viewDefinition;
+  private final String pkField;
+  private final Resource.Type type;
+  private final Map<String, PropertyDescriptor> descriptorMap;
+
+  private final Set<String> pkPropertyIds;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view resource provider for the given resource type and bean class.
+   *
+   * @param type            the resource type
+   * @param clazz           the resource bean class
+   * @param pkField         the primary key field name
+   * @param viewDefinition  the associated view definition
+   *
+   * @throws IntrospectionException if an exception occurs during introspection of the resource bean class
+   */
+  public ViewSubResourceProvider(Resource.Type type, Class<?> clazz, String pkField, ViewDefinition viewDefinition)
+      throws IntrospectionException {
+
+    super(discoverPropertyIds(clazz), getKeyPropertyIds(pkField, type));
+    this.pkField        = pkField;
+    this.viewDefinition = viewDefinition;
+    this.pkPropertyIds  = new HashSet<String>(getKeyPropertyIds().values());
+    this.type           = type;
+    this.descriptorMap  = getDescriptorMap(clazz);
+  }
+
+
+  // ----- ResourceProvider --------------------------------------------------
+
+  @Override
+  public RequestStatus createResources(Request request)
+      throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
+
+    Set<Map<String, Object>> properties = request.getProperties();
+
+    for (Map<String, Object> propertyMap : properties) {
+      String resourceId   = (String) propertyMap.get(pkField);
+      String instanceName = (String) propertyMap.get(INSTANCE_NAME_PROPERTY_ID);
+
+      try {
+        getResourceProvider(instanceName).createResource(resourceId, propertyMap);
+      } catch (org.apache.ambari.view.NoSuchResourceException e) {
+        throw new NoSuchParentResourceException(e.getMessage(), e);
+      } catch (org.apache.ambari.view.UnsupportedPropertyException e) {
+        throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds());
+      } catch (org.apache.ambari.view.ResourceAlreadyExistsException e) {
+        throw new ResourceAlreadyExistsException(e.getMessage());
+      } catch (Exception e) {
+        throw new SystemException(e.getMessage(), e);
+      }
+    }
+    return new RequestStatusImpl(null);
+  }
+
+  @Override
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<String> requestedIds = getRequestPropertyIds(request, predicate);
+
+    Set<ViewInstanceDefinition> instanceDefinitions = new HashSet<ViewInstanceDefinition>();
+
+    try {
+
+      Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
+      int size = propertyMaps.size();
+
+      Collection<ViewInstanceDefinition> viewInstanceDefinitions = viewDefinition.getInstanceDefinitions();
+      if (size == 0) {
+        instanceDefinitions.addAll(viewInstanceDefinitions);
+      } else {
+        for (Map<String, Object> propertyMap : propertyMaps) {
+          String instanceName = (String) propertyMap.get(INSTANCE_NAME_PROPERTY_ID);
+          if (size == 1 && instanceName != null) {
+            String resourceId = (String) propertyMap.get(pkField);
+            if (resourceId != null) {
+              Object bean = getResourceProvider(instanceName).getResource(resourceId, requestedIds);
+              return Collections.singleton(getResource(bean, viewDefinition.getName(), instanceName, requestedIds));
+            }
+          }
+          if (instanceName == null) {
+            instanceDefinitions.addAll(viewInstanceDefinitions);
+            break;
+          } else {
+            instanceDefinitions.add(viewDefinition.getInstanceDefinition(instanceName));
+          }
+        }
+      }
+
+      Set<Resource> results = new HashSet<Resource>();
+      ReadRequest readRequest = new ViewReadRequest(requestedIds, predicate == null ? "" : predicate.toString());
+      for (ViewInstanceDefinition instanceDefinition : instanceDefinitions) {
+
+        Set<?> beans = instanceDefinition.getResourceProvider(type).getResources(readRequest);
+
+        for (Object bean : beans) {
+          Resource resource = getResource(bean, viewDefinition.getName(), instanceDefinition.getName(), requestedIds);
+          if (predicate.evaluate(resource)) {
+            results.add(resource);
+          }
+        }
+      }
+      return results;
+    } catch (org.apache.ambari.view.NoSuchResourceException e) {
+      throw new NoSuchParentResourceException(e.getMessage(), e);
+    } catch (org.apache.ambari.view.UnsupportedPropertyException e) {
+      throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds());
+    } catch (Exception e) {
+      throw new SystemException(e.getMessage(), e);
+    }
+  }
+
+  @Override
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+
+    if (iterator.hasNext()) {
+      Map<String,Object> propertyMap = iterator.next();
+      Set<Resource>      resources   = getResources(request, predicate);
+
+      for (Resource resource : resources) {
+        String resourceId   = (String) resource.getPropertyValue(pkField);
+        String instanceName = (String) resource.getPropertyValue(INSTANCE_NAME_PROPERTY_ID);
+
+        try {
+          getResourceProvider(instanceName).updateResource(resourceId, propertyMap);
+        } catch (org.apache.ambari.view.NoSuchResourceException e) {
+          throw new NoSuchParentResourceException(e.getMessage(), e);
+        } catch (org.apache.ambari.view.UnsupportedPropertyException e) {
+          throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds());
+        } catch (Exception e) {
+          throw new SystemException(e.getMessage(), e);
+        }
+      }
+    }
+    return new RequestStatusImpl(null);
+  }
+
+  @Override
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    Set<Resource> resources = getResources(PropertyHelper.getReadRequest(), predicate);
+    for (Resource resource : resources) {
+      String resourceId   = (String) resource.getPropertyValue(pkField);
+      String instanceName = (String) resource.getPropertyValue(INSTANCE_NAME_PROPERTY_ID);
+
+      try {
+        getResourceProvider(instanceName).deleteResource(resourceId);
+      } catch (org.apache.ambari.view.NoSuchResourceException e) {
+        throw new NoSuchParentResourceException(e.getMessage(), e);
+      } catch (org.apache.ambari.view.UnsupportedPropertyException e) {
+        throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds());
+      } catch (Exception e) {
+        throw new SystemException(e.getMessage(), e);
+      }
+    }
+    return new RequestStatusImpl(null);
+  }
+
+  @Override
+  protected Set<String> getPKPropertyIds() {
+    return pkPropertyIds;
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  // get a Resource from the bean
+  private Resource getResource(Object bean, String viewName, String instanceName, Set<String> requestedIds)
+      throws InvocationTargetException, IllegalAccessException {
+
+    Resource resource = new ResourceImpl(type);
+
+    resource.setProperty(VIEW_NAME_PROPERTY_ID, viewName);
+    resource.setProperty(INSTANCE_NAME_PROPERTY_ID, instanceName);
+
+    for (Map.Entry<String, PropertyDescriptor> entry : descriptorMap.entrySet()) {
+      Object value = entry.getValue().getReadMethod().invoke(bean);
+
+      setResourceProperty(resource, entry.getKey(), value, requestedIds);
+    }
+    return resource;
+  }
+
+  // get the resource provider associated with the given instance name for this resource type
+  private org.apache.ambari.view.ResourceProvider<?> getResourceProvider(String instanceName) {
+    return viewDefinition.getInstanceDefinition(instanceName).getResourceProvider(type);
+  }
+
+  // get the resource type associated with the given UnsupportedPropertyException
+  private Resource.Type getResourceType(org.apache.ambari.view.UnsupportedPropertyException e) {
+    Resource.Type type = Resource.Type.valueOf(e.getType());
+    return type == null ? this.type : type;
+  }
+
+  // discover the property ids for the given bean class
+  private static Set<String> discoverPropertyIds(Class<?> clazz) throws IntrospectionException {
+    Set<String> propertyIds = new HashSet<String>(getDescriptorMap(clazz).keySet());
+    propertyIds.add(INSTANCE_NAME_PROPERTY_ID);
+    propertyIds.add("view_name");
+
+    return propertyIds;
+  }
+
+  // get a descriptor map for the given bean class
+  private static Map<String, PropertyDescriptor> getDescriptorMap(Class<?> clazz) throws IntrospectionException {
+    Map<String, PropertyDescriptor> descriptorMap = new HashMap<String, PropertyDescriptor>();
+
+    for (PropertyDescriptor pd : Introspector.getBeanInfo(clazz).getPropertyDescriptors()) {
+      String name = pd.getName();
+      if (pd.getReadMethod() != null && !name.equals("class")) {
+        descriptorMap.put(name, pd);
+      }
+    }
+    return descriptorMap;
+  }
+
+  // get the key property ids for the resource
+  private static Map<Resource.Type, String> getKeyPropertyIds(String pkField, Resource.Type type) {
+
+    Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+
+    keyPropertyIds.put(Resource.Type.View, VIEW_NAME_PROPERTY_ID);
+    keyPropertyIds.put(Resource.Type.ViewInstance, INSTANCE_NAME_PROPERTY_ID);
+    keyPropertyIds.put(type, pkField);
+
+    return keyPropertyIds;
+  }
+
+
+  // ----- inner class : ViewReadRequest -------------------------------------
+
+  /**
+   * A read request to pass the the view resource provider.
+   */
+  private static class ViewReadRequest implements ReadRequest {
+    /**
+     * The property ids of the request.
+     */
+    private final Set<String> propertyIds;
+
+    /**
+     * The request predicate.
+     */
+    private final String predicate;
+
+
+    // ----- Constructors ----------------------------------------------------
+
+    /**
+     * Construct a view read request.
+     *
+     * @param propertyIds  the property ids
+     * @param predicate    the predicate
+     */
+    private ViewReadRequest(Set<String> propertyIds, String predicate) {
+      this.propertyIds = propertyIds;
+      this.predicate = predicate;
+    }
+
+
+    // ----- ReadRequest -----------------------------------------------------
+
+    @Override
+    public Set<String> getPropertyIds() {
+      return propertyIds;
+    }
+
+    @Override
+    public String getPredicate() {
+      return predicate;
+    }
+  }
+}

+ 65 - 0
ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewInstanceResourceDefinitionTest.java

@@ -0,0 +1,65 @@
+/**
+ * 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 org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * ViewInstanceResourceDefinition tests.
+ */
+public class ViewInstanceResourceDefinitionTest {
+  @Test
+  public void testGetPluralName() throws Exception {
+    ViewInstanceResourceDefinition viewInstanceResourceDefinition = getViewInstanceResourceDefinition();
+    Assert.assertEquals("instances", viewInstanceResourceDefinition.getPluralName());
+  }
+
+  @Test
+  public void testGetSingularName() throws Exception {
+    ViewInstanceResourceDefinition viewInstanceResourceDefinition = getViewInstanceResourceDefinition();
+    Assert.assertEquals("instance", viewInstanceResourceDefinition.getSingularName());
+  }
+
+  @Test
+  public void testGetSubResourceDefinitions() throws Exception {
+    ViewInstanceResourceDefinition viewInstanceResourceDefinition = getViewInstanceResourceDefinition();
+    Set<SubResourceDefinition> subResourceDefinitions = viewInstanceResourceDefinition.getSubResourceDefinitions();
+
+    Assert.assertEquals(2, subResourceDefinitions.size());
+
+    for (SubResourceDefinition subResourceDefinition : subResourceDefinitions) {
+      Resource.Type type = subResourceDefinition.getType();
+      Assert.assertTrue(type.name().equals("sub1") || type.name().equals("sub2"));
+    }
+  }
+
+  public static ViewInstanceResourceDefinition getViewInstanceResourceDefinition() {
+    Set<SubResourceDefinition> subResourceDefinitions = new HashSet<SubResourceDefinition>();
+
+    subResourceDefinitions.add(new SubResourceDefinition(new Resource.Type("sub1")));
+    subResourceDefinitions.add(new SubResourceDefinition(new Resource.Type("sub2")));
+
+    return new ViewInstanceResourceDefinition(subResourceDefinitions);
+  }
+}

+ 51 - 0
ambari-server/src/test/java/org/apache/ambari/server/api/resources/ViewResourceDefinitionTest.java

@@ -0,0 +1,51 @@
+/**
+ * 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.junit.Assert;
+import org.junit.Test;
+
+import java.util.Set;
+
+/**
+ * ViewResourceDefinition tests.
+ */
+public class ViewResourceDefinitionTest {
+  @Test
+  public void testGetPluralName() throws Exception {
+    ViewResourceDefinition viewResourceDefinition = new ViewResourceDefinition();
+    Assert.assertEquals("views", viewResourceDefinition.getPluralName());
+  }
+
+  @Test
+  public void testGetSingularName() throws Exception {
+    ViewResourceDefinition viewResourceDefinition = new ViewResourceDefinition();
+    Assert.assertEquals("view", viewResourceDefinition.getSingularName());
+  }
+
+  @Test
+  public void testGetSubResourceDefinitions() throws Exception {
+    ViewResourceDefinition viewResourceDefinition = new ViewResourceDefinition();
+    Set<SubResourceDefinition> subResourceDefinitions = viewResourceDefinition.getSubResourceDefinitions ();
+
+    Assert.assertEquals(1, subResourceDefinitions.size());
+
+    Assert.assertEquals("ViewInstance", subResourceDefinitions.iterator().next().getType().name());
+  }
+}

+ 92 - 0
ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java

@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+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.server.view.configuration.InstanceConfigTest;
+import org.apache.ambari.view.ResourceProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createNiceMock;
+
+/**
+ * ViewContextImpl tests.
+ */
+public class ViewContextImplTest {
+  @Test
+  public void testGetViewName() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition);
+
+    Assert.assertEquals("MY_VIEW", viewContext.getViewName());
+  }
+
+  @Test
+  public void testGetInstanceName() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition);
+
+    Assert.assertEquals("INSTANCE1", viewContext.getInstanceName());
+  }
+
+  @Test
+  public void testGetProperties() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+    viewInstanceDefinition.addProperty("p1", "v1");
+    viewInstanceDefinition.addProperty("p2", "v2");
+    viewInstanceDefinition.addProperty("p3", "v3");
+
+    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition);
+
+    Map<String, String> properties = viewContext.getProperties();
+    Assert.assertEquals(3, properties.size());
+
+    Assert.assertEquals("v1", properties.get("p1"));
+    Assert.assertEquals("v2", properties.get("p2"));
+    Assert.assertEquals("v3", properties.get("p3"));
+  }
+
+  @Test
+  public void testGetResourceProvider() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    ResourceProvider provider = createNiceMock(ResourceProvider.class);
+    Resource.Type type = new Resource.Type("MY_VIEW/myType");
+
+    viewInstanceDefinition.addResourceProvider(type, provider);
+
+    ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition);
+
+    Assert.assertEquals(provider, viewContext.getResourceProvider("myType"));
+  }
+}

+ 155 - 0
ambari-server/src/test/java/org/apache/ambari/server/view/ViewDefinitionTest.java

@@ -0,0 +1,155 @@
+/**
+ * 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.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+import org.apache.ambari.server.view.configuration.ResourceConfigTest;
+import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.ambari.server.view.configuration.ViewConfigTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Collection;
+import java.util.Set;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * ViewDefinition tests.
+ */
+public class ViewDefinitionTest {
+
+  public static ViewDefinition getViewDefinition() throws Exception {
+    return new ViewDefinition(ViewConfigTest.getConfig());
+  }
+
+  public static ViewDefinition getViewDefinition(ViewConfig config) throws Exception {
+    return new ViewDefinition(config);
+  }
+
+  @Test
+  public void testGetName() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+    Assert.assertEquals("MY_VIEW", viewDefinition.getName());
+  }
+
+  @Test
+  public void testGetLabel() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+    Assert.assertEquals("My View!", viewDefinition.getLabel());
+  }
+
+  @Test
+  public void testGetVersion() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+    Assert.assertEquals("1.0.0", viewDefinition.getVersion());
+  }
+
+  @Test
+  public void testGetConfiguration() throws Exception {
+    ViewConfig viewConfig = ViewConfigTest.getConfig();
+    ViewDefinition viewDefinition = getViewDefinition(viewConfig);
+    Assert.assertEquals(viewConfig, viewDefinition.getConfiguration());
+  }
+
+  @Test
+  public void testAddGetResourceProvider() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+
+    ResourceProvider provider = createNiceMock(ResourceProvider.class);
+
+    Resource.Type type = new Resource.Type("myType");
+    viewDefinition.addResourceProvider(type, provider);
+
+    Assert.assertEquals(provider, viewDefinition.getResourceProvider(type));
+  }
+
+  @Test
+  public void testAddGetResourceDefinition() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+
+    BaseResourceDefinition definition = createNiceMock(BaseResourceDefinition.class);
+    Resource.Type type = new Resource.Type("myType");
+
+    expect(definition.getType()).andReturn(type);
+
+    replay(definition);
+
+    viewDefinition.addResourceDefinition(definition);
+
+    Assert.assertEquals(definition, viewDefinition.getResourceDefinition(type));
+
+    verify(definition);
+  }
+
+  @Test
+  public void testAddGetResourceConfiguration() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+
+    ResourceConfig config = ResourceConfigTest.getResourceConfigs().get(0);
+
+    Resource.Type type1 = new Resource.Type("myType");
+
+    viewDefinition.addResourceConfiguration(type1, config);
+
+    Assert.assertEquals(config, viewDefinition.getResourceConfigurations().get(type1));
+
+    Resource.Type type2 = new Resource.Type("myType2");
+
+    viewDefinition.addResourceConfiguration(type2, config);
+
+    Assert.assertEquals(config, viewDefinition.getResourceConfigurations().get(type2));
+
+    Set<Resource.Type> types = viewDefinition.getViewResourceTypes();
+
+    Assert.assertEquals(2, types.size());
+
+    Assert.assertTrue(types.contains(type1));
+    Assert.assertTrue(types.contains(type2));
+  }
+
+  @Test
+  public void testAddGetInstanceDefinition() throws Exception {
+    ViewDefinition viewDefinition = getViewDefinition();
+
+    ViewInstanceDefinition definition = createNiceMock(ViewInstanceDefinition.class);
+
+    expect(definition.getName()).andReturn("instance1");
+
+    replay(definition);
+
+    viewDefinition.addInstanceDefinition(definition);
+
+    Assert.assertEquals(definition, viewDefinition.getInstanceDefinition("instance1"));
+
+    Collection<ViewInstanceDefinition> definitions = viewDefinition.getInstanceDefinitions();
+
+    Assert.assertEquals(1, definitions.size());
+
+    Assert.assertTrue(definitions.contains(definition));
+
+    verify(definition);
+  }
+}

+ 127 - 0
ambari-server/src/test/java/org/apache/ambari/server/view/ViewInstanceDefinitionTest.java

@@ -0,0 +1,127 @@
+/**
+ * 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.server.view.configuration.InstanceConfigTest;
+import org.apache.ambari.view.ResourceProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.easymock.EasyMock.createNiceMock;
+
+/**
+ * ViewInstanceDefinition tests.
+ */
+public class ViewInstanceDefinitionTest {
+  @Test
+  public void testGetViewDefinition() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    Assert.assertEquals(viewDefinition, viewInstanceDefinition.getViewDefinition());
+  }
+
+  @Test
+  public void testGetConfiguration() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = new ViewInstanceDefinition(viewDefinition, instanceConfig);
+
+    Assert.assertEquals(instanceConfig, viewInstanceDefinition.getConfiguration());
+  }
+
+  @Test
+  public void testGetName() throws Exception {
+    ViewInstanceDefinition viewInstanceDefinition = getViewInstanceDefinition();
+
+    Assert.assertEquals("INSTANCE1", viewInstanceDefinition.getName());
+  }
+
+  @Test
+  public void testAddGetServletMapping() throws Exception {
+    ViewInstanceDefinition viewInstanceDefinition = getViewInstanceDefinition();
+
+    viewInstanceDefinition.addServletMapping("Servlet1", "path1");
+    viewInstanceDefinition.addServletMapping("Servlet2", "path2");
+
+    Map<String, String> mappings = viewInstanceDefinition.getServletMappings();
+
+    Assert.assertEquals(2, mappings.size());
+
+    Assert.assertEquals("path1", mappings.get("Servlet1"));
+    Assert.assertEquals("path2", mappings.get("Servlet2"));
+  }
+
+  @Test
+  public void testAddGetProperty() throws Exception {
+    ViewInstanceDefinition viewInstanceDefinition = getViewInstanceDefinition();
+
+    viewInstanceDefinition.addProperty("p1", "v1");
+    viewInstanceDefinition.addProperty("p2", "v2");
+    viewInstanceDefinition.addProperty("p3", "v3");
+
+    Map<String, String> properties = viewInstanceDefinition.getProperties();
+
+    Assert.assertEquals(3, properties.size());
+
+    Assert.assertEquals("v1", properties.get("p1"));
+    Assert.assertEquals("v2", properties.get("p2"));
+    Assert.assertEquals("v3", properties.get("p3"));
+  }
+
+  @Test
+  public void testAddGetService() throws Exception {
+    ViewInstanceDefinition viewInstanceDefinition = getViewInstanceDefinition();
+
+    Object service = new Object();
+
+    viewInstanceDefinition.addService("resources", service);
+
+    Object service2 = new Object();
+
+    viewInstanceDefinition.addService("subresources", service2);
+
+    Assert.assertEquals(service, viewInstanceDefinition.getService("resources"));
+    Assert.assertEquals(service2, viewInstanceDefinition.getService("subresources"));
+  }
+
+  @Test
+  public void testAddGetResourceProvider() throws Exception {
+    ViewInstanceDefinition viewInstanceDefinition = getViewInstanceDefinition();
+
+    ResourceProvider provider = createNiceMock(ResourceProvider.class);
+    Resource.Type type = new Resource.Type("MY_VIEW/myType");
+
+    viewInstanceDefinition.addResourceProvider(type, provider);
+
+    Assert.assertEquals(provider, viewInstanceDefinition.getResourceProvider(type));
+    Assert.assertEquals(provider, viewInstanceDefinition.getResourceProvider("myType"));
+  }
+
+  public static ViewInstanceDefinition getViewInstanceDefinition() throws Exception {
+    InstanceConfig instanceConfig = InstanceConfigTest.getInstanceConfigs().get(0);
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    return new ViewInstanceDefinition(viewDefinition, instanceConfig);
+  }
+}

+ 99 - 0
ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java

@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import org.apache.ambari.server.api.resources.SubResourceDefinition;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+import org.apache.ambari.server.view.configuration.ResourceConfigTest;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * ViewRegistry tests.
+ */
+public class ViewRegistryTest {
+  @Test
+  public void testAddGetDefinitions() throws Exception {
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+
+    ViewRegistry registry = ViewRegistry.getInstance();
+
+    registry.addDefinition(viewDefinition);
+
+    Assert.assertEquals(viewDefinition, registry.getDefinition("MY_VIEW"));
+
+    Collection<ViewDefinition> viewDefinitions = registry.getDefinitions();
+
+    Assert.assertEquals(1, viewDefinitions.size());
+
+    Assert.assertEquals(viewDefinition, viewDefinitions.iterator().next());
+  }
+
+  @Test
+  public void testAddGetInstanceDefinitions() throws Exception {
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewInstanceDefinition viewInstanceDefinition = ViewInstanceDefinitionTest.getViewInstanceDefinition();
+
+    ViewRegistry registry = ViewRegistry.getInstance();
+
+    registry.addDefinition(viewDefinition);
+
+    registry.addInstanceDefinition(viewDefinition, viewInstanceDefinition);
+
+    Assert.assertEquals(viewInstanceDefinition, registry.getInstanceDefinition("MY_VIEW", "INSTANCE1"));
+
+    Collection<ViewInstanceDefinition> viewInstanceDefinitions = registry.getInstanceDefinitions(viewDefinition);
+
+    Assert.assertEquals(1, viewInstanceDefinitions.size());
+
+    Assert.assertEquals(viewInstanceDefinition, viewInstanceDefinitions.iterator().next());
+  }
+
+  @Test
+  public void testGetSubResourceDefinitions() throws Exception {
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ViewRegistry registry = ViewRegistry.getInstance();
+
+    ResourceConfig config = ResourceConfigTest.getResourceConfigs().get(0);
+    Resource.Type type1 = new Resource.Type("myType");
+
+    viewDefinition.addResourceConfiguration(type1, config);
+    registry.addDefinition(viewDefinition);
+    Set<SubResourceDefinition> subResourceDefinitions = registry.getSubResourceDefinitions("MY_VIEW");
+
+    Assert.assertEquals(1, subResourceDefinitions.size());
+    Assert.assertEquals("myType", subResourceDefinitions.iterator().next().getType().name());
+  }
+
+  @Before
+  public void before() throws Exception {
+    ViewRegistry.getInstance().clear();
+  }
+
+  @AfterClass
+  public static void afterClass() {
+    ViewRegistry.getInstance().clear();
+  }
+}

+ 68 - 0
ambari-server/src/test/java/org/apache/ambari/server/view/ViewSubResourceDefinitionTest.java

@@ -0,0 +1,68 @@
+/**
+ * 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.SubResourceDefinition;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.view.configuration.ResourceConfig;
+import org.apache.ambari.server.view.configuration.ResourceConfigTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Set;
+
+/**
+ * ViewSubResourceDefinition tests.
+ */
+public class ViewSubResourceDefinitionTest {
+  @Test
+  public void testGetPluralName() throws Exception {
+    ViewSubResourceDefinition viewSubResourceDefinition = getViewSubResourceDefinition();
+
+    Assert.assertEquals("resources", viewSubResourceDefinition.getPluralName());
+  }
+
+  @Test
+  public void testGetSingularName() throws Exception {
+    ViewSubResourceDefinition viewSubResourceDefinition = getViewSubResourceDefinition();
+
+    Assert.assertEquals("resource", viewSubResourceDefinition.getSingularName());
+  }
+
+  @Test
+  public void testGetSubResourceDefinitions() throws Exception {
+    ViewSubResourceDefinition viewSubResourceDefinition = getViewSubResourceDefinition();
+
+    new Resource.Type("MY_VIEW/resource");
+    new Resource.Type("MY_VIEW/subresource");
+
+    Set<SubResourceDefinition> subResourceDefinitions = viewSubResourceDefinition.getSubResourceDefinitions ();
+
+    Assert.assertEquals(1, subResourceDefinitions.size());
+
+    Assert.assertEquals("MY_VIEW/subresource", subResourceDefinitions.iterator().next().getType().name());
+  }
+
+  public static ViewSubResourceDefinition getViewSubResourceDefinition() throws Exception {
+    ViewDefinition viewDefinition = ViewDefinitionTest.getViewDefinition();
+    ResourceConfig resourceConfig = ResourceConfigTest.getResourceConfigs().get(0);
+
+    return new ViewSubResourceDefinition(viewDefinition, resourceConfig);
+  }
+}

+ 40 - 0
ambari-views/src/main/java/org/apache/ambari/view/URLStreamProvider.java

@@ -0,0 +1,40 @@
+/**
+ * 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.view;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Provider of a URL stream.
+ */
+public interface URLStreamProvider {
+  /**
+   * Read from the input stream specified by the given URL spec.
+   *
+   * @param spec           the String to parse as a URL
+   * @param requestMethod  the HTTP method (GET,POST,PUT,etc.).
+   * @param params         the body of the request; may be null
+   *
+   * @return the input stream
+   *
+   * @throws IOException if an error occurred connecting to the server
+   */
+  public InputStream readFrom(String spec, String requestMethod, String params) throws IOException;
+}

+ 7 - 0
ambari-views/src/main/java/org/apache/ambari/view/ViewContext.java

@@ -62,4 +62,11 @@ public interface ViewContext {
    * @return the resource provider
    */
   public ResourceProvider<?> getResourceProvider(String type);
+
+  /**
+   * Get a URL stream provider.
+   *
+   * @return a stream provider
+   */
+  public URLStreamProvider getURLStreamProvider();
 }