/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* 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.constellation.rest.api;
import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.util.logging.Logging;
import org.constellation.ServiceDef.Specification;
import org.constellation.business.IServiceBusiness;
import org.constellation.configuration.*;
import org.constellation.dto.Details;
import org.constellation.dto.ParameterValues;
import org.constellation.dto.SimpleValue;
import org.constellation.generic.database.Automatic;
import org.constellation.json.metadata.v2.Template;
import org.constellation.json.metadata.binding.RootObj;
import org.constellation.metadata.CSWworker;
import org.constellation.metadata.configuration.CSWConfigurer;
import org.constellation.ws.ServiceConfigurer;
import org.constellation.ws.WSEngine;
import org.opengis.metadata.Metadata;
import org.springframework.beans.factory.annotation.Autowired;
import org.w3c.dom.Node;
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 java.io.File;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.constellation.utils.RESTfulUtilities.ok;
import org.geotoolkit.index.tree.manager.NamedEnvelope;
import org.geotoolkit.util.StringUtilities;
/**
*
* @author Guilhem Legal (Geomatys)
* @author Cédric Briançon (Geomatys)
*/
@Path("/1/CSW")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public class CSWServicesRest {
@Autowired
protected IServiceBusiness serviceBusiness;
/**
* Used for debugging purposes.
*/
private static final Logger LOGGER = Logging.getLogger("org.constellation.rest.api");
@POST
@Path("{id}/index/refresh")
public Response refreshIndex(final @PathParam("id") String id, final ParameterValues values) throws Exception {
final boolean asynchrone = values.getAsBoolean("ASYNCHRONE");
final boolean forced = values.getAsBoolean("FORCED");
final CSWConfigurer conf = getConfigurer();
final AcknowlegementType ack = conf.refreshIndex(id, asynchrone, forced);
if (!asynchrone && ack.getStatus().equals("Success")) {
serviceBusiness.restart("CSW", id, true);
}
return ok(ack);
}
@PUT
@Path("{id}/index/{metaID}")
public Response AddToIndex(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
final List<String> identifiers = StringUtilities.toStringList(metaID);
return ok(getConfigurer().addToIndex(id, identifiers));
}
@DELETE
@Path("{id}/index/{metaID}")
public Response removeFromIndex(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
final List<String> identifiers = StringUtilities.toStringList(metaID);
return ok(getConfigurer().removeFromIndex(id, identifiers));
}
@POST
@Path("{id}/index/stop")
public Response stopIndexation(final @PathParam("id") String id) throws Exception {
return ok(getConfigurer().stopIndexation(id));
}
// TODO change fileName into dataType parameter
@PUT
@Path("{id}/records/{fileName}")
public Response importRecord(final @PathParam("id") String id, final @PathParam("fileName") String fileName, final File record) throws Exception {
return ok(getConfigurer().importRecords(id, record, fileName));
}
@PUT
@Path("{id}/records/data/{dataID}")
public Response importInternalData(final @PathParam("id") String id, final @PathParam("dataID") String metadataID) throws Exception {
return ok(getConfigurer().importInternalData(id, metadataID));
}
@GET
@Path("{id}/importInternaldata")
public Response canImportInternalData(final @PathParam("id") String id) throws Exception {
return ok(getConfigurer().canImportInternalData(id));
}
@GET
@Path("{id}/records/{count: \\w+}-{startIndex: \\w+}")
public Response getMetadataList(final @PathParam("id") String id, final @PathParam("count") int count, final @PathParam("startIndex") int startIndex) throws Exception {
final List<BriefNode> nodes = getConfigurer().getMetadataList(id, count, startIndex);
return ok(new BriefNodeList(nodes));
}
@DELETE
@Path("{id}/record/{metaID}")
public Response removeMetadata(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
return ok(getConfigurer().removeRecords(id, metaID));
}
@DELETE
@Path("{id}/records")
public Response removeAllMetadata(final @PathParam("id") String id) throws Exception {
return ok(getConfigurer().removeAllRecords(id));
}
@GET
@Path("{id}/record/{metaID}")
public Response getMetadata(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
return ok(getConfigurer().getMetadata(id, metaID));
}
@GET
@Path("{id}/clearCache")
public Response clearCache(final @PathParam("id") String id) throws Exception {
final CSWworker worker = (CSWworker) WSEngine.getInstance("CSW", id);
if (worker != null) {
worker.refresh();
return ok(AcknowlegementType.success("The CSW cache has been cleared"));
}
return ok(AcknowlegementType.failure("Unable to find a csw service " + id));
}
@GET
@Path("{id}/record/exist/{metaID}")
public Response metadataExist(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
return ok(getConfigurer().metadataExist(id, metaID));
}
@GET
@Path("{id}/record/download/{metaID}")
@Produces("application/xml")
public Response downloadMetadata(final @PathParam("id") String id, final @PathParam("metaID") String metaID) throws Exception {
final Node md = getConfigurer().getMetadata(id, metaID);
return Response.ok(md, MediaType.APPLICATION_XML_TYPE).header("Content-Disposition", "attachment; filename=\"" + metaID + ".xml\"").build();
}
@GET
@Path("{id}/records/count")
public Response getMetadataCount(final @PathParam("id") String id) throws Exception {
return ok(new SimpleValue(getConfigurer().getMetadataCount(id)));
}
@GET
@Path("types")
public Response getCSWDatasourceType() throws Exception {
return ok(getConfigurer().getAvailableCSWDataSourceType());
}
@POST
@Path("{id}/federatedCatalog")
public Response setFederatedCatalog(final @PathParam("id") String id, StringList url) throws Exception {
final Details details = serviceBusiness.getInstanceDetails("csw", id, null);
final Automatic conf = (Automatic) serviceBusiness.getConfiguration("csw", id);
final List<String> urls = conf.getParameterList("CSWCascading");
urls.addAll(url.getList());
conf.setParameterList("CSWCascading", urls);
serviceBusiness.configure("csw", id, details, conf);
return ok(new AcknowlegementType("Success", "federated catalog added"));
}
/**
* Returns applied template for metadata.
*
* @param id service identifier.
* @param metaID given record identifier.
* @param type type raster or vector.
* @param prune flag that indicates if template result will clean empty children/block.
* @return {@code Response}
*/
@GET
@Path("{id}/metadataJson/{metaID}/{type}/{prune}")
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
public Response getCSWMetadataJson(final @PathParam("id") String id,
final @PathParam("metaID") String metaID,
final @PathParam("type") String type,
final @PathParam("prune") boolean prune) {
try{
final CSWConfigurer configurer = getConfigurer();
final Node node = configurer.getMetadata(id, metaID);
if(node!=null){
final Metadata metadata = configurer.getMetadataFromNode(id, node);
if(metadata!=null){
if(metadata instanceof DefaultMetadata){
//prune the metadata
((DefaultMetadata)metadata).prune();
}
final StringWriter writer = new StringWriter();
final String templateName = configurer.getTemplateName(id, metaID, type);
final Template template = Template.getInstance(templateName);
template.write(metadata,writer,prune, false);
return Response.ok(writer.toString()).build();
}
}
}catch(Exception ex){
LOGGER.log(Level.WARNING, "error while writing metadata to json.", ex);
return Response.status(500).entity("failed").build();
}
return Response.status(500).entity("Cannot get metadata for id "+metaID).build();
}
private static CSWConfigurer getConfigurer() throws NotRunningServiceException {
return (CSWConfigurer) ServiceConfigurer.newInstance(Specification.CSW);
}
/**
* Proceed to save metadata with given values from metadata editor.
*
* @param id service identifier.
* @param metaID given record identifier.
* @param type the data type.
* @param metadataValues the values of metadata editor.
* @return {@code Response}
*/
@POST
@Path("{id}/metadata/save/{metaID}/{type}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response saveMetadata(final @PathParam("id") String id,
final @PathParam("metaID") String metaID,
final @PathParam("type") String type,
final RootObj metadataValues) {
try {
final CSWConfigurer configurer = getConfigurer();
final Node node = configurer.getMetadata(id, metaID);
if(node!=null){
final Metadata metadata = configurer.getMetadataFromNode(id, node);
if(metadata!=null){
//get template name
final String templateName = configurer.getTemplateName(id, metaID, type);
final Template template = Template.getInstance(templateName);
template.read(metadataValues,metadata,false);
// Save metadata
final Node result = configurer.getNodeFromGeotkMetadata(id, metadata);
//@TODO call updateRecord instead
getConfigurer().importRecord(id,result);
}
}
} catch (Exception ex) {
LOGGER.log(Level.WARNING, "Error while saving metadata", ex);
return Response.status(500).entity(ex.getLocalizedMessage()).build();
}
return Response.ok().type(MediaType.TEXT_PLAIN_TYPE).build();
}
@GET
@Path("{serviceID}/mapper")
@Produces("text/html")
public String getMapperContent(@PathParam("serviceID") final String serviceID) throws ConfigurationException {
final CSWConfigurer configurer = getConfigurer();
final Map<Integer, NamedEnvelope> map = configurer.getMapperContent(serviceID);
StringBuilder s = new StringBuilder("<html><body><table border=\"1\"><tr><th>Tree ID</td><th> Envelope</td></tr>");
for (Entry<Integer, NamedEnvelope> entry : map.entrySet()) {
s.append("<tr><td>").append(Integer.toString(entry.getKey())).append("</td><td>").append(entry.getValue().toString()).append("</td></tr>");
}
s.append("</table></body></html>");
return s.toString();
}
@GET
@Path("{serviceID}/tree")
@Produces("text/plain")
public String getStreeRepresentation(@PathParam("serviceID") final String serviceID) throws ConfigurationException {
final CSWConfigurer configurer = getConfigurer();
final String result = configurer.getTreeRepresentation(serviceID);
return result;
}
}