/*
* Copyright (c) 2011-2014 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.geo.service.impl.resource;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;
import java.net.URI;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import com.emc.storageos.api.service.impl.resource.ArgValidator;
import com.emc.storageos.db.client.constraint.ConstraintDescriptor;
import com.emc.storageos.db.client.util.KeyspaceUtil;
import com.emc.storageos.db.common.DependencyChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.client.constraint.Constraint;
import com.emc.storageos.db.client.constraint.QueryResultList;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.security.geo.GeoServiceClient;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.model.BulkIdParam;
import com.emc.storageos.geomodel.ResourcesResponse;
/**
* query "GeoVisibilty" objects
*/
@Path(GeoServiceClient.INTERVDC_URI)
public class QueryService {
private static final Logger log = LoggerFactory.getLogger(QueryService.class);
private DbClient dbClient;
private DependencyChecker dependencyChecker;
public DbClient getDbClient() {
return dbClient;
}
public void setDbClient(DbClient dbClient) {
this.dbClient = dbClient;
}
public void setDependencyChecker(DependencyChecker dependencyChecker) {
this.dependencyChecker = dependencyChecker;
}
private StreamingOutput getStreamingOutput(final Object obj) {
return new StreamingOutput() {
@Override
public void write(OutputStream outputStream) {
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(outputStream);
out.writeObject(obj);
} catch (Exception e) {
log.error("Failed to write ResourceIDsResponse", e);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
log.error("stream close error", e);
}
}
}
};
}
@GET
@Path(GeoServiceClient.GEO_VISIBLE + "{name}")
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
public Response queryByType(@PathParam("name") String className, @QueryParam("active_only") boolean activeOnly,
@QueryParam("start_id") URI startId, @QueryParam("max_count") Integer maxCount) throws DatabaseException {
ArgValidator.checkFieldNotNull(className, "name");
try {
Class clazz = Class.forName(className);
List<URI> ids;
if (maxCount == null) {
ids = dbClient.queryByType(clazz, activeOnly);
} else {
ids = dbClient.queryByType(clazz, activeOnly, startId, maxCount);
}
return genResourcesResponse(ids.iterator());
} catch (ClassNotFoundException e) {
log.error("e=", e);
throw APIException.badRequests.invalidParameter("name", className);
}
}
@GET
@Path(GeoServiceClient.GEO_VISIBLE + "{name}/object/{id}")
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
public Response queryObject(@PathParam("name") String className, @PathParam("id") URI id) throws DatabaseException {
ArgValidator.checkFieldNotNull(className, "name");
ArgValidator.checkUri(id);
try {
Class clazz = Class.forName(className);
DataObject obj = dbClient.queryObject(clazz, id);
return Response.ok(getStreamingOutput(obj), MediaType.APPLICATION_OCTET_STREAM).build();
} catch (ClassNotFoundException e) {
log.error("e=", e);
throw APIException.badRequests.invalidParameter("name", className);
}
}
@GET
@Path(GeoServiceClient.DEPENDENCIES + "{name}/{id}/")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public String checkDependencies(@PathParam("name") String className, @PathParam("id") URI id,
@QueryParam("active_only") boolean activeOnly) throws DatabaseException {
ArgValidator.checkFieldNotNull(className, "name");
ArgValidator.checkUri(id);
try {
Class clazz = Class.forName(className);
if (!KeyspaceUtil.isGlobal(clazz)) {
Throwable cause = new Throwable(className + " is not in geodb");
throw APIException.badRequests.invalidParameterWithCause("name", className, cause);
}
String dependency = dependencyChecker.checkDependencies(id, clazz, activeOnly);
if (dependency != null) {
return dependency;
}
return "";
} catch (ClassNotFoundException e) {
log.error("e=", e);
throw APIException.badRequests.invalidParameter("name", className);
}
}
@POST
@Path("geo-visible/{name}/objects")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
public Response queryObjects(@PathParam("name") String className, BulkIdParam ids) throws DatabaseException {
ArgValidator.checkFieldNotNull(className, "name");
try {
Class clazz = Class.forName(className);
Iterator<DataObject> it = dbClient.queryIterativeObjects(clazz, ids.getIds());
return genResourcesResponse(it);
} catch (ClassNotFoundException e) {
log.error("e=", e);
throw APIException.badRequests.invalidParameter("name", className);
}
}
@POST
@Path("geo-visible/{name}/field/{fieldName}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
public Response queryObjectsField(@PathParam("name") String className, @PathParam("fieldName") String fieldName,
BulkIdParam ids) throws DatabaseException {
List<URI> resourceIds = ids.getIds();
try {
Class clazz = Class.forName(className);
Iterator<DataObject> it = dbClient.queryIterativeObjectField(clazz, fieldName, resourceIds);
return genResourcesResponse(it);
} catch (ClassNotFoundException e) {
log.error("e=", e);
throw APIException.badRequests.invalidParameter("name", className);
}
}
@POST
@Path("geo-visible/constraint/{className}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
public Response queryByConstraint(@PathParam("className") String className, ConstraintDescriptor constraintDescriptor,
@QueryParam("start_id") URI startId, @QueryParam("max_count") Integer maxCount) throws DatabaseException {
Constraint condition;
try {
condition = constraintDescriptor.toConstraint();
} catch (ClassNotFoundException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException | InstantiationException e) {
throw APIException.badRequests.invalidParameterWithCause(constraintDescriptor.getClass().getName(), constraintDescriptor.toString(), e);
}
try {
Class clazz = Class.forName(className);
QueryResultList<?> resultList = (QueryResultList<?>) clazz.newInstance();
if (maxCount == null) {
dbClient.queryByConstraint(condition, resultList);
} else {
dbClient.queryByConstraint(condition, resultList, startId, maxCount);
}
return genResourcesResponse(resultList);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
log.error("Can't find the class e=", e);
throw APIException.badRequests.invalidParameter("className", className);
}
}
private <T> Response genResourcesResponse(Iterator<T> objs) {
ResourcesResponse<T> resp = new ResourcesResponse();
int count = 0;
while (objs.hasNext()) {
count++;
resp.add(objs.next());
}
resp.setSize(count);
return Response.ok(getStreamingOutput(resp), MediaType.APPLICATION_OCTET_STREAM).build();
}
private Response genResourcesResponse(QueryResultList<?> queryResult) {
ResourcesResponse<Object> resp = new ResourcesResponse();
int count = 0;
Iterator<?> it = queryResult.iterator();
while (it.hasNext()) {
count++;
resp.add(it.next());
}
resp.setSize(count);
return Response.ok(getStreamingOutput(resp), MediaType.APPLICATION_OCTET_STREAM).build();
}
}