ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From adorosz...@apache.org
Subject [17/49] ambari git commit: AMBARI-20436. Create a prototype of ambari-server swagger integration. (jaimin)
Date Tue, 23 May 2017 10:34:15 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
new file mode 100644
index 0000000..ad9c485
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/users/UserService.java
@@ -0,0 +1,193 @@
+/**
+ * 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.users;
+
+import java.util.Collections;
+
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.UserResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * Service responsible for user requests.
+ */
+@Path("/users/")
+@Api(value = "Users", description = "Endpoint for user specific operations")
+public class UserService extends BaseService {
+
+  /**
+   * Gets all users.
+   * Handles: GET /users requests.
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all users", notes = "Returns details of all users.", response = UserResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter user details", defaultValue = "Users/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "sortBy", value = "Sort users (asc | desc)", defaultValue = "Users/user_name.desc", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = UserResponse.class, responseContainer = "List")}
+  )
+  public Response getUsers(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET, createUserResource(null));
+  }
+
+  /**
+   * Gets a single user.
+   * Handles: GET /users/{username} requests
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param userName    the username
+   * @return information regarding the created user
+   */
+  @GET
+  @Path("{userName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get single user", notes = "Returns user details.", response = UserResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter user details", defaultValue = "Users", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = UserResponse.class)}
+  )
+  public Response getUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                          @ApiParam(value = "user name", required = true, defaultValue = "admin") @PathParam("userName") String userName) {
+    return handleRequest(headers, body, ui, Request.Type.GET, createUserResource(userName));
+  }
+
+  /**
+   * Creates a user.
+   * Handles: POST /users
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @return information regarding the created user
+   */
+  @POST
+  @Produces("text/plain")
+  public Response createUser(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.POST, createUserResource(null));
+  }
+
+  /**
+   * Creates a user.
+   * Handles: POST /users/{username}
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param userName    the username
+   * @return information regarding the created user
+   */
+  @POST
+  @Path("{userName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Create new user", notes = "Creates user resource.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.UserRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response createUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                             @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
+    return handleRequest(headers, body, ui, Request.Type.POST, createUserResource(userName));
+  }
+
+  /**
+   * Updates a specific user.
+   * Handles: PUT /users/{userName}
+   *
+   * @param headers     http headers
+   * @param ui          uri info
+   * @param userName   the username
+   * @return information regarding the updated user
+   */
+  @PUT
+  @Path("{userName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Update user detail", notes = "Updates user resource.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.UserRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response updateUser(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                             @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createUserResource(userName));
+  }
+
+  /**
+   * Deletes a user.
+   * Handles:  DELETE /users/{userName}
+   */
+  @DELETE
+  @Path("{userName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Delete single user", notes = "Delete user resource.")
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response deleteUser(@Context HttpHeaders headers, @Context UriInfo ui,
+                             @ApiParam(value = "user name", required = true) @PathParam("userName") String userName) {
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createUserResource(userName));
+  }
+
+  /**
+   * Create a user resource instance.
+   *
+   * @param userName  user name
+   *
+   * @return a user resource instance
+   */
+  private ResourceInstance createUserResource(String userName) {
+    return createResource(Resource.Type.User,
+        Collections.singletonMap(Resource.Type.User, userName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewDataMigrationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewDataMigrationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewDataMigrationService.java
new file mode 100644
index 0000000..388f454
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewDataMigrationService.java
@@ -0,0 +1,113 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.api.services.views;
+
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.view.ViewDataMigrationUtility;
+import org.apache.ambari.server.view.ViewRegistry;
+import org.apache.ambari.view.migration.ViewDataMigrationException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * Service responsible for data migration between view instances.
+ */
+@Api(tags = "Views", description = "Endpoint for view specific operations")
+@Path("/views/{viewName}/versions/{version}/instances/{instanceName}/migrate")
+public class ViewDataMigrationService extends BaseService {
+  /**
+   * Logger.
+   */
+  private static final Log LOG = LogFactory.getLog(ViewDataMigrationService.class);
+
+  /**
+   * The singleton view registry.
+   */
+  private ViewRegistry viewRegistry = ViewRegistry.getInstance();
+
+  /**
+   * The view data migration utility.
+   */
+  private ViewDataMigrationUtility viewDataMigrationUtility;
+
+  /**
+   * Migrates view instance persistence data from origin view instance
+   * specified in the path params.
+   *
+   * @param viewName           view id
+   * @param viewVersion        version id
+   * @param instanceName       instance id
+   * @param originViewVersion  the origin view version
+   * @param originInstanceName the origin view instance name
+   */
+  @PUT
+  @Path("{originVersion}/{originInstanceName}")
+  @ApiOperation(value = "Migrate view instance data", notes = "Migrates view instance persistence data from origin view instance specified in the path params.")
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response migrateData( @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                               @ApiParam(value = "view version") @PathParam("viewVersion") String viewVersion,
+                               @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName,
+                               @ApiParam(value = "origin version") @PathParam("originVersion") String originViewVersion,
+                               @ApiParam(value = "origin instance name") @PathParam("originInstanceName") String originInstanceName)
+      throws ViewDataMigrationException {
+
+    if (!viewRegistry.checkAdmin()) {
+      throw new WebApplicationException(Response.Status.FORBIDDEN);
+    }
+
+    LOG.info("Data Migration to view instance " + viewName + "/" + viewVersion + "/" + instanceName +
+        " from " + viewName + "/" + originViewVersion + "/" + originInstanceName);
+
+    ViewInstanceEntity instanceDefinition = viewRegistry.getInstanceDefinition(
+        viewName, viewVersion, instanceName);
+    ViewInstanceEntity originInstanceDefinition = viewRegistry.getInstanceDefinition(
+        viewName, originViewVersion, originInstanceName);
+
+    getViewDataMigrationUtility().migrateData(instanceDefinition, originInstanceDefinition, false);
+
+    Response.ResponseBuilder builder = Response.status(Response.Status.OK);
+    return builder.build();
+  }
+
+  protected ViewDataMigrationUtility getViewDataMigrationUtility() {
+    if (viewDataMigrationUtility == null) {
+      viewDataMigrationUtility = new ViewDataMigrationUtility(viewRegistry);
+    }
+    return viewDataMigrationUtility;
+  }
+
+  protected void setViewDataMigrationUtility(ViewDataMigrationUtility viewDataMigrationUtility) {
+    this.viewDataMigrationUtility = viewDataMigrationUtility;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewExternalSubResourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewExternalSubResourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewExternalSubResourceService.java
new file mode 100644
index 0000000..bca0f05
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewExternalSubResourceService.java
@@ -0,0 +1,148 @@
+/**
+ * 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.views;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.GET;
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+
+/**
+ * Service responsible for view sub-resource requests.
+ */
+public class ViewExternalSubResourceService  extends BaseService {
+
+  /**
+   * The resource type.
+   */
+  private final Resource.Type type;
+
+  /**
+   * The view name.
+   */
+  private final String viewName;
+
+  /**
+   * The view version.
+   */
+  private final String version;
+
+  /**
+   * The instance name.
+   */
+  private final String instanceName;
+
+  /**
+   * Mapping of resource names to services.
+   */
+  private final Map<String, Object> resourceServiceMap = new HashMap<String, Object>();
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  public ViewExternalSubResourceService(Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+    ViewEntity viewEntity = viewInstanceDefinition.getViewEntity();
+
+    this.type         = type;
+    this.viewName     = viewEntity.getCommonName();
+    this.version      = viewEntity.getVersion();
+    this.instanceName = viewInstanceDefinition.getName();
+  }
+
+  /**
+   * Handles URL: /resources
+   * Get all external resources for a view.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return instance collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  public Response getResources(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET,
+        createResource(viewName, instanceName));
+  }
+
+  /**
+   * Handles: GET /resources/{resourceName} Get a specific external resource.
+   *
+   * @param resourceName  resource name
+   *
+   * @return resource service instance representation
+   *
+   * @throws IllegalArgumentException if the given resource name is unknown
+   */
+  @Path("{resourceName}")
+  public Object getResource(@PathParam("resourceName") String resourceName) throws IOException {
+
+    Object service = resourceServiceMap.get(resourceName);
+    if (service == null) {
+      throw new IllegalArgumentException("A resource type " + resourceName + " for view instance " +
+          viewName + "/" + instanceName + " can not be found.");
+    }
+
+    return service;
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Register a sub-resource service.
+   *
+   * @param resourceName  the resource name
+   * @param service       the service
+   */
+  public void addResourceService(String resourceName, Object service) {
+    resourceServiceMap.put(resourceName, service);
+  }
+
+  /**
+   * Create an view instance resource.
+   *
+   * @param viewName      view name
+   * @param instanceName  instance name
+   *
+   * @return a view instance resource
+   */
+  private ResourceInstance createResource(String viewName, String instanceName) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, version);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+    return createResource(type, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewInstanceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewInstanceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewInstanceService.java
new file mode 100644
index 0000000..9657c0e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewInstanceService.java
@@ -0,0 +1,313 @@
+/*
+ * 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.views;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.WebApplicationException;
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.ViewInstanceResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+import org.apache.ambari.server.view.ViewRegistry;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ * Service responsible for instances resource requests.
+ */
+@Path("/views/{viewName}/versions/{version}/instances")
+@Api(tags = "Views", description = "Endpoint for view specific operations")
+public class ViewInstanceService extends BaseService {
+  /**
+   * The view registry;
+   */
+  private final ViewRegistry viewRegistry = ViewRegistry.getInstance();
+
+  /**
+   * Handles URL: /views/{viewName}/versions/{version}/instances
+   * Get all instances for a view.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   * @param version    version id
+   *
+   * @return instance collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all view instances", notes = "Returns all instances for a view version.", response = ViewInstanceResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view instance details", defaultValue = "ViewInstanceInfo/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "sortBy", value = "Sort users (asc | desc)", defaultValue = "ViewInstanceInfo/instance_name.desc", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewInstanceResponse.class, responseContainer = "List")}
+  )
+  public Response getServices(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                              @PathParam("viewName") String viewName, @PathParam("version") String version) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.GET, createResource(viewName, version, null));
+  }
+
+
+  /**
+   * Handles URL: /views/{viewName}/versions/{version}/instances/{instanceID}
+   * Get a specific instance.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return instance resource representation
+   */
+  @GET
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get single view instance", notes = "Returns view instance details.", response = ViewInstanceResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view instance details", defaultValue = "ViewInstanceInfo", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewInstanceResponse.class)}
+  )
+  public Response getService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                             @ApiParam(value = "view name") @PathParam("viewName") String viewName, @PathParam("version") String version,
+                             @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.GET, createResource(viewName, version, instanceName));
+  }
+
+
+  /**
+   * Handles: POST /views/{viewName}/versions/{version}/instances/{instanceId}
+   * Create a specific instance.
+   *
+   * @param body          http body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the created instance
+   */
+  @POST
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Create view instance", notes = "Creates view instance resource.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.ViewInstanceRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response createService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @ApiParam(value = "view name") @PathParam("viewName") String viewName, @PathParam("version") String version,
+                                @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.POST, createResource(viewName, version, instanceName));
+  }
+
+  /**
+   * Handles: POST /views/{viewName}/versions/{version}/instances
+   * Create multiple instances.
+   *
+   * @param body       http body
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   * @param version    version id
+   *
+   * @return information regarding the created instances
+   */
+  @POST
+  @Produces("text/plain")
+  public Response createServices(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                 @PathParam("viewName") String viewName, @PathParam("version") String version) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.POST, createResource(viewName, version, null));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}/instances/{instanceId}
+   * Update a specific instance.
+   *
+   * @param body          http body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName   view id
+   * @param version    version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the updated instance
+   */
+  @PUT
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Update view instance detail", notes = "Updates view instance resource.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.ViewInstanceRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response updateService(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                @ApiParam(value = "view name") @PathParam("viewName") String viewName, @PathParam("version") String version,
+                                @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createResource(viewName, version, instanceName));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}/instances
+   * Update multiple instances.
+   *
+   * @param body     http body
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param viewName   view id
+   * @param version    version id
+   *
+   * @return information regarding the updated instance
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response updateServices(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                 @PathParam("viewName") String viewName, @PathParam("version") String version) throws AuthorizationException {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createResource(viewName, version, null));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewName}/versions/{version}/instances/{instanceId}
+   * Delete a specific instance.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName   view id
+   * @param version    version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the deleted instance
+   */
+  @DELETE
+  @Path("{instanceName}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Delete view instance", notes = "Delete view resource.")
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response deleteService(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @ApiParam(value = "view name") @PathParam("viewName") String viewName, @PathParam("version") String version,
+                                @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) throws AuthorizationException {
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(viewName, version, instanceName));
+  }
+
+  /**
+   * Get the sub-resource
+   *
+   * @param instanceName  the instance id
+   *
+   * @return the service
+   */
+  @Path("{instanceName}/{resources}")
+  public Object getResourceHandler(@Context javax.ws.rs.core.Request request,
+                                   @PathParam("viewName") String viewName, @PathParam("version") String version,
+                                   @PathParam("instanceName") String instanceName,
+                                   @PathParam("resources") String resources) {
+
+    hasPermission(viewName, version, Request.Type.valueOf(request.getMethod()), instanceName);
+
+    ViewInstanceEntity instanceDefinition =
+        ViewRegistry.getInstance().getInstanceDefinition(viewName, version, instanceName);
+
+    if (instanceDefinition == null) {
+      throw new IllegalArgumentException("A view instance " +
+          viewName + "/" + instanceName + " can not be found.");
+    }
+
+    Object service = instanceDefinition.getService(resources);
+
+    if (service == null) {
+      throw new IllegalArgumentException("A resource type " + resources + " for view instance " +
+          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 createResource(String viewName, String viewVersion, String instanceName) {
+    Map<Resource.Type, String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+    return createResource(Resource.Type.ViewInstance, mapIds);
+  }
+
+  /**
+   * Determine whether or not the access specified by the given request type
+   * is permitted for the current user on the view instance resource identified
+   * by the given instance name.
+   *
+   * @param requestType   the request method type
+   * @param instanceName  the name of the view instance resource
+   *
+   * @throws WebApplicationException if access is forbidden
+   */
+  private void hasPermission(String viewName, String version, Request.Type requestType, String instanceName) {
+    if (!viewRegistry.checkPermission(viewName, version, instanceName, requestType == Request.Type.GET)) {
+      throw new WebApplicationException(Response.Status.FORBIDDEN);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPermissionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPermissionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPermissionService.java
new file mode 100644
index 0000000..cbc037b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPermissionService.java
@@ -0,0 +1,208 @@
+/**
+ * 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.views;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.ViewPermissionResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+
+/**
+ * Service responsible for custom view permission resource requests.
+ */
+@Path("/views/{viewName}/versions/{version}/permissions")
+@Api(value = "Views", description = "Endpoint for view specific operations")
+public class ViewPermissionService extends BaseService {
+
+  /**
+   * Handles: GET  /permissions
+   * Get all permissions.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   * @param version    version id
+   *
+   * @return permission collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all permissions for a view", notes = "Returns all permission details for the version of a view.", response = ViewPermissionResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter privileges", defaultValue = "PermissionInfo/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewPermissionResponse.class, responseContainer = "List")}
+  )
+  public Response getPermissions(@Context HttpHeaders headers, @Context UriInfo ui,
+                                 @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                 @ApiParam(value = "view version") @PathParam("version") String version) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+      viewName, version, null));
+  }
+
+  /**
+   * Handles: GET /views/{viewName}/versions/{version}/permissions/{permissionID}
+   * Get a specific permission.
+   *
+   * @param headers        http headers
+   * @param ui             uri info
+   * @param viewName       view id
+   * @param version        version id
+   * @param permissionId   permission id
+   *
+   * @return permission instance representation
+   */
+  @GET
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get single view permission", notes = "Returns permission details for a single version of a view.", response = ViewPermissionResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view permission details", defaultValue = "PermissionInfo", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewPermissionResponse.class)}
+  )
+  public Response getPermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                @ApiParam(value = "view version") @PathParam("version") String version,
+                                @ApiParam(value = "permission id") @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: POST /views/{viewName}/versions/{version}/permissions/{permissionID}
+   * Create a specific permission.
+   *
+   * @param headers        http headers
+   * @param ui             uri info
+   * @param viewName       view id
+   * @param version        version id
+   * @param permissionId   permission id
+   *
+   * @return information regarding the created permission
+   */
+  @POST
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response createPermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                   @ApiParam(value = "view version") @PathParam("version") String version,
+                                   @ApiParam(value = "permission id") @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}/permissions/{permissionID}
+   * Update a specific permission.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param permissionId  permission id
+   * @return information regarding the updated permission
+   */
+  @PUT
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response updatePermission(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                   @ApiParam(value = "view version") @PathParam("version") String version,
+                                   @ApiParam(value = "permission id") @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewName}/versions/{version}/permissions/{permissionID}
+   * Delete a specific permission.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param permissionId  permission id
+   *
+   * @return information regarding the deleted permission
+   */
+  @DELETE
+  @Path("{permissionId}")
+  @Produces("text/plain")
+  public Response deletePermission(@Context HttpHeaders headers, @Context UriInfo ui,
+                                   @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                   @ApiParam(value = "view version") @PathParam("version") String version,
+                                   @ApiParam(value = "permission id") @PathParam("permissionId") String permissionId) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createPermissionResource(
+        viewName, version, permissionId));
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a permission resource.
+   *
+   * @param permissionId permission name
+   *
+   * @return a permission resource instance
+   */
+  protected ResourceInstance createPermissionResource(String viewName, String viewVersion, String permissionId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewPermission, permissionId);
+
+    return createResource(Resource.Type.ViewPermission, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPrivilegeService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPrivilegeService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPrivilegeService.java
new file mode 100644
index 0000000..e6d817f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewPrivilegeService.java
@@ -0,0 +1,268 @@
+/**
+ * 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 privileges and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services.views;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.ViewPrivilegeResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+/**
+ *  Service responsible for view privilege resource requests.
+ */
+@Api(tags = "Views", description = "Endpoint for view specific operations")
+@Path("/views/{viewName}/versions/{version}/instances/{instanceName}/privileges")
+public class ViewPrivilegeService extends BaseService {
+  /**
+   * Handles: GET  /views/{viewName}/versions/{version}/instances/{instanceName}/privileges
+   * Get all privileges.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return privilege collection representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all view instance privileges", notes = "Returns all privileges for the resource.", response = ViewPrivilegeResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter privileges", defaultValue = "PrivilegeInfo/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "sortBy", value = "Sort privileges (asc | desc)", defaultValue = "PrivilegeInfo/user_name.asc", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  public Response getPrivileges(@Context HttpHeaders headers, @Context UriInfo ui,
+                                @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                @ApiParam(value = "view version") @PathParam("version") String version,
+                                @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) {
+    return handleRequest(headers, null, ui, Request.Type.GET, createPrivilegeResource(viewName, version, instanceName,null));
+  }
+
+  /**
+   * Handles: GET /views/{viewName}/versions/{version}/instances/{instanceName}/privileges/{privilegeID}
+   * Get a specific privilege.
+   *
+   * @param headers        http headers
+   * @param ui             uri info
+   * @param viewName       view id
+   * @param version        version id
+   * @param instanceName   instance id
+   * @param privilegeId    privilege id
+   *
+   * @return privilege instance representation
+   */
+  @GET
+  @Path("/{privilegeId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get single view instance privilege", notes = "Returns privilege details.", response = ViewPrivilegeResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter privilege details", defaultValue = "PrivilegeInfo", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewPrivilegeResponse.class)}
+  )
+  public Response getPrivilege(@Context HttpHeaders headers, @Context UriInfo ui,
+                               @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                               @ApiParam(value = "view version") @PathParam("version") String version,
+                               @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName,
+                               @ApiParam(value = "privilege id", required = true) @PathParam("privilegeId") String privilegeId) {
+
+    return handleRequest(headers, null, ui, Request.Type.GET, createPrivilegeResource(viewName, version, instanceName,privilegeId));
+  }
+
+  /**
+   * Handles: POST /views/{viewName}/versions/{version}/instances/{instanceName}/privileges
+   * Create a privilege.
+   *
+   * @param body          request body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the created privilege
+   */
+  @POST
+  @Produces("text/plain")
+  @ApiOperation(value = "Create view instance privilege", notes = "Create privilege resource for view instance.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.ViewPrivilegeRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response createPrivilege(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                  @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                  @ApiParam(value = "view version") @PathParam("version") String version,
+                                  @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createPrivilegeResource(viewName, version, instanceName,null));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}/instances/{instanceName}/privileges/{privilegeID}
+   * Update a specific privilege.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   * @param privilegeId   privilege id
+   *
+   * @return information regarding the updated privilege
+   */
+  @PUT
+  // Remove comments when the below API call is fixed
+  /*@Path("{privilegeId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Update view instance privilege", notes = "Update privilege resource for view instance.")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "body", value = "input parameters in json form", required = true, dataType = "org.apache.ambari.server.controller.ViewPrivilegeRequest", paramType = "body")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  ) */
+  public Response updatePrivilege(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                  @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                  @ApiParam(value = "view version") @PathParam("version") String version,
+                                  @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName,
+                                  @ApiParam(value = "privilege id") @PathParam("privilegeId") String privilegeId) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createPrivilegeResource(viewName, version, instanceName, privilegeId));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}/instances/{instanceName}/privileges
+   * Update a set of privileges for the resource.
+   *
+   * @param body          request body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the updated privileges
+   */
+  @PUT
+  @Produces("text/plain")
+  public Response updatePrivileges(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                   @ApiParam(value = "view version") @PathParam("version") String version,
+                                   @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) {
+    return handleRequest(headers, body, ui, Request.Type.PUT, createPrivilegeResource(viewName, version, instanceName,null));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewName}/versions/{version}/instances/{instanceName}/privileges
+   * Delete privileges.
+   *
+   * @param body          request body
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   *
+   * @return information regarding the deleted privileges
+   */
+  @DELETE
+  @Produces("text/plain")
+  public Response deletePrivileges(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                   @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                   @ApiParam(value = "view version") @PathParam("viewVersion") String version,
+                                   @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName) {
+
+    return handleRequest(headers, body, ui, Request.Type.DELETE, createPrivilegeResource(viewName, version, instanceName,null));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewName}/versions/{version}/instances/{instanceName}/privileges/{privilegeID}
+   * Delete a specific privilege.
+   *
+   * @param headers       http headers
+   * @param ui            uri info
+   * @param viewName      view id
+   * @param version       version id
+   * @param instanceName  instance id
+   * @param privilegeId   privilege id
+   *
+   * @return information regarding the deleted privilege
+   */
+  @DELETE
+  @Path("{privilegeId}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Delete view instance privilege", notes = "Delete view instance privilege resource.")
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation"),
+    @ApiResponse(code = 500, message = "Server Error")}
+  )
+  public Response deletePrivilege(@Context HttpHeaders headers, @Context UriInfo ui,
+                                  @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                  @ApiParam(value = "view version") @PathParam("version") String version,
+                                  @ApiParam(value = "instance name") @PathParam("instanceName") String instanceName,
+                                  @ApiParam(value = "privilege id") @PathParam("privilegeId") String privilegeId) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createPrivilegeResource(viewName, version, instanceName, privilegeId));
+  }
+
+
+  protected ResourceInstance createPrivilegeResource(String viewName, String viewVersion, String instanceName, String privilegeId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, viewVersion);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+    mapIds.put(Resource.Type.ViewPrivilege, privilegeId);
+
+    return createResource(Resource.Type.ViewPrivilege, mapIds);
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewService.java
new file mode 100644
index 0000000..1936d5b
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewService.java
@@ -0,0 +1,181 @@
+/**
+ * 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.views;
+
+import java.util.Collections;
+
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.ViewResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+
+/**
+ * Service responsible for view resource requests.
+ */
+@Path("/views/")
+@Api(value = "Views", description = "Endpoint for view specific operations")
+public class ViewService extends BaseService {
+
+  /**
+   * Handles: GET  /views
+   * Get all views.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   *
+   * @return view collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all views", notes = "Returns details of all views.", response = ViewResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view details", defaultValue = "ViewInfo/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "sortBy", value = "Sort users (asc | desc)", defaultValue = "ViewInfo/view_name.asc", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewResponse.class, responseContainer = "List")}
+  )
+  public Response getViews(String body, @Context HttpHeaders headers, @Context UriInfo ui) {
+    return handleRequest(headers, body, ui, Request.Type.GET, createViewResource(null));
+  }
+
+  /**
+   * 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")
+  @ApiOperation(value = "Get single view", notes = "Returns view details.", response = ViewResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view details", defaultValue = "ViewInfo", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewResponse.class)}
+  )
+  public Response getView(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                          @ApiParam(value = "view name", required = true) @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET, createViewResource(viewName));
+  }
+
+
+  /**
+   * 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,
+                             @ApiParam(value = "view name", required = true) @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,
+                             @ApiParam(value = "view name", required = true) @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createViewResource(viewName));
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a view resource.
+   *
+   * @param viewName view name
+   *
+   * @return a view resource instance
+   */
+  private ResourceInstance createViewResource(String viewName) {
+    return createResource(Resource.Type.View,
+        Collections.singletonMap(Resource.Type.View, viewName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewSubResourceService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewSubResourceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewSubResourceService.java
new file mode 100644
index 0000000..081d699
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewSubResourceService.java
@@ -0,0 +1,136 @@
+/**
+ * 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.views;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.view.ViewResourceHandler;
+
+/**
+ * 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 view version.
+   */
+  private final String version;
+
+  /**
+   * The associated view instance name.
+   */
+  private final String instanceName;
+
+
+  // ----- Constructors ------------------------------------------------------
+
+  /**
+   * Construct a view sub-resource service.
+   */
+  public ViewSubResourceService(Resource.Type type, ViewInstanceEntity viewInstanceDefinition) {
+    ViewEntity viewEntity = viewInstanceDefinition.getViewEntity();
+
+    this.type         = type;
+    this.viewName     = viewEntity.getCommonName();
+    this.version      = viewEntity.getVersion();
+    this.instanceName = viewInstanceDefinition.getName();
+  }
+
+
+  // ----- ViewResourceHandler -----------------------------------------------
+
+  @Override
+  public Response handleRequest(HttpHeaders headers, UriInfo ui,
+                                RequestType requestType, MediaType mediaType,
+                                String resourceId) {
+    return handleRequest(headers, null, ui, getRequestType(requestType),
+        getMediaType(mediaType), createResource(resourceId));
+  }
+
+  @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
+  protected ResourceInstance createResource(String resourceId) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type,String>();
+
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, version);
+    mapIds.put(Resource.Type.ViewInstance, instanceName);
+
+    if (resourceId != null) {
+      mapIds.put(type, resourceId);
+    }
+    return super.createResource(type, mapIds);
+  }
+
+  // get the internal request type from the view API request type
+  private Request.Type getRequestType(RequestType type) {
+    switch (type) {
+      case GET:
+        return Request.Type.GET;
+      case POST:
+        return Request.Type.POST;
+      case PUT:
+        return Request.Type.PUT;
+      case DELETE:
+        return Request.Type.DELETE;
+      case QUERY_POST:
+        return Request.Type.QUERY_POST;
+    }
+    throw new IllegalArgumentException("Unknown resource type " + type);
+  }
+
+  // get the JAX-RS media type from the view media type
+  private javax.ws.rs.core.MediaType getMediaType(MediaType type) {
+    switch (type) {
+      case TEXT_PLAIN:
+        return javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+      case APPLICATION_JSON:
+        return javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+    }
+    throw new IllegalArgumentException("Unknown media type " + type);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewVersionService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewVersionService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewVersionService.java
new file mode 100644
index 0000000..ed6ddb1
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/views/ViewVersionService.java
@@ -0,0 +1,208 @@
+/**
+ * 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.views;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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 org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.BaseService;
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.controller.ViewVersionResponse;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+
+/**
+ * Service responsible for view version resource requests.
+ */
+@Path("/views/{viewName}/versions")
+@Api(value = "Views", description = "Endpoint for view specific operations")
+public class ViewVersionService extends BaseService {
+
+  /**
+   * Handles: GET  /views/{viewName}/versions
+   * Get all views versions.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param viewName   view id
+   *
+   * @return view collection resource representation
+   */
+  @GET
+  @Produces("text/plain")
+  @ApiOperation(value = "Get all versions for a view", notes = "Returns details of all versions for a view.", response = ViewVersionResponse.class, responseContainer = "List")
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view version details", defaultValue = "ViewVersionInfo/*", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "sortBy", value = "Sort users (asc | desc)", defaultValue = "ViewVersionInfo/version.desc", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "page_size", value = "The number of resources to be returned for the paged response.", defaultValue = "10", dataType = "integer", paramType = "query"),
+    @ApiImplicitParam(name = "from", value = "The starting page resource (inclusive). Valid values are :offset | \"start\"", defaultValue = "0", dataType = "string", paramType = "query"),
+    @ApiImplicitParam(name = "to", value = "The ending page resource (inclusive). Valid values are :offset | \"end\"", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewVersionResponse.class, responseContainer = "List")}
+  )
+  public Response getVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                              @ApiParam(value = "view name") @PathParam("viewName") String viewName) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET, createResource(viewName, null));
+  }
+
+
+  /**
+   * Handles: GET /views/{viewName}/versions/{version}
+   * Get a specific view version.
+   *
+   * @param headers  http headers
+   * @param ui       uri info
+   * @param viewName   view id
+   * @param version  version id
+   *
+   * @return view instance representation
+   */
+  @GET
+  @Path("{version}")
+  @Produces("text/plain")
+  @ApiOperation(value = "Get single view version", notes = "Returns view details.", response = ViewVersionResponse.class)
+  @ApiImplicitParams({
+    @ApiImplicitParam(name = "fields", value = "Filter view details", defaultValue = "ViewVersionInfo", dataType = "string", paramType = "query")
+  })
+  @ApiResponses(value = {
+    @ApiResponse(code = 200, message = "Successful operation", response = ViewVersionResponse.class)}
+  )
+  public Response getVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                              @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                              @PathParam("version") String version) {
+
+    return handleRequest(headers, body, ui, Request.Type.GET, createResource(viewName, version));
+  }
+
+  /**
+   * Handles: POST /views/{viewName}/versions/{version}
+   * Create a specific view version.
+   *
+   * @param headers    http headers
+   * @param ui         uri info
+   * @param viewName   view id
+   * @param version    the version
+   *
+   * @return information regarding the created view
+   */
+  @POST
+  @Path("{version}")
+  @Produces("text/plain")
+  public Response createVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                 @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                 @PathParam("version") String version) {
+
+    return handleRequest(headers, body, ui, Request.Type.POST, createResource(viewName, version));
+  }
+
+  /**
+   * Handles: PUT /views/{viewName}/versions/{version}
+   * Update a specific view version.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param viewName  view id
+   * @param version   the version
+   *
+   * @return information regarding the updated view
+   */
+  @PUT
+  @Path("{version}")
+  @Produces("text/plain")
+  public Response updateVersions(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+                                 @ApiParam(value = "view name") @PathParam("viewName") String viewName,
+                                 @PathParam("version") String version) {
+
+    return handleRequest(headers, body, ui, Request.Type.PUT, createResource(viewName, version));
+  }
+
+  /**
+   * Handles: DELETE /views/{viewName}/versions/{version}
+   * Delete a specific view version.
+   *
+   * @param headers   http headers
+   * @param ui        uri info
+   * @param viewName   view id
+   * @param version   version id
+   *
+   * @return information regarding the deleted view version
+   */
+  @DELETE
+  @Path("{version}")
+  @Produces("text/plain")
+  public Response deleteVersions(@Context HttpHeaders headers, @Context UriInfo ui,
+                                 @PathParam("viewName") String viewName, @PathParam("version") String version) {
+
+    return handleRequest(headers, null, ui, Request.Type.DELETE, createResource(viewName, version));
+  }
+
+
+  /**
+   * Get the permissions sub-resource
+   *
+   * @param version  the version
+   *
+   * @return the permission service
+
+  @Path("{version}/permissions")
+  public ViewPermissionService getPermissionHandler(@PathParam("version") String version) {
+
+    return new ViewPermissionService(viewName, version);
+  }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Create a view resource.
+   *
+   * @param viewName view name
+   *
+   * @return a view resource instance
+   */
+  private ResourceInstance createResource(String viewName, String version) {
+    Map<Resource.Type,String> mapIds = new HashMap<Resource.Type, String>();
+    mapIds.put(Resource.Type.View, viewName);
+    mapIds.put(Resource.Type.ViewVersion, version);
+    return createResource(Resource.Type.ViewVersion, mapIds);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutRequest.java
new file mode 100644
index 0000000..b137abd
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutRequest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+import java.util.List;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.services.users.ActiveWidgetLayoutService;
+
+import io.swagger.annotations.ApiModelProperty;
+
+
+/**
+ * Wrapper class for request body schema of {@link ActiveWidgetLayoutService#updateServices(String, HttpHeaders, UriInfo, String)}
+ */
+public class ActiveWidgetLayoutRequest implements ApiModel {
+   private List<WidgetLayoutIdWrapper> widgetLayouts;
+
+  /**
+   * Returns all widget layouts
+   * @return widget layouts
+   */
+  @ApiModelProperty(name = "WidgetLayouts")
+  public List<WidgetLayoutIdWrapper> getWidgetLayouts() {
+    return widgetLayouts;
+  }
+
+  private class WidgetLayoutIdWrapper {
+    private Long id;
+
+    /**
+     * Returns widget layout id
+     * @return {@link #id}
+     */
+    public Long getId() {
+      return id;
+    }
+
+    /**
+     * Sets widget layout id
+     * @param id
+     */
+    public void setId(Long id) {
+      this.id = id;
+    }
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutResponse.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutResponse.java
new file mode 100644
index 0000000..c18b55a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ActiveWidgetLayoutResponse.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller;
+
+import java.util.HashMap;
+import java.util.List;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.ambari.server.api.services.users.ActiveWidgetLayoutService;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * Response schema for endpoint {@link ActiveWidgetLayoutService#getServices(String, HttpHeaders, UriInfo, String)}
+ */
+public class ActiveWidgetLayoutResponse implements ApiModel {
+
+  private final Long id;
+  private final String clusterName;
+  private final String displayName;
+  private final String layoutName;
+  private final String scope;
+  private final String sectionName;
+  private final String userName;
+  private List<HashMap<String, WidgetResponse>> widgets;
+
+  /**
+   *
+   * @param id
+   * @param clusterName   cluster name
+   * @param displayName   display name
+   * @param layoutName    layout name
+   * @param sectionName   section name
+   * @param scope         scope
+   * @param userName      user name
+   * @param widgets       widgets
+   */
+  public ActiveWidgetLayoutResponse(Long id, String clusterName, String displayName, String layoutName, String sectionName, String scope, String userName, List<HashMap<String, WidgetResponse>> widgets) {
+    this.id = id;
+    this.clusterName = clusterName;
+    this.displayName = displayName;
+    this.layoutName = layoutName;
+    this.sectionName = sectionName;
+    this.scope = scope;
+    this.userName = userName;
+    this.widgets = widgets;
+  }
+
+  /**
+   * Returns id for the widget layout
+   * @return widget layout id
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/id", hidden=true)
+  public Long getId() {
+    return id;
+  }
+
+  /**
+   * Returns cluster name for the widget layout
+   * @return cluster name
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/cluster_name")
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  /**
+   * Returns display name for the widget layout
+   * @return  display name
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/display_name")
+  public String getDisplayName() {
+    return displayName;
+  }
+
+  /**
+   * Returns layout name
+   * @return  layout name
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/layout_name")
+  public String getLayoutName() {
+    return layoutName;
+  }
+
+  /**
+   * Returns scope
+   * @return scope
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/scope")
+  public String getScope() {
+    return scope;
+  }
+
+  /**
+   * Returns section name
+   * @return section name
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/section_name")
+  public String getSectionName() {
+    return sectionName;
+  }
+
+  /**
+   * Returns user name
+   * @return user name
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/user_name")
+  public String getUserName() {
+    return userName;
+  }
+
+  /**
+   * Returns widgets of the layout
+   * @return  widgets
+   */
+  @ApiModelProperty(name = "WidgetLayoutInfo/widgets")
+  public List<HashMap<String, WidgetResponse>> getWidgets() {
+    return widgets;
+  }
+
+  public void setWidgets(List<HashMap<String, WidgetResponse>> widgets) {
+    this.widgets = widgets;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/fb86fb3b/ambari-server/src/main/java/org/apache/ambari/server/controller/ApiModel.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ApiModel.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ApiModel.java
new file mode 100644
index 0000000..ffca19e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ApiModel.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.controller;
+
+import org.apache.ambari.server.controller.internal.BaseProvider;
+
+/**
+ * inherits from swagger {@link ApiModel}
+ * This should be a return type for getResponse method in {@link BaseProvider}
+ */
+@io.swagger.annotations.ApiModel
+public interface ApiModel {
+}


Mime
View raw message