atlas-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mad...@apache.org
Subject [04/25] incubator-atlas git commit: ATLAS-1898: initial commit of ODF
Date Wed, 28 Jun 2017 05:57:17 GMT
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnalysesResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnalysesResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnalysesResource.java
new file mode 100755
index 0000000..a3bc3b2
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnalysesResource.java
@@ -0,0 +1,156 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.util.logging.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.atlas.odf.api.analysis.AnalysisCancelResult;
+import org.apache.atlas.odf.api.analysis.AnalysisRequest;
+import org.apache.atlas.odf.api.analysis.AnalysisRequestStatus;
+import org.apache.atlas.odf.api.analysis.AnalysisResponse;
+import org.apache.atlas.odf.json.JSONUtils;
+import org.apache.wink.json4j.JSONException;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.analysis.AnalysisRequestSummary;
+import org.apache.atlas.odf.api.analysis.AnalysisRequestTrackers;
+import org.apache.atlas.odf.api.ODFFactory;
+
+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;
+
+@Path("/analyses")
+@Api(value = "/analyses", description = "Create and view analysis requests", produces = MediaType.APPLICATION_JSON)
+public class AnalysesResource {
+	private Logger logger = Logger.getLogger(AnalysesResource.class.getName());
+
+	@GET
+	@Path("/stats")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get analysis request statistics", httpMethod = "GET", notes = "Return number of successfull and failing analysis requests", response = AnalysisRequestSummary.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getStats() {
+		try {
+			return Response.ok(JSONUtils.toJSON(new ODFFactory().create().getAnalysisManager().getAnalysisStats())).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get list of analysis requests", httpMethod = "GET", notes = "Retrieve list of recent analysis requests (from latest to oldest)", responseContainer="List", response = AnalysisRequestTrackers.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getAnalysisRequests(
+			@ApiParam(value = "Starting offset (use 0 to start with the latest request).", required = false)
+			@DefaultValue("0") @QueryParam("offset") int offset,
+			@ApiParam(value = "Maximum number of analysis requests to be returned (use -1 to retrieve all requests).", required = false)
+			@DefaultValue("10") @QueryParam("limit") int limit) {
+		try {
+			String result = JSONUtils.toJSON(new ODFFactory().create().getAnalysisManager().getAnalysisRequests(offset, limit));
+			return Response.ok(result).build();
+		} catch (Exception exc) {
+			throw new RuntimeException(exc);
+		}
+	}
+
+	@GET
+	@Path("/{requestId}")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get analysis request status", httpMethod = "GET", notes = "Show status of a specific analysis request", response = AnalysisRequestStatus.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getAnalysisStatus(
+			@ApiParam(value = "ID of the analysis request", required = true)
+			@PathParam("requestId") String requestId) {
+		logger.entering(AnalysesResource.class.getName(), "getAnalysisStatus");
+		AnalysisRequestStatus analysisRequestStatus = new ODFFactory().create().getAnalysisManager().getAnalysisRequestStatus(requestId);
+		try {
+			return Response.ok(JSONUtils.toJSON(analysisRequestStatus)).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@POST
+	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Run analysis", httpMethod = "POST", notes = "Create and run new analysis request", response = AnalysisResponse.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response startAnalysis(@ApiParam(value = "Analysis request to be started", required = true) AnalysisRequest request) {
+		logger.entering(AnalysesResource.class.getName(), "startAnalysis");
+		try {
+			AnalysisResponse analysisResponse = new ODFFactory().create().getAnalysisManager().runAnalysis(request);
+			return Response.ok(JSONUtils.toJSON(analysisResponse)).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@POST
+	@Path("/{requestId}/cancel")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Cancel analysis request", httpMethod = "POST", notes = "Cancel a queued analysis request that has not been started yet", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request - The request with the provided id could not be found"),
+			@ApiResponse(code = 403, message = "Forbidden - The status of the analysis request does not allow for cancellation")
+	})
+	public Response cancelAnalysisRequest(@ApiParam(value = "ID of the analysis request", required = true) @PathParam("requestId") String requestId) {
+		logger.entering(AnalysesResource.class.getName(), "cancelAnalysisRequest");
+		AnalysisCancelResult result = new ODFFactory().create().getAnalysisManager().cancelAnalysisRequest(requestId);
+		if (result.getState() == AnalysisCancelResult.State.NOT_FOUND) {
+			return Response.status(Status.BAD_REQUEST).build();
+		} else if (result.getState() == AnalysisCancelResult.State.INVALID_STATE) {
+			return Response.status(Status.FORBIDDEN).build();
+		}
+		return Response.ok().build();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnnotationsResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnnotationsResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnnotationsResource.java
new file mode 100755
index 0000000..704b004
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/AnnotationsResource.java
@@ -0,0 +1,130 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.metadata.MetaDataObjectReference;
+import org.apache.atlas.odf.api.metadata.models.Annotation;
+import org.apache.atlas.odf.api.ODFFactory;
+import org.apache.atlas.odf.api.annotation.AnnotationStore;
+import org.apache.atlas.odf.api.annotation.AnnotationStoreUtils;
+import org.apache.atlas.odf.api.annotation.Annotations;
+import org.apache.atlas.odf.json.JSONUtils;
+
+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;
+
+@Path("/annotations")
+@Api(value = "/annotations", description = "Create and query ODF annotations", produces = MediaType.APPLICATION_JSON)
+public class AnnotationsResource {
+
+	Logger logger = Logger.getLogger(AnnotationsResource.class.getName());
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Retrieve annotations", httpMethod = "GET", notes = "Retrieve annotations for an asset and/or for a specific analysis request.", response = Annotations.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response retrieveAnnotationsForAsset(@ApiParam(value = "Reference ID of the asset", required = false) @QueryParam("assetReference") String assetReference,
+			@ApiParam(value = "Analysis request ID", required = false) @QueryParam("analysisRequestId") String analysisRequestId) {
+		try {
+			MetaDataObjectReference ref = null;
+			if (assetReference != null) {
+				ref = new MetaDataObjectReference();
+				String repoId = new ODFFactory().create().getMetadataStore().getRepositoryId();
+				ref.setRepositoryId(repoId);
+				ref.setId(assetReference);
+			}
+			AnnotationStore as = new ODFFactory().create().getAnnotationStore();
+			List<Annotation> annots = as.getAnnotations(ref, analysisRequestId);
+			Annotations result = new Annotations();
+			result.setAnnotations(annots);
+			return Response.ok(JSONUtils.toJSON(result)).build();
+		} catch (Exception exc) {
+			logger.log(Level.WARNING, "An exception occurred while retrieving annotations", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+	}
+
+
+	@GET
+	@Path("/objects/{objectReference}")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Retrieve annotation", httpMethod = "GET", notes = "Retrieve annotation by Id.", response = Annotation.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response retrieveAnnotation(@ApiParam(value = "Reference ID of the annotation", required = true) @PathParam("objectReference") String objectReference) {
+		try {
+			MetaDataObjectReference ref = new MetaDataObjectReference();
+			AnnotationStore as = new ODFFactory().create().getAnnotationStore();
+			ref.setRepositoryId(as.getRepositoryId());
+			ref.setId(objectReference);
+			Annotation annot = as.retrieveAnnotation(ref);
+			return Response.ok(JSONUtils.toJSON(annot)).build();
+		} catch (Exception exc) {
+			logger.log(Level.WARNING, "An exception occurred while retrieving annotation", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+	}
+
+
+	// no swagger documentation as this will be replaced by "annotation propagation"
+	@GET
+	@Path("/newestAnnotations/{assetReference}")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response retrieveMostRecentAnnotations(@PathParam("assetReference") String assetReference) {
+		try {
+			MetaDataObjectReference ref = JSONUtils.fromJSON(assetReference, MetaDataObjectReference.class);
+			AnnotationStore as = new ODFFactory().create().getAnnotationStore();
+			List<Annotation> annotations = AnnotationStoreUtils.getMostRecentAnnotationsByType(as, ref);
+			String result = JSONUtils.toJSON(annotations);
+			return Response.ok(result).build();
+		} catch (Exception e) {
+			logger.log(Level.WARNING, "An exception occurred while retrieving most recent annotations", e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@POST
+	@ApiOperation(value = "Create annotation", httpMethod = "POST", notes = "Create new annotation object", response = MetaDataObjectReference.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response createAnnotation(@ApiParam(value = "Analysis request to be started", required = true) String annotString) {
+		try {
+			Annotation annot = JSONUtils.fromJSON(annotString, Annotation.class);
+			AnnotationStore as = new ODFFactory().create().getAnnotationStore();
+			MetaDataObjectReference annotRef = as.store(annot);
+			return Response.status(Status.CREATED).entity(JSONUtils.toJSON(annotRef)).build();
+		} catch (Exception exc) {
+			logger.log(Level.WARNING, "An exception occurred while storing an annotation", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/DiscoveryServicesResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/DiscoveryServicesResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/DiscoveryServicesResource.java
new file mode 100755
index 0000000..bd01e60
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/DiscoveryServicesResource.java
@@ -0,0 +1,341 @@
+/**
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.ws.rs.Consumes;
+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.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.atlas.odf.api.settings.validation.ValidationException;
+import org.apache.wink.json4j.JSONException;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.ODFFactory;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceManager;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceProperties;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceRuntimeStatistics;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceStatus;
+import org.apache.atlas.odf.api.discoveryservice.ServiceNotFoundException;
+import org.apache.atlas.odf.api.discoveryservice.ServiceStatusCount;
+import org.apache.atlas.odf.json.JSONUtils;
+
+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;
+
+@Path("/services")
+@Api(value = "/services", description = "Manage ODF services", produces = MediaType.APPLICATION_JSON)
+public class DiscoveryServicesResource {
+	private Logger logger = Logger.getLogger(DiscoveryServicesResource.class.getName());
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get list of discovery services", httpMethod = "GET", notes = "Retrieve list of all discovery services registered in ODF", responseContainer="List", response = DiscoveryServiceProperties.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getDiscoveryServices() {
+		logger.entering(DiscoveryServicesResource.class.getName(), "getServices");
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response;
+		List<DiscoveryServiceProperties> dsProperties = dsAdmin.getDiscoveryServicesProperties();
+		try {
+			String json = JSONUtils.toJSON(dsProperties);
+			response = Response.ok(json).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			response = RestUtils.createErrorResponse(e);
+		}
+		return response;
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@Path("/status")
+	@ApiOperation(value = "Get status of discovery services", httpMethod = "GET", notes = "Retrieve status overview of all discovery services registered in ODF", responseContainer="List", response = ServiceStatusCount.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 404, message = "Not found"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getAllServicesStatus() {
+		logger.entering(DiscoveryServicesResource.class.getName(), "getAllServicesStatus");
+		List<ServiceStatusCount> servicesStatus = new ODFFactory().create().getDiscoveryServiceManager().getDiscoveryServiceStatusOverview();
+		if (servicesStatus == null) {
+			return Response.status(Status.NOT_FOUND).build();
+		}
+		String json;
+		try {
+			json = JSONUtils.toJSON(servicesStatus);
+		} catch (JSONException e) {
+			throw new RuntimeException(e);
+		}
+		return Response.ok(json).build();
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@Path("/{serviceId}/status")
+	@ApiOperation(value = "Get discovery service status", httpMethod = "GET", notes = "Retrieve status of a discovery service that is registered in ODF", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 404, message = "Not found"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getDiscoveryServiceStatus(
+			@ApiParam(value = "Discovery service ID", required = true)
+			@PathParam("serviceId") String serviceId) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "getDiscoveryServiceStatus");
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response;
+		try {
+			DiscoveryServiceStatus dsStatus = dsAdmin.getDiscoveryServiceStatus(serviceId);
+			if (dsStatus == null) {
+				response = Response.status(Status.NOT_FOUND).build();
+			}
+			else {
+				try {
+					String json = JSONUtils.toJSON(dsStatus);
+					response = Response.ok(json).build();
+				} catch (JSONException e) {
+					e.printStackTrace();
+					logger.info("Parse exception " + e);
+					response = RestUtils.createErrorResponse(e);
+				}
+			}
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		return response;
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@Path("/{serviceId}/runtimeStats")
+	@ApiOperation(value = "Get runtime statistics of a discovery service", httpMethod = "GET", notes = "Retrieve the runtime statistics of a discovery service that is registered in ODF.", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 404, message = "Not found"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getDiscoveryServiceRuntimeStats(
+			@ApiParam(value = "Discovery service ID", required = true)
+			@PathParam("serviceId") String serviceId) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "getDiscoveryServiceRuntimeStats");
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response;
+		try {
+			DiscoveryServiceRuntimeStatistics dsRuntimeStats = dsAdmin.getDiscoveryServiceRuntimeStatistics(serviceId);
+			String json = JSONUtils.toJSON(dsRuntimeStats);
+			response = Response.ok(json).build();
+		}
+		catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			response = RestUtils.createErrorResponse(e);
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		return response;
+	}
+
+	@DELETE
+	@Path("/{serviceId}/runtimeStats")
+	@ApiOperation(value = "Delete runtime statistics of a discovery service", httpMethod = "DELETE", notes = "Delete the runtime statistics of a discovery service that is registered in ODF.", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 404, message = "Not found"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response deleteDiscoveryServiceRuntimeStats(
+			@ApiParam(value = "Discovery service ID", required = true)
+			@PathParam("serviceId") String serviceId) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "deleteDiscoveryServiceRuntimeStats");
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response;
+		try {
+			dsAdmin.deleteDiscoveryServiceRuntimeStatistics(serviceId);
+			response = Response.ok().build();
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		return response;
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@Path("/{serviceId}")
+	@ApiOperation(value = "Get properties of a discovery service registered in ODF", httpMethod = "GET", notes = "Retrieve properties of a discovery service that is registered in ODF", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 404, message = "Not found"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getDiscoveryServiceProperties(
+			@ApiParam(value = "Id string of discovery service", required = true)
+			@PathParam("serviceId") String serviceId) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "getDiscoveryServiceProperties");
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response;
+		try {
+			DiscoveryServiceProperties dsStatus = dsAdmin.getDiscoveryServiceProperties(serviceId);
+			if (dsStatus == null) {
+				response = Response.status(Status.NOT_FOUND).build();
+			}
+			else {
+				try {
+					String json = JSONUtils.toJSON(dsStatus);
+					response = Response.ok(json).build();
+				} catch (JSONException e) {
+					e.printStackTrace();
+					logger.info("Parse exception " + e);
+					response = RestUtils.createErrorResponse(e);
+				}
+			}
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		return response;
+	}
+
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Register a discovery service", httpMethod = "POST", notes = "Register a new service in ODF", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response registerDiscoveryService(
+			@ApiParam(value = "ODF service definition", required = true) DiscoveryServiceProperties dsProperties) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "registerDiscoveryService");
+		Response response;
+		try {
+			DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+			dsAdmin.createDiscoveryService(dsProperties);
+			response = Response.ok().build();
+		} catch (ValidationException e) {
+			e.printStackTrace();
+			logger.info("Validation exception during setting of property " + e.getProperty());
+			response = RestUtils.createErrorResponse(e.getErrorCause());
+		}
+		return response;
+	}
+
+	@PUT
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Update properties of a discovery service", httpMethod = "POST", notes = "Update properties of a discovery service that is registered in ODF", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response updateDiscoveryService(
+			@ApiParam(value = "ODF service definition", required = true) DiscoveryServiceProperties dsProperties) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "updateDiscoveryService");
+		Response response;
+		try {
+			DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+			dsAdmin.replaceDiscoveryService(dsProperties);
+			response = Response.ok().build();
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		catch (ValidationException e) {
+			e.printStackTrace();
+			logger.info("Validation exception during setting of property " + e.getProperty());
+			response = RestUtils.createErrorResponse(e.getErrorCause());
+		}
+		return response;
+	}
+
+	@DELETE
+	@Path("/{serviceId}")
+	@ApiOperation(value = "Delete a discovery service", httpMethod = "DELETE", notes = "Remove a registered service from ODF", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response deleteDiscoveryService(
+			@ApiParam(value = "Id string of discovery service to be deleted", required = true)
+			@PathParam("serviceId") String serviceId) {
+		logger.entering(DiscoveryServicesResource.class.getName(), "deleteDiscoveryService");
+		Response response;
+		try {
+			DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+			dsAdmin.deleteDiscoveryService(serviceId);
+			response = Response.ok().build();
+		}
+		catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		catch (ValidationException e) {
+			e.printStackTrace();
+			logger.info("Validation exception during deletion. Property: " + e.getProperty());
+			response = RestUtils.createErrorResponse(e.getErrorCause());
+		}
+		return response;
+	}
+
+	@GET
+	@Path("/{serviceId}/image")
+	@Produces("image/*")
+	@ApiOperation(value = "Get a discovery service logo", httpMethod = "GET", notes = "Retrieve image representing a discovery service", response = InputStream.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getImage(
+			@ApiParam(value = "ID of discovery service", required = true)
+			@PathParam("serviceId") String serviceId) {
+
+		DiscoveryServiceManager dsAdmin = new ODFFactory().create().getDiscoveryServiceManager();
+		Response response = null;
+		InputStream is;
+		try {
+			is = dsAdmin.getDiscoveryServiceImage(serviceId);
+			if (is == null) {
+				// should never happen
+				response = Response.status(Status.NOT_FOUND).build();
+			}
+			else {
+				response = Response.ok(is, "image/png").build();
+			}
+		} catch (ServiceNotFoundException snfe) {
+			response = Response.status(Status.NOT_FOUND).entity(snfe.getMessage()).build();
+		}
+		return response;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/EngineResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/EngineResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/EngineResource.java
new file mode 100755
index 0000000..d6cd37d
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/EngineResource.java
@@ -0,0 +1,167 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.atlas.odf.api.engine.SystemHealth;
+import org.apache.atlas.odf.api.utils.ODFLogConfig;
+import org.apache.wink.json4j.JSONException;
+
+import org.apache.atlas.odf.admin.log.LoggingHandler;
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.ODFFactory;
+import org.apache.atlas.odf.api.engine.ODFEngineOptions;
+import org.apache.atlas.odf.api.engine.ODFStatus;
+import org.apache.atlas.odf.api.engine.ODFVersion;
+import org.apache.atlas.odf.api.engine.ServiceRuntimesInfo;
+import org.apache.atlas.odf.json.JSONUtils;
+
+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;
+
+@Path("/engine")
+@Api(value = "/engine", description = "Monitor and control the ODF engine", produces = MediaType.APPLICATION_JSON)
+public class EngineResource {
+	final static LoggingHandler REST_LOG_HANDLER = new LoggingHandler();
+
+	static {
+		//initialize log config and log handler to cache logs
+		ODFLogConfig.run();
+		Logger rootLogger = Logger.getLogger("org.apache.atlas.odf");
+		REST_LOG_HANDLER.setLevel(Level.ALL);
+		rootLogger.addHandler(REST_LOG_HANDLER);
+	}
+
+	private Logger logger = Logger.getLogger(EngineResource.class.getName());
+
+	@POST
+	@Path("shutdown")
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Shutdown ODF engine", httpMethod = "POST", notes = "Shutdown ODF engine, purge all scheduled analysis requests from the queues, and cancel all running analysis requests (for debugging purposes only)", response = Response.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response shutdown(@ApiParam(value = "Engine options", defaultValue = "false", required = true) ODFEngineOptions engineOptions) {
+		logger.entering(EngineResource.class.getName(), "shutdown");
+		logger.log(Level.INFO, "Restart option is ", engineOptions.isRestart());
+		new ODFFactory().create().getEngineManager().shutdown(engineOptions);
+		return Response.ok().build();
+	}
+
+	@GET
+	@Path("health")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get health status", httpMethod = "GET", notes = "Check the health status of ODF", response = SystemHealth.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response healthCheck() {
+		logger.entering(EngineResource.class.getName(), "healthCheck");
+		SystemHealth health = new ODFFactory().create().getEngineManager().checkHealthStatus();
+		Status status = Status.OK;
+		try {
+			return Response.status(status).entity(JSONUtils.toJSON(health)).type(MediaType.APPLICATION_JSON).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("runtimes")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get info about the available runtimes", httpMethod = "GET", notes = "Get information about all runtimes running discovery services", response = SystemHealth.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 400, message = "Bad Request"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getRuntimesInfo() {
+		logger.entering(EngineResource.class.getName(), "getRuntimesInfo");
+		ServiceRuntimesInfo sri = new ODFFactory().create().getEngineManager().getRuntimesInfo();
+		Status status = Status.OK;
+		try {
+			return Response.status(status).entity(JSONUtils.toJSON(sri)).type(MediaType.APPLICATION_JSON).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		} finally {
+			logger.exiting(EngineResource.class.getName(), "getRuntimesInfo");
+		}
+	}
+
+	@GET
+	@Path("status")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get current status", httpMethod = "GET", notes = "Retrieve status of the messaging subsystem and the internal thread manager", response = ODFStatus.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getStatus() throws IOException {
+		logger.entering(EngineResource.class.getName(), "getStatus");
+		try {
+			ODFStatus odfStatus = new ODFFactory().create().getEngineManager().getStatus();
+			return Response.status(Status.OK).entity(JSONUtils.toJSON(odfStatus)).type(MediaType.APPLICATION_JSON).build();
+		} catch (Exception exc) {
+			logger.log(Level.INFO, "An exception occurred while getting the request status", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+	}
+
+	@GET
+	@Path("log")
+	@Produces(MediaType.TEXT_PLAIN)
+	@ApiOperation(value = "Get current application log", httpMethod = "GET", notes = "Retrieve logs of the ODF instance", response = ODFStatus.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getLog(@QueryParam("numberOfLogs") Integer numberOfLogs, @QueryParam("logLevel") String logLevel) throws IOException {
+		logger.entering(EngineResource.class.getName(), "getLog");
+		try {
+			Level level = Level.ALL;
+			if (logLevel != null) {
+				level = Level.parse(logLevel);
+			}
+			return Response.status(Status.OK).entity(REST_LOG_HANDLER.getFormattedCachedLog(numberOfLogs, level)).type(MediaType.TEXT_PLAIN).build();
+		} catch (Exception exc) {
+			logger.log(Level.INFO, "An exception occurred while getting the ODF log", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+	}
+
+	@GET
+	@Path("version")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get the ODF build version", httpMethod = "GET", notes = "The version is of the form versionnumber-buildid, e.g., 0.1.0-154", response = ODFVersion.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getVersion() {
+		try {
+			ODFVersion version = new ODFFactory().create().getEngineManager().getVersion();
+			Status status = Status.OK;
+			return Response.status(status).entity(JSONUtils.toJSON(version)).type(MediaType.APPLICATION_JSON).build();
+		} catch (Exception exc) {
+			logger.log(Level.INFO, "An exception occurred while getting the version", exc);
+			return RestUtils.createErrorResponse(exc);
+		}
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/ImportResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/ImportResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/ImportResource.java
new file mode 100755
index 0000000..ef489a8
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/ImportResource.java
@@ -0,0 +1,89 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.util.logging.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.apache.atlas.odf.api.metadata.importer.JDBCMetadataImportResult;
+import org.apache.atlas.odf.api.metadata.importer.JDBCMetadataImporter;
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.ODFFactory;
+import org.apache.atlas.odf.api.metadata.importer.MetadataImportException;
+import org.apache.atlas.odf.api.metadata.models.JDBCConnection;
+import org.apache.atlas.odf.json.JSONUtils;
+
+@Path("/import")
+public class ImportResource {
+	private Logger logger = Logger.getLogger(ImportResource.class.getName());
+
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response doImport(String parameterString) {
+		logger.entering(ImportResource.class.getName(), "import");
+		try {
+			JSONObject parameter = new JSONObject(parameterString);
+
+			Object jdbcObj = parameter.get("jdbcString");
+			Object userObj = parameter.get("user");
+			Object passwordObj = parameter.get("password");
+			Object dbObj = parameter.get("database");
+			Object schemaObj = parameter.get("schema");
+			Object tableObj = parameter.get("table");
+
+			if (jdbcObj == null || userObj == null || passwordObj == null) {
+				return RestUtils.createErrorResponse("jdbcString, user, password, database, schema and table are required!");
+			}
+
+			String user = (String) userObj;
+			String password = (String) passwordObj;
+			String jdbcString = (String) jdbcObj;
+			String db = (String) dbObj;
+			String schema = (String) schemaObj;
+			String table = (String) tableObj;
+
+			JDBCMetadataImporter importer = new ODFFactory().create().getJDBCMetadataImporter();
+			JDBCConnection conn = new JDBCConnection();
+			conn.setJdbcConnectionString(jdbcString);
+			conn.setUser(user);
+			conn.setPassword(password);
+
+			JDBCMetadataImportResult result = null;
+			try {
+				result = importer.importTables(conn, db, schema, table);
+			} catch (MetadataImportException ex) {
+				return RestUtils.createErrorResponse(ex.getMessage());
+			}
+
+			if (result == null) {
+				return Response.serverError().build();
+			}
+
+			return Response.ok(JSONUtils.toJSON(result)).build();
+		} catch (JSONException e) {
+			return RestUtils.createErrorResponse(e.getMessage());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/MetadataResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/MetadataResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/MetadataResource.java
new file mode 100755
index 0000000..9daf09a
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/MetadataResource.java
@@ -0,0 +1,246 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.metadata.InternalMetaDataUtils;
+import org.apache.atlas.odf.api.metadata.MetaDataObjectReference;
+import org.apache.atlas.odf.api.metadata.MetadataStore;
+import org.apache.atlas.odf.api.metadata.MetadataStoreException;
+import org.apache.atlas.odf.api.metadata.models.MetaDataObject;
+import org.apache.atlas.odf.api.ODFFactory;
+import org.apache.atlas.odf.json.JSONUtils;
+
+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;
+
+@Path("/metadata")
+@Api(value = "/metadata", description = "Populate and query metadata repository", produces = MediaType.APPLICATION_JSON)
+public class MetadataResource {
+	private Logger logger = Logger.getLogger(MetadataResource.class.getName());
+
+	@GET
+	@Path("/connectiontest")
+	public Response testConnection() {
+		try {
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			MetadataStore.ConnectionStatus status = mds.testConnection();
+			switch (status) {
+			case OK:
+				return Response.ok().build();
+			case AUTHORIZATION_FAILED:
+				return Response.status(Status.UNAUTHORIZED).build();
+			case UNREACHABLE:
+				return Response.status(Status.NOT_FOUND).build();
+			default:
+				return Response.status(Status.INTERNAL_SERVER_ERROR).build();
+			}
+		} catch (Exception e) {
+			logger.log(Level.WARNING, "An exception occurred while getting metatdata store properties", e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get metadata store properties", httpMethod = "GET", notes = "Retrieve type and URL of underlying metadata store", response = Response.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getMetadataStoreProperties() {
+		try {
+			JSONObject result = new JSONObject();
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			Hashtable<Object, Object> propertyHashtable = (Hashtable<Object, Object>) mds.getProperties();
+			for (Object propKey : propertyHashtable.keySet()) {
+				result.put((String) propKey, (String) propertyHashtable.get(propKey));
+			}
+			String s = result.write();
+			return Response.ok(s).build();
+		} catch (Exception e) {
+			logger.log(Level.WARNING, "An exception occurred while getting metatdata store properties", e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("/referencetypes")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Get list of available reference types", httpMethod = "GET", notes = "Retrieve list of supported metadata object reference types", responseContainer="List", response = MetaDataObject.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response getReferenceTypes() {
+		JSONObject result = new JSONObject();
+		List<String> referenceTypes = null;
+		try {
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			referenceTypes = mds.getReferenceTypes();
+			result = JSONUtils.toJSONObject(referenceTypes);
+			return Response.ok(result.write()).build();
+		} catch (JSONException e) {
+			logger.warning("Parse exception " + e.getMessage() + " Parsed object: " + referenceTypes);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("/asset/{assetReference}")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Retrieve asset by reference", httpMethod = "GET", notes = "Retrieve object from metadata repository", response = MetaDataObject.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response retrieveAsset(@ApiParam(value = "Metadata object reference id", required = true) @PathParam("assetReference") String assetReference) {
+		JSONObject result;
+		try {
+			MetaDataObjectReference ref = JSONUtils.fromJSON(assetReference, MetaDataObjectReference.class);
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			MetaDataObject mdo = mds.retrieve(ref);
+			if (mdo != null) {
+				result = JSONUtils.toJSONObject(mdo);
+			} else {
+				// Return empty JSON document to indicate that the result should be null.
+				result = new JSONObject();
+			}
+			return Response.ok(result.write()).build();
+		} catch (JSONException e) {
+			logger.warning("Parse exception " + e.getMessage() + " Parsed object: " + assetReference);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("/asset/{assetReference}/{referenceType}")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Retrieve objects referenced by an asset", httpMethod = "GET", notes = "Retrieve referenced metadata objects by reference type", responseContainer="List", response = MetaDataObject.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response retrieveAssetReferences(
+			@ApiParam(value = "Metadata object reference", required = true) @PathParam("assetReference") String assetReference,
+			@ApiParam(value = "Reference type name (including 'PARENT' and 'CHILDREN')", required = true) @PathParam("referenceType") String referenceType) {
+		try {
+			MetaDataObjectReference ref = JSONUtils.fromJSON(assetReference, MetaDataObjectReference.class);
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			List<MetaDataObject> referencedObjects = new ArrayList<MetaDataObject>();
+			if (InternalMetaDataUtils.ODF_PARENT_REFERENCE.equals(referenceType.toUpperCase())) {
+				MetaDataObject parent = mds.getParent(mds.retrieve(ref));
+				if (parent != null) {
+					referencedObjects.add(parent);
+				}
+			} else if (InternalMetaDataUtils.ODF_CHILDREN_REFERENCE.toString().equals(referenceType.toUpperCase())) {
+				referencedObjects = mds.getChildren(mds.retrieve(ref));
+			} else {
+				referencedObjects = mds.getReferences(referenceType.toUpperCase(), mds.retrieve(ref));
+			}
+			List<JSONObject> jsons = new ArrayList<JSONObject>();
+			for (MetaDataObject obj : referencedObjects) {
+				jsons.add(JSONUtils.toJSONObject(obj));
+			}
+			String result = JSONUtils.toJSON(jsons);
+			logger.log(Level.FINE, "Serialized JSON: {0}", result);
+			return Response.ok(result).build();
+		} catch (JSONException e) {
+			logger.warning("Parse exception " + e.getMessage() + " Parsed object: " + assetReference);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("/sampledata")
+	@ApiOperation(value = "Create sample data", httpMethod = "GET", notes = "Populate metadata repository with ODF sample metadata", response = Response.class)
+	@ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Internal server error") })
+	public Response createSampleData() {
+		try {
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			mds.createSampleData();
+			return Response.ok().build();
+		} catch (Exception exc) {
+			exc.printStackTrace();
+			throw new RuntimeException(exc);
+		}
+	}
+
+	@POST
+	@Path("/resetalldata")
+	public Response resetAllData() {
+		try {
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			mds.resetAllData();
+			return Response.ok().build();
+		} catch (Exception e) {
+			logger.log(Level.WARNING, "An exception occurred while resetting metatdata store", e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@GET
+	@Path("/search")
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Query metadata repository", httpMethod = "GET", notes = "Search for objects in metadata repository", responseContainer="List", response = MetaDataObjectReference.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error") })
+	public Response search(@ApiParam(value = "Query to be sent to metadata repository (refer to Atlas query notation)", required = true) @QueryParam("query") String query,
+			@ApiParam(value = "Type of results to be returned, 'objects' vs. 'references'", required = false) @QueryParam("resulttype") String resultType) {
+		List<MetaDataObjectReference> queryResults;
+		try {
+			MetadataStore mds = new ODFFactory().create().getMetadataStore();
+			try {
+				queryResults = mds.search(query);
+			} catch(MetadataStoreException e) {
+				logger.log(Level.WARNING, MessageFormat.format("Error processing query ''{0}''.", query), e);
+				return Response.status(Status.BAD_REQUEST).build();
+			}
+			List<JSONObject> jsons = new ArrayList<JSONObject>();
+			if ((resultType != null) && resultType.equals("references")) {
+				for (MetaDataObjectReference ref : queryResults) {
+					jsons.add(JSONUtils.toJSONObject(ref));
+				}
+			} else {
+				// TODO very slow, retrieve results in bulk ?!?
+				//FIXME serialization of each object on its own is necessary because of a jackson issue (https://github.com/FasterXML/jackson-databind/issues/336)
+				//this should be replaced by a custom objectmapper initialization, issue #59 in gitlab
+				for (MetaDataObjectReference ref : queryResults) {
+					MetaDataObject retrievedMdo = mds.retrieve(ref);
+					jsons.add(JSONUtils.toJSONObject(retrievedMdo));
+				}
+			}
+			String result = JSONUtils.toJSON(jsons);
+			logger.log(Level.FINE, "Serialized JSON: {0}", result);
+			return Response.ok(result).build();
+		} catch (Exception exc) {
+			exc.printStackTrace();
+			throw new RuntimeException(exc);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/SettingsResource.java
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/SettingsResource.java b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/SettingsResource.java
new file mode 100755
index 0000000..e203774
--- /dev/null
+++ b/odf/odf-web/src/main/java/org/apache/atlas/odf/admin/rest/resources/SettingsResource.java
@@ -0,0 +1,128 @@
+/**
+ *
+ * Licensed 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.atlas.odf.admin.rest.resources;
+
+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;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.atlas.odf.admin.rest.RestUtils;
+import org.apache.atlas.odf.api.settings.ODFSettings;
+import org.apache.atlas.odf.api.settings.SettingsManager;
+import org.apache.atlas.odf.api.settings.validation.ValidationException;
+import org.apache.atlas.odf.json.JSONUtils;
+import org.apache.wink.json4j.JSONException;
+
+import org.apache.atlas.odf.api.ODFFactory;
+
+@Path("/settings")
+@Api(value = "/settings", description = "View or update the settings of the Open Discovery Framework", produces = MediaType.APPLICATION_JSON)
+public class SettingsResource {
+
+	private Logger logger = Logger.getLogger(SettingsResource.class.getName());
+
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Retrieve settings", httpMethod = "GET", notes = "Retrieve current ODF settings", response = ODFSettings.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response getSettings() {
+		logger.entering(SettingsResource.class.getName(), "getConfig");
+		try {
+			return Response.ok(JSONUtils.toJSON(new ODFFactory().create().getSettingsManager().getODFSettingsHidePasswords()), MediaType.APPLICATION_JSON).build();
+		} catch (JSONException e) {
+			e.printStackTrace();
+			logger.info("Parse exception " + e);
+			return RestUtils.createErrorResponse(e);
+		}
+	}
+
+	@POST
+	@Path("/reset")
+	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Reset settings", httpMethod = "POST", notes = "Reset ODF settings to the default", response = Response.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response resetSettings() {
+		logger.entering(SettingsResource.class.getName(), "getConfig");
+		new ODFFactory().create().getSettingsManager().resetODFSettings();
+		return Response.ok().build();
+	}
+
+	@PUT
+	@Produces(MediaType.APPLICATION_JSON)
+	@Consumes(MediaType.APPLICATION_JSON)
+	@ApiOperation(value = "Update settings", httpMethod = "PUT", notes = "Update ODF settings", response = ODFSettings.class)
+	@ApiResponses(value = {
+			@ApiResponse(code = 200, message = "OK"),
+			@ApiResponse(code = 400, message = "Bad Request"),
+			@ApiResponse(code = 500, message = "Internal server error")
+	})
+	public Response changeSettings(@ApiParam(value = "ODF configuration options", required = true) ODFSettings odfConfig) {
+		logger.entering(SettingsResource.class.getName(), "changeConfig");
+		if (odfConfig == null) {
+			return Response.status(Status.BAD_REQUEST).entity("The body must be a valid settings JSON.").build();
+		}
+
+		try {
+			SettingsManager config = new ODFFactory().create().getSettingsManager();
+			config.updateODFSettings(odfConfig);
+			return Response.ok(JSONUtils.toJSON(config.getODFSettingsHidePasswords())).build();
+		} catch (ValidationException e) {
+			e.printStackTrace();
+			logger.info("Validation exception during setting of property " + e.getProperty());
+			return RestUtils.createErrorResponse(e);
+		} catch (JSONException e1) {
+			e1.printStackTrace();
+			return RestUtils.createErrorResponse(MessageFormat.format("The provided input is not valid JSON in form {0}", getEmptyODFConfig()));
+		}
+	}
+
+	private String getEmptyODFConfig() {
+		ODFSettings odf = new ODFSettings();
+		odf.setUserDefined(new HashMap<String, Object>());
+		String emptyJSON = "";
+		try {
+			emptyJSON = JSONUtils.toJSON(odf);
+		} catch (JSONException e2) {
+			e2.printStackTrace();
+		}
+		return emptyJSON;
+	}
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/activity_32.png
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/activity_32.png b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/activity_32.png
new file mode 100755
index 0000000..fabcc37
Binary files /dev/null and b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/activity_32.png differ

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/applications_32.png
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/applications_32.png b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/applications_32.png
new file mode 100755
index 0000000..1f3744b
Binary files /dev/null and b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/applications_32.png differ

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/bar-chart_32.png
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/bar-chart_32.png b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/bar-chart_32.png
new file mode 100755
index 0000000..59a7ff8
Binary files /dev/null and b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/bar-chart_32.png differ

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/world_32.png
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/world_32.png b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/world_32.png
new file mode 100755
index 0000000..4b9bcd3
Binary files /dev/null and b/odf/odf-web/src/main/resources/org/apache/atlas/odf/images/world_32.png differ

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/.gitignore
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/.gitignore b/odf/odf-web/src/main/webapp/.gitignore
new file mode 100755
index 0000000..4cc0506
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/.gitignore
@@ -0,0 +1,19 @@
+#
+#  Licensed 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.
+#
+/odf-web.js
+/odf-web.js.map
+/odf-client.js
+/odf-client.js.map
+resources
+resources/**

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/WEB-INF/web.xml b/odf/odf-web/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..9e16b0d
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~
+~ Licensed 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.
+-->
+<web-app id="WebApp_ID" version="3.0"
+	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+	<display-name>odf-admin</display-name>
+	<servlet>
+		<servlet-name>odf-admin-servlet</servlet-name>
+		<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+		<init-param>
+			<param-name>javax.ws.rs.Application</param-name>
+			<param-value>org.apache.atlas.odf.admin.rest.ODFAdminApp</param-value>
+		</init-param>
+		<load-on-startup>1</load-on-startup>
+		<enabled>true</enabled>
+		<async-supported>false</async-supported>
+	</servlet>
+
+	<servlet-mapping>
+		<servlet-name>odf-admin-servlet</servlet-name>
+		<url-pattern>/odf/api/v1/*</url-pattern>
+	</servlet-mapping>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>Secure resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+			<role-name>user</role-name>
+			<role-name>moderator</role-name>
+		</auth-constraint>
+	</security-constraint>
+	<login-config>
+		<auth-method>BASIC</auth-method>
+		<realm-name>ODF Realm</realm-name>
+	</login-config>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/client_index.html
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/client_index.html b/odf/odf-web/src/main/webapp/client_index.html
new file mode 100755
index 0000000..ea85c87
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/client_index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<!--
+  ~ 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.
+  -->
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Data lake application</title>
+</head>
+<body>
+   <div id="odf-toplevel-div" class="container-fluid">
+     Loading...
+   </div>
+   <script type="text/javascript" src="odf-config.js"></script>
+   <script type="text/javascript" src="odf-client.js"></script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/img/lg_proc.gif
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/img/lg_proc.gif b/odf/odf-web/src/main/webapp/img/lg_proc.gif
new file mode 100755
index 0000000..7dd40ef
Binary files /dev/null and b/odf/odf-web/src/main/webapp/img/lg_proc.gif differ

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/index.html
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/index.html b/odf/odf-web/src/main/webapp/index.html
new file mode 100755
index 0000000..f224997
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<!--
+  ~ 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.
+  -->
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Open Discovery Framework</title>
+</head>
+<body>
+   <div id="odf-toplevel-div" class="container-fluid">
+     Loading...
+   </div>
+   <script type="text/javascript" src="odf-config.js"></script>
+   <script type="text/javascript" src="odf-web.js"></script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/odf-config.js
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/odf-config.js b/odf/odf-web/src/main/webapp/odf-config.js
new file mode 100755
index 0000000..6bb4a47
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/odf-config.js
@@ -0,0 +1,15 @@
+/**
+ * 
+ * Licensed 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.
+ */
+const API_PATH = "odf/api/v1/";

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-web/src/main/webapp/scripts/odf-analysis-request.js
----------------------------------------------------------------------
diff --git a/odf/odf-web/src/main/webapp/scripts/odf-analysis-request.js b/odf/odf-web/src/main/webapp/scripts/odf-analysis-request.js
new file mode 100755
index 0000000..67bb709
--- /dev/null
+++ b/odf/odf-web/src/main/webapp/scripts/odf-analysis-request.js
@@ -0,0 +1,473 @@
+/**
+ *
+ * Licensed 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.
+ */
+var $ = require("jquery");
+var bootstrap = require("bootstrap");
+
+var React = require("react");
+var ReactDOM = require("react-dom");
+var LinkedStateMixin = require('react-addons-linked-state-mixin');
+var ReactBootstrap = require("react-bootstrap");
+var AJAXCleanupMixin = require("./odf-mixins.js");
+var configurationStore = require("./odf-configuration-store.js");
+var metadataStore = require("./odf-utils.js").MetadataStore;
+var ODFGlobals = require("./odf-globals.js");
+
+var Button = ReactBootstrap.Button;
+var Row = ReactBootstrap.Row;
+var Col = ReactBootstrap.Col;
+var Table = ReactBootstrap.Table;
+var Modal = ReactBootstrap.Modal;
+var Input = ReactBootstrap.Input;
+var Alert = ReactBootstrap.Alert;
+var Panel = ReactBootstrap.Panel;
+var Label = ReactBootstrap.Label;
+var Input = ReactBootstrap.Input;
+var Image = ReactBootstrap.Image;
+
+var OdfAnalysisRequest = {
+	NewAnalysisRequestButton : React.createClass({
+
+		getInitialState : function(){
+			return {showAnalysisRequestDialog : false};
+		},
+
+		open : function(){
+			this.setState({showAnalysisRequestDialog: true});
+		},
+
+		onClose : function(){
+			this.setState({showAnalysisRequestDialog: false});
+			if(this.props.onClose){
+				this.props.onClose();
+			}
+		},
+
+		render : function() {
+			return (
+					<span>
+						<Button bsStyle={this.props.bsStyle} onClick={this.open}>Start analysis (service sequence)</Button>
+						<OdfAnalysisRequest.NewAnalysisRequestDialog show={this.state.showAnalysisRequestDialog} dataSetId={this.props.dataSetId} alertCallback={this.props.alertCallback} onClose={this.onClose}/>
+					</span>
+			);
+		}
+
+	}),
+
+	NewAnalysisRequestDialog : React.createClass({
+
+	  mixins : [AJAXCleanupMixin],
+
+	  getInitialState : function() {
+	    return ({config: null, discoveryServices: [], errorMessage: null, discoveryServiceSequence: []});
+	  },
+
+	  close : function() {
+		  this.clearDialogState();
+		  if(this.props.onClose){
+			  this.props.onClose();
+		  }
+	  },
+
+	  submitRequest : function() {
+		this.setState({requestInProgress : true});
+	    var dataSet = this.refs.inputDataSet.getValue();
+	    var discoveryServiceIDs = $.map(this.state.discoveryServiceSequence,
+	       function(dsreg) {
+	          return dsreg.id;
+	       }
+	    );
+
+	    var repositoryId = this.state.repositoryId;
+	    var metadataObjectRef = {
+	      repositoryId: repositoryId,
+	      id: dataSet
+	    };
+	    var analysisRequest = {
+	      dataSets: [metadataObjectRef],
+	      discoveryServiceSequence: discoveryServiceIDs
+	    };
+
+	    // now post request
+	    // clear alert
+	    if(this.props.alertCallback){
+	    	this.props.alertCallback({type: "", message: ""});
+	    }
+	    var req = $.ajax({
+	      url: ODFGlobals.analysisUrl,
+	      contentType: "application/json",
+	      dataType: 'json',
+	      type: 'POST',
+	      data: JSON.stringify(analysisRequest),
+	      success: function(analysisResponse) {
+	        if(!this.isMounted()){
+	        	return;
+	        }
+	    	if (analysisResponse.invalidRequest) {
+	          this.setState({errorMessage: analysisResponse.details, requestInProgress: false});
+	        } else {
+	          var msg = "Analysis request was started. ID: " + analysisResponse.id;
+	          if(this.props.alertCallback){
+	      	    this.props.alertCallback({type: "success", message: msg});
+	          }
+	      	  this.close();
+	        }
+	      }.bind(this),
+	      error: function(xhr, status, err) {
+	        var msg = "Error while reading ODF services: " + err.toString();
+	        this.setState({errorMessage: msg, requestInProgress: false});
+	      }.bind(this)
+	    });
+
+	    this.storeAbort(req.abort);
+	  },
+
+	  componentDidMount : function() {
+		  this.loadDiscoveryServices();
+	  },
+
+	  loadDiscoveryServices : function() {
+	    var req = configurationStore.readConfig(
+	      function(config) {
+	    	if(!this.isMounted()){
+	        	return;
+	        }
+	        this.setState({config: config});
+	        // clear alert
+	        if(this.props.alertCallback){
+	        	this.props.alertCallback({type: "", message: ""});
+	        }
+	        var req2 = $.ajax({
+	          url: ODFGlobals.servicesUrl,
+	          dataType: 'json',
+	          type: 'GET',
+	          success: function(data) {
+	        	if(!this.isMounted()){
+	  	        	return;
+	  	        }
+	            this.setState({discoveryServices: data});
+	          }.bind(this),
+	          error: function(xhr, status, err) {
+	            var msg = "Error while reading ODF services: " + err.toString();
+	            if(this.props.alertCallback){
+	        	    this.props.alertCallback({type: "danger", message: msg});
+	            }
+	         }.bind(this)
+	        });
+	        this.storeAbort(req2.abort);
+	      }.bind(this),
+	      this.props.alertCallback
+	    );
+
+	    this.storeAbort(req.abort);
+	  },
+
+	  getDiscoveryServiceFromId : function(id) {
+	      var servicesWithSameId = this.state.discoveryServices.filter(
+	         function(dsreg) {
+	             return dsreg.id == id;
+	         }
+	      );
+	      if (servicesWithSameId.length > 0) {
+	        return servicesWithSameId[0];
+	      }
+	      return null;
+	  },
+
+	  processDiscoveryServiceSelection : function() {
+	      var selection = this.refs.inputAvailableDiscoveryServices.getValue();
+	      var dsreg = this.getDiscoveryServiceFromId(selection);
+	      if (dsreg) {
+	        var newSequence = this.state.discoveryServiceSequence.slice();
+	        newSequence.push(dsreg);
+	        this.setState({discoveryServiceSequence: newSequence});
+	      }
+	  },
+
+	  clearDialogState : function() {
+	      this.setState({discoveryServiceSequence: [], requestInProgress : false, });
+	  },
+
+	  render : function() {
+	     var alert = null;
+	     if (this.state.errorMessage) {
+	        alert = <Alert bsStyle="danger">{this.state.errorMessage}</Alert>;
+	     }
+	     var servicesOptions = $.map(
+	            this.state.discoveryServices,
+	            function(dsreg) {
+	              return (<option key={dsreg.id} value={dsreg.id}>{dsreg.name}</option>);
+	            }.bind(this)
+	        );
+
+	     var discoveryServiceSequenceComponents = $.map(this.state.discoveryServiceSequence,
+	         function(dsreg) {
+	            return <li key={dsreg.id}>{dsreg.name} ({dsreg.id})</li>
+	         }
+	     );
+
+	     var waitingContainer = <div style={{position:"absolute", width:"100%", height:"100%", left:"50%", top: "30%"}}><Image src="img/lg_proc.gif" rounded /></div>;
+	     if(!this.state.requestInProgress){
+	    	 waitingContainer = null;
+	     }
+
+	     return (
+	       <Modal show={this.props.show} onHide={this.close}>
+	         <Modal.Header closeButton>
+	            <Modal.Title>Start analysis (specify service sequence)</Modal.Title>
+	         </Modal.Header>
+	         <Modal.Body>
+	         	{waitingContainer}
+	            {alert}
+	            <Input type="text" ref="inputDataSet" label="Data Set" value={this.props.dataSetId} readOnly={this.props.dataSetId}></Input>
+	            <hr/>
+	            Select a service from the "Available Services"
+	            dropdown to append it to the sequence. Repeat selection to run multiple services for the data set.
+	            <Input type="select" onChange={this.processDiscoveryServiceSelection} ref="inputAvailableDiscoveryServices" label="Available Services">
+	              <option key="emptySelection">&lt;Select a service...&gt;</option>
+	              {servicesOptions}
+	            </Input>
+	            <strong>Service Sequence</strong>
+	            <ol>{discoveryServiceSequenceComponents}</ol>
+	            <hr />
+	            <Button bsStyle="warning" onClick={this.clearDialogState}>Clear Sequence</Button>
+	        </Modal.Body>
+	        <Modal.Footer>
+	        <Button onClick={this.submitRequest} bsStyle="primary">Submit</Button>
+	        <Button onClick={this.close} >Cancel</Button>
+	        </Modal.Footer>
+	       </Modal>
+	     );
+	  }
+
+	}),
+
+	NewCreateAnnotationsButton : React.createClass({
+
+		getInitialState : function(){
+			return {showCreateAnnotationsDialog : false};
+		},
+
+		open : function(){
+			this.setState({showCreateAnnotationsDialog: true});
+		},
+
+		onClose : function(){
+			this.setState({showCreateAnnotationsDialog: false});
+			if(this.props.onClose){
+				this.props.onClose();
+			}
+		},
+
+		render : function() {
+			return (
+					<span>
+						<Button bsStyle={this.props.bsStyle} onClick={this.open}>Start analysis (annotation types)</Button>
+						<OdfAnalysisRequest.NewCreateAnnotationsDialog show={this.state.showCreateAnnotationsDialog} dataSetId={this.props.dataSetId} alertCallback={this.props.alertCallback} onClose={this.onClose}/>
+					</span>
+			);
+		}
+
+	}),
+
+	NewCreateAnnotationsDialog : React.createClass({
+
+		  mixins : [AJAXCleanupMixin],
+
+		  getInitialState : function() {
+		    return ({config: null, annotationTypes: [], errorMessage: null, analysisTypeSelection: []});
+		  },
+
+		  close : function() {
+			  this.clearDialogState();
+			  if(this.props.onClose){
+				  this.props.onClose();
+			  }
+		  },
+
+		  submitRequest : function() {
+			this.setState({requestInProgress : true});
+		    var dataSet = this.refs.inputDataSet.getValue();
+		    var annotationTypeIDs = $.map(this.state.analysisTypeSelection,
+		       function(annotationTypeId) {
+		          return annotationTypeId;
+		       }
+		    );
+
+		    var repositoryId = this.state.repositoryId;
+		    var metadataObjectRef = {
+		      repositoryId: repositoryId,
+		      id: dataSet
+		    };
+		    var analysisRequest = {
+		      dataSets: [metadataObjectRef],
+		      annotationTypes: annotationTypeIDs
+		    };
+
+		    // now post request
+		    // clear alert
+		    if(this.props.alertCallback){
+		    	this.props.alertCallback({type: "", message: ""});
+		    }
+		    var req = $.ajax({
+		      url: ODFGlobals.analysisUrl,
+		      contentType: "application/json",
+		      dataType: 'json',
+		      type: 'POST',
+		      data: JSON.stringify(analysisRequest),
+		      success: function(analysisResponse) {
+		        if(!this.isMounted()){
+		        	return;
+		        }
+		    	if (analysisResponse.invalidRequest) {
+		          this.setState({errorMessage: analysisResponse.details, requestInProgress: false});
+		        } else {
+		          var msg = "Analysis request was started. ID: " + analysisResponse.id;
+		          if(this.props.alertCallback){
+		      	    this.props.alertCallback({type: "success", message: msg});
+		          }
+		      	  this.close();
+		        }
+		      }.bind(this),
+		      error: function(xhr, status, err) {
+		        var msg = "Error starting discovery request: " + err.toString();
+		        this.setState({errorMessage: msg, requestInProgress: false});
+		      }.bind(this)
+		    });
+
+		    this.storeAbort(req.abort);
+		  },
+
+		  componentDidMount : function() {
+			  this.loadannotationTypes();
+		  },
+
+		  loadannotationTypes : function() {
+		    var req = configurationStore.readConfig(
+		      function(config) {
+		    	if(!this.isMounted()){
+		        	return;
+		        }
+		        this.setState({config: config});
+		        // clear alert
+		        if(this.props.alertCallback){
+		        	this.props.alertCallback({type: "", message: ""});
+		        }
+		        var req2 = $.ajax({
+		          url: ODFGlobals.servicesUrl,
+		          dataType: 'json',
+		          type: 'GET',
+		          success: function(data) {
+		        	if(!this.isMounted()){
+		  	        	return;
+		  	        }
+		            var ids = [];
+		            $.each(data, function(key, dsreg){
+			            $.each(dsreg.resultingAnnotationTypes, function(key, annotationTypeId){
+			            	if($.inArray(annotationTypeId,ids) == -1){
+				            	ids.push(annotationTypeId);
+			            	};
+			            });
+		            });
+		            this.setState({annotationTypes: ids});
+		          }.bind(this),
+		          error: function(xhr, status, err) {
+		            var msg = "Error while reading ODF services: " + err.toString();
+		            if(this.props.alertCallback){
+		        	    this.props.alertCallback({type: "danger", message: msg});
+		            }
+		         }.bind(this)
+		        });
+		        this.storeAbort(req2.abort);
+		      }.bind(this),
+		      this.props.alertCallback
+		    );
+			 metadataStore.getProperties(
+					 function(data) {
+					     this.setState({repositoryId: data.STORE_PROPERTY_ID});
+					 }.bind(this)
+			 );
+		    this.storeAbort(req.abort);
+		  },
+
+		  processAnalysisTypeSelection : function() {
+		      var selection = this.refs.inputAvailableAnnotationTypes.getValue();
+		      if (selection) {
+		        var newSelection = this.state.analysisTypeSelection.slice();
+		        newSelection.push(selection);
+		        this.setState({analysisTypeSelection: newSelection});
+		      }
+		  },
+
+		  clearDialogState : function() {
+		      this.setState({analysisTypeSelection: [], requestInProgress : false, });
+		  },
+
+		  render : function() {
+		     var alert = null;
+		     if (this.state.errorMessage) {
+		        alert = <Alert bsStyle="danger">{this.state.errorMessage}</Alert>;
+		     }
+		     var analysisTypeOptions = $.map(
+			            this.state.annotationTypes,
+			            function(annotationTypeId) {
+			              return (<option key={annotationTypeId} value={annotationTypeId}>{annotationTypeId}</option>);
+			            }.bind(this)
+			        );
+
+		     var analysisTypeSelectionComponents = $.map(this.state.analysisTypeSelection,
+		         function(annotationTypeId) {
+		            return <li key={annotationTypeId}>{annotationTypeId}</li>
+		         }
+		     );
+
+		     var waitingContainer = <div style={{position:"absolute", width:"100%", height:"100%", left:"50%", top: "30%"}}><Image src="img/lg_proc.gif" rounded /></div>;
+		     if(!this.state.requestInProgress){
+		    	 waitingContainer = null;
+		     }
+
+		     return (
+		       <Modal show={this.props.show} onHide={this.close}>
+		         <Modal.Header closeButton>
+		            <Modal.Title>Start analysis (specify annotation types)</Modal.Title>
+		         </Modal.Header>
+		         <Modal.Body>
+		         	{waitingContainer}
+		            {alert}
+		            <Input type="text" ref="inputDataSet" label="Data Set" value={this.props.dataSetId} readOnly={this.props.dataSetId}></Input>
+		            <hr/>
+		            Select an annotation type from the "Available Annotation Types"
+		            dropdown to append it to the list. Repeat selection to create multiple annotation types for the data set.
+		            <Input type="select" onChange={this.processAnalysisTypeSelection} ref="inputAvailableAnnotationTypes" label="Available Annotation Types">
+		              <option key="emptySelection">&lt;Select an annotation type...&gt;</option>
+		              {analysisTypeOptions}
+		            </Input>
+		            <strong>Selected Annotation Types</strong>
+		            <ol>{analysisTypeSelectionComponents}</ol>
+		            <hr />
+		            <Button bsStyle="warning" onClick={this.clearDialogState}>Clear Selection</Button>
+		        </Modal.Body>
+		        <Modal.Footer>
+		        <Button onClick={this.submitRequest} bsStyle="primary">Submit</Button>
+		        <Button onClick={this.close} >Cancel</Button>
+		        </Modal.Footer>
+		       </Modal>
+		     );
+		  }
+
+		})
+}
+
+
+module.exports = OdfAnalysisRequest;


Mime
View raw message