blob: 8255a86eed2f47fe86f5469b239f0cf213031413 [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.curation.service;
//OODT imports
import org.apache.oodt.cas.curation.structs.ExtractorConfig;
import org.apache.oodt.cas.curation.util.CurationXmlStructFactory;
import org.apache.oodt.cas.curation.util.ExtractorConfigReader;
import org.apache.oodt.cas.filemgr.catalog.Catalog;
import org.apache.oodt.cas.filemgr.repository.XMLRepositoryManager;
import org.apache.oodt.cas.filemgr.structs.Product;
import org.apache.oodt.cas.filemgr.structs.ProductType;
import org.apache.oodt.cas.filemgr.structs.Reference;
import org.apache.oodt.cas.filemgr.structs.exceptions.CatalogException;
import org.apache.oodt.cas.filemgr.structs.exceptions.RepositoryManagerException;
import org.apache.oodt.cas.filemgr.util.GenericFileManagerObjectFactory;
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.exceptions.MetExtractionException;
import org.apache.oodt.cas.metadata.util.GenericMetadataObjectFactory;
//JDK imports
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//JAX-RS imports
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
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.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
//JSON imports
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
@Path("metadata")
/**
*
* A web-service endpoint for dealing with CAS {@link Metadata} object.
*
* @author pramirez
* @version $Id$
*/
public class MetadataResource extends CurationService {
@Context
UriInfo uriInfo;
private static final long serialVersionUID = 1930946924218765724L;
public static final String STAGING = "staging";
public static final String CATALOG = "catalog";
public static final String PRODUCT_TYPE = "productType";
public MetadataResource(){
}
public MetadataResource(@Context ServletContext context) {
}
@GET
@Path(STAGING)
@Produces("text/plain")
public String getStagingMetadata(@QueryParam("id") String id,
@DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
@QueryParam("configId") String configId,
@DefaultValue("false") @QueryParam("overwrite") Boolean overwrite,
@Context HttpServletRequest req, @Context HttpServletResponse res) {
// this.sendRedirect("login.jsp", uriInfo, res);
Metadata metadata = null;
try {
metadata = this.getStagingMetadata(id, configId, overwrite);
} catch (Exception e) {
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
if (FORMAT_HTML.equals(format)) {
return this.getMetadataAsHTML(metadata);
}
return this.getMetadataAsJSON(metadata).toString();
}
@GET
@Path("extractor/config")
@Produces("text/plain")
public String getMetExtractorConfigList(
@DefaultValue("") @QueryParam("current") String current,
@DefaultValue(FORMAT_HTML) @QueryParam("format") String format) {
String[] configIds = this.getFilesInDirectory(this.config
.getMetExtrConfUploadPath(), false);
if (FORMAT_HTML.equals(format)) {
return this.getExtractorConfigIdsAsHTML(configIds, current);
}
return this.getExtractorConfigIdsAsJSON(configIds);
}
protected String getExtractorConfigIdsAsHTML(String[] configIds,
String current) {
StringBuffer html = new StringBuffer();
for (int i = 0; i < configIds.length; i++) {
html.append("<option ");
if (configIds[i].equals(current)) {
html.append("selected ");
}
html.append("value=\"");
html.append(configIds[i]);
html.append("\">");
html.append(configIds[i]);
html.append("</option>\r\n");
}
return html.toString();
}
protected String getExtractorConfigIdsAsJSON(String[] configIds) {
// TODO: Support JSON
return "Not Implemented...";
}
/**
*
* @param id
* Relative path from staging root to product. The met extension will
* be added to this id to look up and see if a met file exists with
* in the met area.
* @param configId
* Reference to the extractor config. {@link ExtractorConfigReader}
* will load the configuration
* @param overwrite
* Flag to indicate whether or not to overwrite a met file if present
* in the staging area.
* @return The {@link Metadata} retrieved from the met area path if present or
* extracted using the met extractor config.
* @throws FileNotFoundException
* @throws InstantiationException
* @throws IOException
* @throws MetExtractionException
*/
protected Metadata getStagingMetadata(String id, String configId,
Boolean overwrite) throws FileNotFoundException, InstantiationException,
IOException, MetExtractionException {
if (configId == null || configId.trim().length() == 0) {
return this.readMetFile(id + CurationService.config.getMetExtension());
} else {
String relMetPath = id.startsWith("/") ? id : "/" + id;
String pathToMetFile = CurationService.config.getMetAreaPath()
+ relMetPath + CurationService.config.getMetExtension();
if (!overwrite && new File(pathToMetFile).exists()) {
return this.readMetFile(id + CurationService.config.getMetExtension());
} else {
// Make sure the parent directory exists
new File(pathToMetFile).getParentFile().mkdirs();
Metadata metadata = this.runMetExtractor(id, ExtractorConfigReader
.readFromDirectory(
new File(CurationService.config
.getMetExtrConfUploadPath()), configId));
this.writeMetFile(id, metadata);
return metadata;
}
}
}
/**
*
* @param id
* Relative path from staging root to the product
* @param config
* Configuration to run this met extractor
* @return
* @throws MetExtractionException
*/
protected Metadata runMetExtractor(String id, ExtractorConfig config)
throws MetExtractionException {
MetExtractor metExtractor = GenericMetadataObjectFactory
.getMetExtractorFromClassName(config.getClassName());
metExtractor.setConfigFile(config.getConfigFiles().get(0));
return metExtractor.extractMetadata(CurationService.config
.getStagingAreaPath()
+ "/" + id);
}
@GET
@Path(CATALOG)
@Produces("text/plain")
public String getCatalogMetadata(@QueryParam("id") String id,
@DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
@Context HttpServletRequest req, @Context HttpServletResponse res) {
// this.sendRedirect("login.jsp", uriInfo, res);
// Call file manager to get metadata
Product prod;
Metadata metadata;
String productId = id.substring(id.lastIndexOf("/") + 1);
try {
prod = CurationService.config.getFileManagerClient().getProductById(
productId);
metadata = this.getCatalogMetadata(prod);
} catch (Exception e) {
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
if (FORMAT_HTML.equals(format)) {
return this.getMetadataAsHTML(metadata);
}
return this.getMetadataAsJSON(metadata).toString();
}
@POST
@Path(CATALOG)
@Consumes("application/x-www-form-urlencoded")
@Produces("text/plain")
public String setCatalogMetadata(MultivaluedMap<String, String> formParams,
@FormParam("id") String id) {
Product prod;
Metadata metadata = this.getMetadataFromMap(formParams);
//FIXME: when https://issues.apache.org/jira/browse/CXF-3274
//is addressed
if (id == null) id = formParams.getFirst("id");
String productId = id.substring(id.lastIndexOf("/") + 1);
try {
prod = CurationService.config.getFileManagerClient().getProductById(
productId);
this.updateCatalogMetadata(prod, metadata);
} catch (Exception e) {
e.printStackTrace();
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
return this.getMetadataAsHTML(metadata);
}
@GET
@Path(PRODUCT_TYPE)
@Produces("text/plain")
public String getProductTypeMetadata(@QueryParam("id") String id,
@DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
@Context HttpServletRequest req, @Context HttpServletResponse res) {
// this.sendRedirect("login.jsp", uriInfo, res);
Metadata metadata;
String[] idParts = id.split("/");
String policy = idParts[1];
String productType = idParts[2];
try {
metadata = getProductTypeMetadataForPolicy(policy, productType);
} catch (Exception e) {
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
if (FORMAT_HTML.equals(format)) {
return this.getMetadataAsHTML(metadata);
}
return this.getMetadataAsJSON(metadata).toString();
}
@POST
@Path(PRODUCT_TYPE)
@Consumes("application/x-www-form-urlencoded")
@Produces("text/plain")
public String setProductTypeMetadata(MultivaluedMap<String, String> formParams) {
String[] idParts = formParams.getFirst("id").split("/");
String policy = idParts[1];
String productType = idParts[2];
try {
this.writeProductTypeMetadata(policy, productType, this
.getMetadataFromMap(formParams));
} catch (Exception e) {
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
return "";
}
@POST
@Path(STAGING)
@Consumes("application/x-www-form-urlencoded")
@Produces("text/plain")
public String setStagingMetadata(MultivaluedMap<String, String> formParams) {
try {
this.writeMetFile(formParams.getFirst("id"), this
.getMetadataFromMap(formParams));
} catch (Exception e) {
return "<div class=\"error\">" + e.getMessage() + "</div>";
}
return "";
}
@GET
@Path("staging/info")
@Produces("text/plain")
public String getMetadataInfo(@QueryParam("id") String id) {
return "Staging met info";
}
private JSONObject getMetadataAsJSON(Metadata metadata) {
return JSONObject.fromObject(metadata.getHashtable());
}
private Metadata getMetadataFromJSON(String metadataJSON) {
JSONObject json = (JSONObject) JSONSerializer.toJSON(metadataJSON);
Metadata metadata = new Metadata();
Set<String> keys = json.keySet();
for (String key : keys) {
List values = (List) JSONSerializer.toJava((JSONArray) json.get(key));
metadata.addMetadata(key, values);
}
return metadata;
}
private Metadata getMetadataFromMap(MultivaluedMap<String, String> formParams) {
Metadata metadata = new Metadata();
for (String key : formParams.keySet()) {
if (key.startsWith("metadata.")) {
String newKey = key.substring(key.indexOf('.') + 1);
for (String value : formParams.get(key)) {
metadata.addMetadata(newKey, value);
}
}
}
return metadata;
}
protected String getMetadataAsHTML(Metadata metadata) {
if (metadata == null) {
return "<table></table>";
}
StringBuffer html = new StringBuffer();
html.append("<table>\r\n");
for (String key : (Set<String>) metadata.getHashtable().keySet()) {
html.append(" <tr>\r\n");
html.append(" <th>").append(key).append("</th>\r\n");
html.append(" <td class=\"").append(key).append("\">");
List<String> values = metadata.getAllMetadata(key);
for (Iterator<String> i = values.iterator(); i.hasNext();) {
html.append("<span>").append(i.next()).append("</span>");
if (i.hasNext()) {
html.append(", ");
}
}
for (String value : (List<String>) metadata.getAllMetadata(key)) {
}
html.append("</td>\r\n");
html.append(" </tr>\r\n");
}
html.append("</table>\r\n");
return html.toString();
}
/**
* Reads a {@link Metadata} object from a String representation of a .met
* {@link File}.
*
* @param file
* The full path to the .met {@link File}.
* @return The read-in CAS {@link Metadata} object.
* @throws InstantiationException
* @throws InstantiationException
* If there is an error instantiating the {@link Metadata} class.
* @throws IOException
* @throws FileNotFoundException
* @throws FileNotFoundException
* If the .met {@link File} is not found.
* @throws IOException
* If there is an IO problem opening the met file.
*/
public Metadata readMetFile(String file) throws InstantiationException,
FileNotFoundException, IOException {
SerializableMetadata metadata = new SerializableMetadata("UTF-8", false);
metadata.loadMetadataFromXmlStream(new FileInputStream(config
.getMetAreaPath()
+ "/" + file));
return metadata;
}
/**
* Retrieves the cataloged {@link Metadata} associated with a {@link Product}.
*
* @param product
* The {@link Product} to obtain cataloged {@link Metadata} for.
* @return The cataloged {@link Metadata} for {@link Product}.
* @throws CatalogException
* If there is an error talking to the CAS File Manager
* {@link Catalog}.
*/
public Metadata getCatalogMetadata(Product product) throws CatalogException {
return CurationService.config.getFileManagerClient().getMetadata(
CurationService.config.getFileManagerClient().getProductById(
product.getProductId()));
}
/**
* Writes a CAS {@link Metadata} {@link File} using the given identifier.
*
* @param id
* The identifier of the .met file to write.
* @param metadata
* The {@link Metadata} object to persist and write to a {@link File}
* .
* @throws FileNotFoundException
* If the .met {@link File} cannot be written.
* @throws IOException
* If there is an IO exception writing the {@link File}.
*/
public void writeMetFile(String id, Metadata metadata)
throws FileNotFoundException, IOException {
SerializableMetadata serMet = new SerializableMetadata(metadata, "UTF-8",
false);
serMet.writeMetadataToXmlStream(new FileOutputStream(new File(config
.getMetAreaPath(), id + config.getMetExtension())));
}
/**
* Updates the cataloged {@link Metadata} for a {@link Product} in the CAS
* File Manager.
*
* @param product
* The {@link Product} to update {@link Metadata} for.
* @param metadata
* The new {@link Metadata} to persist into the {@link Catalog}.
* @throws CatalogException
* If any error occurs during the update.
* @throws IOException
* @throws FileNotFoundException
*/
public void updateCatalogMetadata(Product product, Metadata newMetadata)
throws CatalogException, FileNotFoundException, IOException {
System.getProperties().load(
new FileInputStream(CurationService.config.getFileMgrProps()));
Catalog catalog = GenericFileManagerObjectFactory
.getCatalogServiceFromFactory("org.apache.oodt.cas.curation.util.CuratorLuceneCatalogFactory");
Metadata oldMetadata = catalog.getMetadata(product);
List<Reference> references = catalog.getProductReferences(product);
Product newProduct = new Product(product.getProductName(), product
.getProductType(), product.getProductStructure(), product
.getTransferStatus(), product.getProductReferences());
// Constructor is bugged and doesn't set transfer status
newProduct.setTransferStatus(product.getTransferStatus());
catalog.removeMetadata(oldMetadata, product);
catalog.removeProduct(product);
newProduct.setProductId(product.getProductId());
catalog.addProduct(newProduct);
newProduct.setProductReferences(references);
catalog.addProductReferences(newProduct);
catalog.addMetadata(newMetadata, newProduct);
}
private Metadata getProductTypeMetadataForPolicy(String policy,
String productTypeName) throws MalformedURLException,
InstantiationException, RepositoryManagerException {
String rootPolicyPath = this.cleanse(CurationService.config
.getPolicyUploadPath());
String policyPath = new File(rootPolicyPath + policy).toURL()
.toExternalForm();
String[] policies = { policyPath };
XMLRepositoryManager repMgr = new XMLRepositoryManager(Arrays
.asList(policies));
ProductType productType = repMgr.getProductTypeByName(productTypeName);
return productType.getTypeMetadata();
}
private Metadata writeProductTypeMetadata(String policy,
String productTypeName, Metadata metadata) throws Exception {
String rootPolicyPath = this.cleanse(CurationService.config
.getPolicyUploadPath());
String policyPath = new File(rootPolicyPath + policy).toURL()
.toExternalForm();
String[] policies = { policyPath };
XMLRepositoryManager repMgr = new XMLRepositoryManager(Arrays
.asList(policies));
ProductType productType = repMgr.getProductTypeByName(productTypeName);
productType.setTypeMetadata(metadata);
CurationXmlStructFactory.writeProductTypeXmlDocument(repMgr
.getProductTypes(), rootPolicyPath + policy + "/product-types.xml");
// refresh the config on the fm end
CurationService.config.getFileManagerClient().refreshConfigAndPolicy();
return productType.getTypeMetadata();
}
private String cleanse(String origPath) {
String retStr = origPath;
if (!retStr.endsWith("/")) {
retStr += "/";
}
return retStr;
}
}