blob: c5487c0d30df4a50aca4cac599c05528379652f0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.oodt.cas.product.jaxrs.services;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import javax.activation.DataHandler;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
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.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang.StringUtils;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.Multipart;
import org.apache.oodt.cas.filemgr.ingest.StdIngester;
import org.apache.oodt.cas.filemgr.metadata.CoreMetKeys;
import org.apache.oodt.cas.filemgr.structs.*;
import org.apache.oodt.cas.filemgr.structs.exceptions.CatalogException;
import org.apache.oodt.cas.filemgr.system.FileManagerClient;
import org.apache.oodt.cas.metadata.MetExtractor;
import org.apache.oodt.cas.metadata.Metadata;
import org.apache.oodt.cas.metadata.SerializableMetadata;
import org.apache.oodt.cas.metadata.extractors.MetReaderExtractor;
import org.apache.oodt.cas.product.exceptions.CasProductException;
import org.apache.oodt.cas.product.jaxrs.enums.ErrorType;
import org.apache.oodt.cas.product.jaxrs.exceptions.BadRequestException;
import org.apache.oodt.cas.product.jaxrs.exceptions.InternalServerErrorException;
import org.apache.oodt.cas.product.jaxrs.exceptions.NotFoundException;
import org.apache.oodt.cas.product.jaxrs.resources.FMStatusResource;
import org.apache.oodt.cas.product.jaxrs.resources.ProductPageResource;
import org.apache.oodt.cas.product.jaxrs.resources.ProductResource;
import org.apache.oodt.cas.product.jaxrs.resources.ProductTypeListResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service class for Proposing Apache OODT-2.0 FileManager REST-APIs This handles HTTP requests and
* returns file manager entities JAX-RS resources converted to different formats.
*
* @author ngimhana (Nadeeshan Gimhana)
* @author pavinduLakshan (Pavindu Lakshan)
*/
public class FileManagerJaxrsServiceV2 {
private static Logger logger = LoggerFactory.getLogger(FileManagerJaxrsServiceV2.class);
private static final String DATA_TRANSFER_FACTORY =
"org.apache.oodt.cas.filemgr.datatransfer.LocalDataTransferFactory";
// The servlet context, which is used to retrieve context parameters.
@Context private ServletContext context;
private java.nio.file.Path tmpDir;
public FileManagerJaxrsServiceV2() throws IOException {
tmpDir = Files.createTempDirectory("oodt");
}
/**
* Gets an HTTP request that represents a {@link ProductTypeListResource} from the file manager.
*
* @return an HTTP response that represents a {@link ProductTypeListResource} from the file manager
*/
@GET
@Path("productTypes")
@Produces({
"application/xml",
"application/json",
"application/atom+xml",
"application/rdf+xml",
"application/rss+xml"
})
public ProductTypeListResource getProductTypes() throws WebApplicationException {
try {
FileManagerClient client = getContextClient();
List<ProductType> productTypes = client.getProductTypes();
return new ProductTypeListResource(productTypes);
} catch (Exception e) {
throw new NotFoundException(e.getMessage());
}
}
/**
* This method is for calculating the total number of products in the file manager and return it
*
* @return the total number of products in the file manager
*/
public int getTotalNumOfProducts() throws WebApplicationException {
try {
int totalFiles = 0;
FileManagerClient client = getContextClient();
List<ProductType> productTypes = client.getProductTypes();
for(ProductType productType: productTypes){
totalFiles += client.getNumProducts(productType);
}
return totalFiles;
} catch (Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
/**
* Gets an HTTP request that represents a {@link ProductPage} from the file manager.
*
* @param productTypeName the Name of a productType
* @param currentProductPage the current productPage
* @return an HTTP response that represents a {@link ProductPage} from the file manager
*/
@GET
@Path("products")
@Produces({
"application/xml",
"application/json",
"application/atom+xml",
"application/rdf+xml",
"application/rss+xml"
})
public ProductPageResource getNextPage(
@QueryParam("productTypeName") String productTypeName,
@QueryParam("productName") String productName,
@QueryParam("currentProductPage") int currentProductPage)
throws WebApplicationException {
try {
FileManagerClient client = getContextClient();
Query query = new Query();
ProductPage productPage;
if (!StringUtils.isEmpty(productName)) {
Product product = client.getProductByName(productName);
List<Product> products = new ArrayList<Product>();
products.add(product);
productPage = new ProductPage(1, 1, 1, products);
}
else {
productPage = client.pagedQuery(query,client.getProductTypeByName(productTypeName),currentProductPage);
}
return getProductPageResource(client, productPage);
} catch (Exception e) {
throw new NotFoundException(e.getMessage());
}
}
/**
* This method is for creating a ProductPageResource Response and return it This method is for
* creating a ProductPageResource {@link ProductPage} Response and return it
*
* @param client FileManager client
* @param genericFile First/next/prev ProductPage
*/
private ProductPageResource getProductPageResource(
FileManagerClient client, ProductPage genericFile)
throws CatalogException, CasProductException {
// List for storing Metadata of the products in the ProductPage
List<Metadata> proMetaDataList = new ArrayList<>();
// List for storing References of the products in the ProductPage
List<List<Reference>> proReferencesList = new ArrayList<>();
for (Product pro : genericFile.getPageProducts()) {
Metadata metadata = client.getMetadata(pro);
List<Reference> productReferences = pro.getProductReferences();
proMetaDataList.add(metadata);
proReferencesList.add(productReferences);
}
ProductPageResource pageResource = new ProductPageResource(
genericFile, proMetaDataList, proReferencesList, getContextWorkingDir());
int totalProducts = genericFile.getPageProducts().size() == 1 ? 1 : getTotalNumOfProducts();
pageResource.setTotalProducts(totalProducts);
return pageResource;
}
/**
* Gets the file manager's working directory from the servlet context.
*
* @return the file manager working directory
* @throws Exception if an object cannot be retrieved from the context attribute
*/
public File getContextWorkingDir() throws CasProductException {
Object workingDirObject = context.getAttribute("workingDir");
if (workingDirObject != null && workingDirObject instanceof File) {
return (File) workingDirObject;
}
String message = ErrorType.CAS_PRODUCT_EXCEPTION_FILEMGR_WORKING_DIR_UNAVILABLE.getErrorType();
logger.debug("Exception Thrown: {}", message);
throw new CasProductException(message);
}
/**
* Gets the file manager client instance from the servlet context.
*
* @return the file manager client instance from the servlet context attribute
* @throws Exception if an object cannot be retrieved from the context attribute
*/
public FileManagerClient getContextClient() throws CasProductException {
// Get the file manager client from the servlet context.
Object clientObject = context.getAttribute("client");
if (clientObject != null && clientObject instanceof FileManagerClient) {
return (FileManagerClient) clientObject;
}
String message = ErrorType.CAS_PRODUCT_EXCEPTION_FILEMGR_CLIENT_UNAVILABLE.getErrorType();
logger.debug("Exception Thrown: {}", message);
throw new CasProductException(message);
}
/**
* Gets an HTTP response that represents a {@link Product} from the file manager.
*
* @param productId the ID of the product
* @return an HTTP response that represents a {@link Product} from the file manager
*/
@GET
@Path("product")
@Produces({
"application/xml",
"application/json",
"application/atom+xml",
"application/rdf+xml",
"application/rss+xml",
"application/zip"
})
public ProductResource getProduct(@QueryParam("productId") String productId)
throws WebApplicationException {
if (productId == null || productId.trim().equals("")) {
throw new BadRequestException(
ErrorType.BAD_REQUEST_EXCEPTION_PRODUCT_RESOURCE.getErrorType());
}
try {
FileManagerClient client = getContextClient();
// Find the product.
Product product = client.getProductById(productId);
product.setProductReferences(client.getProductReferences(product));
// Create the product resource, add the product data and return the
// resource as the HTTP response.
return new ProductResource(
product,
client.getMetadata(product),
product.getProductReferences(),
getContextWorkingDir());
} catch (Exception e) {
// Just for Logging Purposes
String message = "Unable to find the requested resource.";
logger.error(message, e);
throw new NotFoundException(e.getMessage());
}
}
/**
* Gets an HTTP response that represents a {@link Product} from the file manager.
*
* @param productFile the Product File to ingest
* @param productType ProductType of the ingesting Product - eg.GenericFile
* @param productStructure - Product Structure of the ingesting product - eg. Flat for
* Files/Hierarchy for Directory
* @return an HTTP response that represents the Ingesting Id if success
*/
@POST
@Path("productWithFile")
@Produces({"application/json", "application/xml"})
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response ingestProduct(
@Multipart("productFile") Attachment productFile,
@QueryParam("productType") String productType,
@QueryParam("productStructure") String productStructure) {
try {
// Take Data Handlers for Product and Metadata Files
DataHandler productFileDataHandler = productFile.getDataHandler();
// Get the input Streams of the CXF Attachments
InputStream productFileInputStream = productFileDataHandler.getInputStream();
// Write the Product File and MetaFiles to a temporary Files in server before ingest.
File inputProductFile =
writeToFileServer(
productFileInputStream, productFile.getContentDisposition().getParameter("filename"));
// Write Default Meta File
String defaultMetaFileContent =
"<cas:metadata xmlns:cas=\"http://oodt.jpl.nasa.gov/1.0/cas\">\n" + "</cas:metadata>";
writeToFileServer(
new ByteArrayInputStream(defaultMetaFileContent.getBytes(StandardCharsets.UTF_8)),
productFile.getContentDisposition().getParameter("filename") + ".met");
// Get File Manager and Its URL
FileManagerClient client = getContextClient();
URL fmURL = client.getFileManagerUrl();
// Use StdIngester for Simple File Ingesting
StdIngester ingester = new StdIngester(getDataTransferFactoryClass());
/*
* Use MetaReaderExtracter to extract File Metadata from Product File
* * A Met Extractor that assumes that the .met file has already been generated.
*/
MetExtractor metExtractor = new MetReaderExtractor();
Metadata prodMeta = metExtractor.extractMetadata(inputProductFile);
// Add Several Metadata to Metadata File
prodMeta.addMetadata(CoreMetKeys.FILENAME, inputProductFile.getName());
prodMeta.addMetadata(CoreMetKeys.PRODUCT_TYPE, productType);
prodMeta.addMetadata(CoreMetKeys.PRODUCT_STRUCTURE, productStructure);
prodMeta.addMetadata(CoreMetKeys.PRODUCT_NAME, inputProductFile.getName());
// Product File Location. should Only provide File Path without FileName
prodMeta.addMetadata(
CoreMetKeys.FILE_LOCATION,
(inputProductFile
.getAbsolutePath()
.substring(0, inputProductFile.getAbsolutePath().lastIndexOf(File.separator))));
String ingest = ingester.ingest(fmURL, inputProductFile, prodMeta);
return Response.ok(ingest).build();
} catch (Exception e) {
logger.error("Failed to ingest product", e);
throw new InternalServerErrorException(e.getMessage());
}
}
/**
* Gets an HTTP response that represents a {@link Product} from the file manager.
*
* @param productFile the Product File to ingest
* @param metadataFile the Metadata File to ingest
* @return an HTTP response that represents the Ingesting Id if success
*/
@POST
@Path("productWithMeta")
@Produces({"application/json", "application/xml"})
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response ingestProduct(
@Multipart("productFile") Attachment productFile,
@Multipart("metadataFile") Attachment metadataFile) {
try {
// Take Data Handlers for Product and Metadata Files
DataHandler productFileDataHandler = productFile.getDataHandler();
DataHandler metadataFileDataHandler = metadataFile.getDataHandler();
// Get the input Streams of the CXF Attachments
InputStream productFileInputStream = productFileDataHandler.getInputStream();
InputStream metadataFileInputStream = metadataFileDataHandler.getInputStream();
// Write the Product File and MetaFiles to a temporary Files in server before ingest.
File inputProductFile =
writeToFileServer(
productFileInputStream, productFile.getContentDisposition().getParameter("filename"));
// Get File Manager and Its URL
FileManagerClient client = getContextClient();
URL fmURL = client.getFileManagerUrl();
// Use StdIngester for Simple File Ingesting
StdIngester ingester = new StdIngester(getDataTransferFactoryClass());
Metadata prodMeta = new SerializableMetadata(metadataFileInputStream);
// Add Several Metadata to Metadata File
prodMeta.addMetadata(CoreMetKeys.FILENAME, inputProductFile.getName());
prodMeta.addMetadata(CoreMetKeys.PRODUCT_NAME, inputProductFile.getName());
// Product File Location. should Only provide File Path without FileName
prodMeta.addMetadata(
CoreMetKeys.FILE_LOCATION,
(inputProductFile
.getAbsolutePath()
.substring(0, inputProductFile.getAbsolutePath().lastIndexOf(File.separator))));
String ingest = ingester.ingest(fmURL, inputProductFile, prodMeta);
return Response.ok(ingest).build();
} catch (Exception e) {
logger.error("Failed to ingest product", e);
throw new InternalServerErrorException(e.getMessage());
}
}
/**
* This method uses to Write an InputStream to File in the Server
*
* @param inputStream
* @param fileName
*/
private File writeToFileServer(InputStream inputStream, String fileName) throws IOException {
java.nio.file.Path ingestedFile = tmpDir.resolve(fileName);
try (OutputStream outputStream = new FileOutputStream(ingestedFile.toFile())) {
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.flush();
}
return ingestedFile.toFile();
}
/**
* This method is for getting the current status of FileManager component
*
* @return Response object with status and FMProb URL
*/
@GET
@Path("fmprodstatus")
@Produces({"application/json", "application/xml"})
public Response getFmProductStatus() {
try {
FileManagerClient client = getContextClient();
String URL = client.getFileManagerUrl().toString();
boolean fmStatus = client.isAlive();
FMStatusResource status = new FMStatusResource(URL, fmStatus, "Server Status");
return Response.ok(status).build();
} catch (Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
/**
* This method is for removing the ingested Products
*
* @return Response object with status and FMProb URL
*/
@DELETE
@Path("removeProduct")
@Produces({"application/json", "application/xml"})
public Response removeIngestedProduct(@QueryParam("productId") String productId) {
try {
FileManagerClient client = getContextClient();
String URL = client.getFileManagerUrl().toString();
boolean fmStatus = client.isAlive();
boolean isRemoved = client.removeProduct(client.getProductById(productId));
FMStatusResource status =
new FMStatusResource(URL, fmStatus, "Product Removal Status: " + isRemoved);
return Response.ok(status).build();
} catch (Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
}
private String getDataTransferFactoryClass() {
String factoryClass = DATA_TRANSFER_FACTORY;
logger.debug("Using data transfer factory: {}", factoryClass);
return factoryClass;
}
// /**
// * This method is for retrieve a ingested Products
// *
// * @return Response object with status and FMProb URL
// */
// @GET
// @Path("downloadProduct")
//
// public Response downloadIngestedProduct(@QueryParam("productId") String productId) {
// try {
// FileManagerClient client = getContextClient();
//
// String URL = client.getFileManagerUrl().toString();
// boolean fmStatus = client.isAlive();
//
//// String d = client.getProductById(productId).;// byte[] bytes = client
// byte [] bytes =
// client.retrieveFile("/home/castle/Software_tools/apache-tomcat-9.0.20/bin/ingestedFiles/Hello_2", 0, 2000);
//
//
// //LOGGER.log(Level.INFO,"................."+d);
// // Path of a file
// String FILEPATH = "";
// File outputFile = new File(FILEPATH);
//
// // Initialize a pointer
// // in file using OutputStream
// OutputStream os = new FileOutputStream(outputFile);
//
// os.write(bytes);
//
// // Starts writing the bytes in it
// os.write(bytes);
// System.out.println("Successfully"
// + " byte inserted");
//
// // Close the file
// os.close();
// FMStatusResource status = new FMStatusResource(URL, fmStatus,"Product Retreval Status: " +
// bytes.length);
// return Response.ok(status).build();
//
// } catch (Exception e) {
// throw new InternalServerErrorException(e.getMessage());
// }
// }
}