diff --git a/client/src/main/java/org/n52/geolabel/client/DocumentReference.java b/client/src/main/java/org/n52/geolabel/client/DocumentReference.java index 425146d..4c9f0cd 100644 --- a/client/src/main/java/org/n52/geolabel/client/DocumentReference.java +++ b/client/src/main/java/org/n52/geolabel/client/DocumentReference.java @@ -90,6 +90,19 @@ public InputStream getContent() throws IOException { HttpEntity responseEntity = httpClient.execute(new HttpGet(this.documentUrl.toString())).getEntity(); return responseEntity.getContent(); } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("URLDocument ["); + if (this.documentUrl != null) { + builder.append("documentUrl="); + builder.append(this.documentUrl); + } + builder.append("]"); + return builder.toString(); + } + } /** @@ -109,6 +122,18 @@ public InputStream getContent() { return null; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("InputStreamDocument ["); + if (this.documentStream != null) { + builder.append("documentStream="); + builder.append(this.documentStream); + } + builder.append("]"); + return builder.toString(); + } + } /** @@ -138,6 +163,18 @@ public InputStream getContent() throws IOException { return null; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("XMLDocument ["); + if (this.documentXml != null) { + builder.append("documentXml="); + builder.append(this.documentXml); + } + builder.append("]"); + return builder.toString(); + } + } } \ No newline at end of file diff --git a/client/src/main/java/org/n52/geolabel/client/GeoLabelClientV1.java b/client/src/main/java/org/n52/geolabel/client/GeoLabelClientV1.java index 4fc8e8a..653c910 100644 --- a/client/src/main/java/org/n52/geolabel/client/GeoLabelClientV1.java +++ b/client/src/main/java/org/n52/geolabel/client/GeoLabelClientV1.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.net.URISyntaxException; import org.apache.commons.io.IOUtils; @@ -86,9 +87,11 @@ else if (labelRequestBuilder.feedbackDocument != null && !labelRequestBuilder.fe builder.setParameter(PARAM_METADATA, labelRequestBuilder.metadataDocument.getUrl().toString()); if (labelRequestBuilder.getDesiredSize() != null) - builder.setParameter(PARAM_DESIREDSIZE, "" + labelRequestBuilder.getDesiredSize()); + builder.setParameter(PARAM_DESIREDSIZE, labelRequestBuilder.getDesiredSize().toString()); - request = new HttpGet(builder.build()); + URI requestUri = builder.build(); + + request = new HttpGet(requestUri); } catch (URISyntaxException e) { throw new IOException(e); } @@ -116,6 +119,7 @@ else if (labelRequestBuilder.feedbackDocument != null && !labelRequestBuilder.fe } // Issue request + log.debug("Issuing request {}", request); HttpResponse response = HTTPCLIENT.execute(request); if (response.getStatusLine().getStatusCode() != 200) { @@ -139,8 +143,11 @@ else if (labelRequestBuilder.feedbackDocument != null && !labelRequestBuilder.fe }; protected final static DefaultHttpClient HTTPCLIENT; - private static Logger log = LoggerFactory.getLogger(GeoLabelClientV1.class); + + static Logger log = LoggerFactory.getLogger(GeoLabelClientV1.class); + protected static final String PARAM_DESIREDSIZE = Constants.PARAM_SIZE; + protected static final String PARAM_FEEDBACK = Constants.PARAM_FEEDBACK; protected static final String PARAM_FEEDBACK_DRILL = Constants.PARAM_FEEDBACK_DRILL; @@ -167,7 +174,7 @@ public static GeoLabelRequestBuilder createGeoLabelRequest() { } public static GeoLabelRequestBuilder createGeoLabelRequest(String serviceUrl) { - return new GeoLabelRequestBuilder(geolabelRequestHandler, DEFAULT_GEO_LABEL_SERVER); + return new GeoLabelRequestBuilder(geolabelRequestHandler, serviceUrl); } @Override diff --git a/client/src/main/java/org/n52/geolabel/client/GeoLabelRequestBuilder.java b/client/src/main/java/org/n52/geolabel/client/GeoLabelRequestBuilder.java index e149d48..72feab3 100644 --- a/client/src/main/java/org/n52/geolabel/client/GeoLabelRequestBuilder.java +++ b/client/src/main/java/org/n52/geolabel/client/GeoLabelRequestBuilder.java @@ -139,4 +139,41 @@ public GeoLabelRequestBuilder setUseCache(boolean useCache) { return this; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("GeoLabelRequestBuilder ["); + if (this.metadataDocument != null) { + builder.append("metadataDocument="); + builder.append(this.metadataDocument); + builder.append(", "); + } + if (this.feedbackDocument != null) { + builder.append("feedbackDocument="); + builder.append(this.feedbackDocument); + builder.append(", "); + } + if (this.requestHandler != null) { + builder.append("requestHandler="); + builder.append(this.requestHandler); + builder.append(", "); + } + if (this.desiredSize != null) { + builder.append("desiredSize="); + builder.append(this.desiredSize); + builder.append(", "); + } + builder.append("forceDownload="); + builder.append(this.forceDownload); + builder.append(", useCache="); + builder.append(this.useCache); + builder.append(", "); + if (this.serviceUrl != null) { + builder.append("serviceUrl="); + builder.append(this.serviceUrl); + } + builder.append("]"); + return builder.toString(); + } + } \ No newline at end of file diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/package-info.java b/commons/src/main/java/org/n52/geolabel/commons/ErrorFacet.java similarity index 61% rename from server/src/main/java/org/n52/geolabel/server/mapping/description/package-info.java rename to commons/src/main/java/org/n52/geolabel/commons/ErrorFacet.java index 979fba9..2a78927 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/package-info.java +++ b/commons/src/main/java/org/n52/geolabel/commons/ErrorFacet.java @@ -13,9 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@XmlAccessorType(XmlAccessType.NONE) -package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; +package org.n52.geolabel.commons; +//@XmlRootElement(name = "errorInformation") +public class ErrorFacet extends LabelFacet { + // @XmlElement + private String errorMessage; + + public String getErrorMessage() { + return this.errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + updateAvailability(Availability.AVAILABLE); + } + +} \ No newline at end of file diff --git a/commons/src/main/java/org/n52/geolabel/commons/Label.java b/commons/src/main/java/org/n52/geolabel/commons/Label.java index 1f90fed..b002402 100644 --- a/commons/src/main/java/org/n52/geolabel/commons/Label.java +++ b/commons/src/main/java/org/n52/geolabel/commons/Label.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.geolabel.commons; import java.io.IOException; @@ -36,27 +37,28 @@ import freemarker.template.Template; import freemarker.template.TemplateException; - @XmlRootElement(name = "geoLabel") public class Label { - private static class FacetHolder { - @XmlElementRef - protected ProducerProfileFacet producerProfileFacet = new ProducerProfileFacet(); - @XmlElementRef - protected ProducerCommentsFacet producerCommentsFacet = new ProducerCommentsFacet(); - @XmlElementRef - protected LineageFacet lineageFacet = new LineageFacet(); - @XmlElementRef - protected StandardsComplianceFacet standardsComplianceFacet = new StandardsComplianceFacet(); - @XmlElementRef - protected QualityInformationFacet qualityInformationFacet = new QualityInformationFacet(); - @XmlElementRef - protected UserFeedbackFacet userFeedbackFacet = new UserFeedbackFacet(); - @XmlElementRef - protected ExpertFeedbackFacet expertFeedbackFacet = new ExpertFeedbackFacet(); - @XmlElementRef - protected CitationsFacet citationsFacet = new CitationsFacet(); + private static class FacetHolder { + @XmlElementRef + protected ProducerProfileFacet producerProfileFacet = new ProducerProfileFacet(); + @XmlElementRef + protected ProducerCommentsFacet producerCommentsFacet = new ProducerCommentsFacet(); + @XmlElementRef + protected LineageFacet lineageFacet = new LineageFacet(); + @XmlElementRef + protected StandardsComplianceFacet standardsComplianceFacet = new StandardsComplianceFacet(); + @XmlElementRef + protected QualityInformationFacet qualityInformationFacet = new QualityInformationFacet(); + @XmlElementRef + protected UserFeedbackFacet userFeedbackFacet = new UserFeedbackFacet(); + @XmlElementRef + protected ExpertFeedbackFacet expertFeedbackFacet = new ExpertFeedbackFacet(); + @XmlElementRef + protected CitationsFacet citationsFacet = new CitationsFacet(); + + protected ErrorFacet errorFacet = new ErrorFacet(); public FacetHolder() { // @@ -104,105 +106,124 @@ public String toString() { if (this.citationsFacet != null) { builder.append("citationsFacet="); builder.append(this.citationsFacet); + builder.append(", "); + } + if (this.errorFacet != null) { + builder.append("errorFacet="); + builder.append(this.errorFacet); } builder.append("]"); return builder.toString(); } - } + } - final static Logger log = LoggerFactory.getLogger(Label.class); + final static Logger log = LoggerFactory.getLogger(Label.class); - @XmlElement(name = "facets") - private FacetHolder facetHolder = new FacetHolder(); + @XmlElement(name = "facets") + private FacetHolder facetHolder = new FacetHolder(); - private static Unmarshaller unmarshaller; - private static Marshaller marshaller; - private static Template svgTemplate; + private static Unmarshaller unmarshaller; + private static Marshaller marshaller; + private static Template svgTemplate; - public ProducerProfileFacet getProducerProfileFacet() { + public ProducerProfileFacet getProducerProfileFacet() { return this.facetHolder.producerProfileFacet; - } + } - public LineageFacet getLineageFacet() { + public LineageFacet getLineageFacet() { return this.facetHolder.lineageFacet; - } + } - public ProducerCommentsFacet getProducerCommentsFacet() { + public ProducerCommentsFacet getProducerCommentsFacet() { return this.facetHolder.producerCommentsFacet; - } + } - public StandardsComplianceFacet getStandardsComplianceFacet() { + public StandardsComplianceFacet getStandardsComplianceFacet() { return this.facetHolder.standardsComplianceFacet; - } + } - public QualityInformationFacet getQualityInformationFacet() { + public QualityInformationFacet getQualityInformationFacet() { return this.facetHolder.qualityInformationFacet; - } + } - public FeedbackFacet getUserFeedbackFacet() { + public FeedbackFacet getUserFeedbackFacet() { return this.facetHolder.userFeedbackFacet; - } + } - public FeedbackFacet getExpertFeedbackFacet() { + public FeedbackFacet getExpertFeedbackFacet() { return this.facetHolder.expertFeedbackFacet; - } + } - public CitationsFacet getCitationsFacet() { + public CitationsFacet getCitationsFacet() { return this.facetHolder.citationsFacet; - } - - public static Label fromXML(InputStream input) throws IOException { - try { - if (unmarshaller == null) - unmarshaller = JAXBContext.newInstance(Label.class).createUnmarshaller(); - - Label label = (Label) unmarshaller.unmarshal(input); - return label; - } catch (JAXBException e) { - throw new IOException(e); - } - } - - public void toXML(OutputStream outputStream) throws IOException { - try { - if (marshaller == null) - marshaller = JAXBContext.newInstance(Label.class).createMarshaller(); - - marshaller.marshal(this, outputStream); - } catch (JAXBException e) { - throw new IOException(e); - } - } - - /** - * Obtains freemarker template for geolabel from classpath and caches - * result. - * - * @return - * @throws IOException - */ - private static Template getSVGTemplate() throws IOException { - if (svgTemplate == null) { - Configuration configuration = new Configuration(); - configuration.setClassForTemplateLoading(Label.class, ""); - svgTemplate = configuration.getTemplate("geolabel.ftl"); - } - return svgTemplate; - } - - public void toSVG(Writer writer, final String id, final int size) throws IOException { - try { - SimpleHash model = new SimpleHash(); + } + + public ErrorFacet getErrorFacet() { + return this.facetHolder.errorFacet; + } + + public static Label fromXML(InputStream input) throws IOException { + try { + if (unmarshaller == null) + unmarshaller = JAXBContext.newInstance(Label.class).createUnmarshaller(); + + Label label = (Label) unmarshaller.unmarshal(input); + return label; + } + catch (JAXBException e) { + throw new IOException(e); + } + } + + public void toXML(OutputStream outputStream) throws IOException { + try { + if (marshaller == null) + marshaller = JAXBContext.newInstance(Label.class).createMarshaller(); + + marshaller.marshal(this, outputStream); + } + catch (JAXBException e) { + throw new IOException(e); + } + } + + /** + * Obtains freemarker template for geolabel from classpath and caches result. + * + * @return + * @throws IOException + */ + private static Template getSVGTemplate() throws IOException { + if (svgTemplate == null) { + Configuration configuration = new Configuration(); + configuration.setClassForTemplateLoading(Label.class, ""); + svgTemplate = configuration.getTemplate("geolabel.ftl"); + } + return svgTemplate; + } + + public void setError(Exception e) { + String formattedException = String.format("Error: %s \nMessage: %s", + e.getClass().getName(), + e.getMessage(), + e.getStackTrace()); + this.facetHolder.errorFacet.setErrorMessage(formattedException); + } + + public void toSVG(Writer writer, final String id, final int size) throws IOException { + try { + SimpleHash model = new SimpleHash(); model.put("size", Integer.valueOf(size)); - model.put("id", id); - model.put("label", this); - - getSVGTemplate().process(model, writer); - } catch (TemplateException e) { - log.error("Error in geolabel template", e); - throw new IOException("Unable to process SVG template"); - } - } + model.put("id", id); + model.put("label", this); + + getSVGTemplate().process(model, writer); + } + catch (TemplateException e) { + log.error("Error in geolabel template", e); + throw new IOException("Unable to process SVG template"); + } + } @Override public String toString() { diff --git a/commons/src/main/java/org/n52/geolabel/commons/LabelFacet.java b/commons/src/main/java/org/n52/geolabel/commons/LabelFacet.java index 47d8b05..b9abf72 100644 --- a/commons/src/main/java/org/n52/geolabel/commons/LabelFacet.java +++ b/commons/src/main/java/org/n52/geolabel/commons/LabelFacet.java @@ -13,79 +13,90 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.geolabel.commons; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.adapters.XmlAdapter; -@XmlSeeAlso({ ProducerProfileFacet.class, LineageFacet.class, ProducerCommentsFacet.class, - StandardsComplianceFacet.class, QualityInformationFacet.class, FeedbackFacet.class, CitationsFacet.class }) +@XmlSeeAlso({ProducerProfileFacet.class, + LineageFacet.class, + ProducerCommentsFacet.class, + StandardsComplianceFacet.class, + QualityInformationFacet.class, + FeedbackFacet.class, + CitationsFacet.class}) public abstract class LabelFacet { - /** - * Mapping LML availability indicator - */ - public enum Availability { - AVAILABLE(1), NOT_AVAILABLE(0), AVAILABLE_HIGHER(2), NA(-1); + /** + * Mapping LML availability indicator + */ + public enum Availability { + AVAILABLE(1), NOT_AVAILABLE(0), AVAILABLE_HIGHER(2), NA( -1); protected int code; - private Availability(int code) { - this.code = code; - } + private Availability(int code) { + this.code = code; + } - public static Availability fromString(String v) { - try { + public static Availability fromString(String v) { + try { return fromLmlCode(Integer.valueOf(v)); - } catch (NumberFormatException e) { - return NA; - } - } + } + catch (NumberFormatException e) { + return NA; + } + } - public static Availability fromLmlCode(Integer v) { + public static Availability fromLmlCode(Integer v) { switch (v.intValue()) { - case 0: - return NOT_AVAILABLE; - case 1: - return AVAILABLE; - case 2: - return AVAILABLE_HIGHER; - default: - return NA; - } - } - - public static class AvailabilityAdapter extends XmlAdapter { - - @Override - public Integer marshal(Availability v) throws Exception { + case 0: + return NOT_AVAILABLE; + case 1: + return AVAILABLE; + case 2: + return AVAILABLE_HIGHER; + default: + return NA; + } + } + + public static class AvailabilityAdapter extends XmlAdapter { + + @Override + public Integer marshal(Availability v) throws Exception { return Integer.valueOf(v.code); - } + } - @Override - public Availability unmarshal(Integer v) throws Exception { - return fromLmlCode(v); - } + @Override + public Availability unmarshal(Integer v) throws Exception { + return fromLmlCode(v); + } - } + } } - @XmlElement - private Availability availability = Availability.NA; + @XmlElement + private Availability availability = Availability.NA; - @XmlElement - private String drilldownURL; + @XmlElement + private String drilldownURL; - public Availability getAvailability() { + public Availability getAvailability() { return this.availability; - } + } - public String getDrilldownURL() { + public String getDrilldownURL() { return this.drilldownURL; - } + } - /** + public void setDrilldownURL(String drilldownURL) { + this.drilldownURL = drilldownURL; + } + + /** * Updating availability status. AVAILABLE beats all, NOT_AVAILABLE beats NA * * @param availabilityP @@ -93,7 +104,7 @@ public String getDrilldownURL() { public void updateAvailability(Availability availabilityP) { if (this.availability == Availability.NA || availabilityP == Availability.AVAILABLE) this.availability = availabilityP; - } + } @Override public String toString() { diff --git a/commons/src/main/java/org/n52/geolabel/commons/ProducerProfileFacet.java b/commons/src/main/java/org/n52/geolabel/commons/ProducerProfileFacet.java index 8c13f38..e856cde 100644 --- a/commons/src/main/java/org/n52/geolabel/commons/ProducerProfileFacet.java +++ b/commons/src/main/java/org/n52/geolabel/commons/ProducerProfileFacet.java @@ -25,6 +25,7 @@ @XmlRootElement(name = "producerProfile") public class ProducerProfileFacet extends LabelFacet { + @XmlElement(name = "producerOrganisationName") private Set organizationNames; @@ -37,7 +38,7 @@ public Collection getOrganizationNames() { public void addOrganizationNames(String organizationName) { if (this.organizationNames == null) - this.organizationNames = new HashSet(); + this.organizationNames = new HashSet<>(); this.organizationNames.add(organizationName); } } \ No newline at end of file diff --git a/commons/src/main/resources/org/n52/geolabel/commons/geolabel.ftl b/commons/src/main/resources/org/n52/geolabel/commons/geolabel.ftl index d792012..76ed8bc 100644 --- a/commons/src/main/resources/org/n52/geolabel/commons/geolabel.ftl +++ b/commons/src/main/resources/org/n52/geolabel/commons/geolabel.ftl @@ -517,6 +517,38 @@ + + + inline<#else>none"> + + + + + + + + + + diff --git a/integration-test/src/test/java/org/n52/geolabel/client/GeoLabelClientV1IT.java b/integration-test/src/test/java/org/n52/geolabel/client/GeoLabelClientV1IT.java index e8dee10..a93b009 100644 --- a/integration-test/src/test/java/org/n52/geolabel/client/GeoLabelClientV1IT.java +++ b/integration-test/src/test/java/org/n52/geolabel/client/GeoLabelClientV1IT.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.geolabel.client; import static org.junit.Assert.assertTrue; @@ -23,84 +24,75 @@ import org.apache.commons.io.IOUtils; import org.junit.Test; -import org.n52.geolabel.client.GeoLabelCache; -import org.n52.geolabel.client.GeoLabelClientV1; public class GeoLabelClientV1IT { - @Test - public void testCreateGeoLabelMetadataStream() throws IOException { - InputStream metadataStream = getClass().getResourceAsStream("FAO_GEO_Network_iso19139.xml"); - InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataStream).getSVG(); - String svgString = IOUtils.toString(svg); - - assertTrue(svgString - .contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); - assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); - } - - @Test - public void testCreateGeoLabelMetadataAndFeedbackStream() throws IOException { - InputStream metadataStream = getClass().getResourceAsStream("FAO_GEO_Network_iso19139.xml"); - InputStream feedbackStream = getClass().getResourceAsStream("GVQ_Feedback_All_Available.xml"); - - InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataStream) - .setFeedbackDocument(feedbackStream).getSVG(); - String svgString = IOUtils.toString(svg); - - assertTrue(svgString - .contains("User Feedback. Number of feedbacks 3. Average rating: 3 (2 ratings).")); - } - - @Test - public void testCreateGeoLabelMetadataUrl() throws IOException { - String metadataUrl = "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_v10.xml"; - InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataUrl).getSVG(); - String svgString = IOUtils.toString(svg); - - assertTrue("organization", svgString.contains("Animal and Plant Biology and Ecology Department")); - assertTrue(svgString.contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); - assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); - } - - @Test - public void testCreateGeoLabelMetadataUrlAndFeedbackStream() throws IOException { - String metadataUrl = "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_v10.xml"; - InputStream feedbackStream = getClass().getResourceAsStream("GVQ_Feedback_All_Available.xml"); - - InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataUrl) - .setFeedbackDocument(feedbackStream).getSVG(); - String svgString = IOUtils.toString(svg); - - assertTrue(svgString - .contains("User Feedback. Number of feedbacks 3. Average rating: 3 (2 ratings).")); - } - - @Test - public void testCreateGeoLabelMetadataUrlCache() throws IOException { - String metadataUrl = "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_v10.xml"; - - GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataUrl).setUseCache(true).getSVG(); - - assertTrue(GeoLabelCache.hasSVG(metadataUrl)); - - InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataUrl).setUseCache(true) - .getSVG(); - String svgString = IOUtils.toString(svg); - - assertTrue("organization", svgString.contains("Animal and Plant Biology and Ecology Department")); - assertTrue(svgString.contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); - assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); - } - - @Test - public void testCreateGeoLabelNoContent() { - try { - GeoLabelClientV1.createGeoLabelRequest().getSVG(); - fail("Server should send error code"); - } catch (IOException e) { - assertTrue(e.getMessage().contains("Bad Request")); - } - - } + private String gvqExample = "http://schemas.geoviqua.org/GVQ/4.0/example_documents/PQM_UQM_combined/DigitalClimaticAtlas_mt_an_v10.xml"; + + @Test + public void testCreateGeoLabelMetadataStream() throws IOException { + InputStream metadataStream = getClass().getResourceAsStream("FAO_GEO_Network_iso19139.xml"); + InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataStream).getSVG(); + String svgString = IOUtils.toString(svg); + + assertTrue(svgString.contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); + assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); + } + + @Test + public void testCreateGeoLabelMetadataAndFeedbackStream() throws IOException { + InputStream metadataStream = getClass().getResourceAsStream("FAO_GEO_Network_iso19139.xml"); + InputStream feedbackStream = getClass().getResourceAsStream("GVQ_Feedback_All_Available.xml"); + + InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(metadataStream).setFeedbackDocument(feedbackStream).getSVG(); + String svgString = IOUtils.toString(svg); + + assertTrue(svgString.contains("User Feedback. Number of feedbacks 3. Average rating: 3 (2 ratings).")); + } + + @Test + public void testCreateGeoLabelMetadataUrl() throws IOException { + InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(this.gvqExample).getSVG(); + String svgString = IOUtils.toString(svg); + + assertTrue("organization", svgString.contains("Animal and Plant Biology and Ecology Department")); + assertTrue(svgString.contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); + assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); + } + + @Test + public void testCreateGeoLabelMetadataUrlAndFeedbackStream() throws IOException { + InputStream feedbackStream = getClass().getResourceAsStream("GVQ_Feedback_All_Available.xml"); + + InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(this.gvqExample).setFeedbackDocument(feedbackStream).getSVG(); + String svgString = IOUtils.toString(svg); + + assertTrue(svgString.contains("User Feedback. Number of feedbacks 3. Average rating: 3 (2 ratings).")); + } + + @Test + public void testCreateGeoLabelMetadataUrlCache() throws IOException { + GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(this.gvqExample).setUseCache(true).getSVG(); + + assertTrue(GeoLabelCache.hasSVG(this.gvqExample)); + + InputStream svg = GeoLabelClientV1.createGeoLabelRequest().setMetadataDocument(this.gvqExample).setUseCache(true).getSVG(); + String svgString = IOUtils.toString(svg); + + assertTrue("organization", svgString.contains("Animal and Plant Biology and Ecology Department")); + assertTrue(svgString.contains("Standards Compliance. Standard name: ISO 19115:2003/19139, version 1.0.")); + assertTrue("ensure has no feedback info", svgString.contains("User Feedback")); + } + + @Test + public void testCreateGeoLabelNoContent() { + try { + GeoLabelClientV1.createGeoLabelRequest().getSVG(); + fail("Server should send error code"); + } + catch (IOException e) { + assertTrue(e.getMessage().contains("Bad Request")); + } + + } } diff --git a/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponent.java b/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponent.java index d8141e2..5678cfd 100644 --- a/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponent.java +++ b/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponent.java @@ -32,15 +32,21 @@ import org.apache.commons.io.IOUtils; import org.n52.geolabel.client.GeoLabelClientV1; import org.n52.geolabel.client.GeoLabelRequestBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @FacesComponent("geolabelcomponent") @ResourceDependency(library = "javax.faces", name = "jsf.js") public class GeoLabelComponent extends UIComponentBase { + private static Logger log = LoggerFactory.getLogger(GeoLabelComponent.class); + enum PropertyKeys { metadataUrl, feedbackUrl, size, async, serviceUrl, metadataContent, feedbackContent, forceDownload, useCache; } + private static final String INPUTSTREAM_CHARSET = "utf-8"; + public GeoLabelComponent() { super(); } @@ -54,7 +60,8 @@ public void setMetadataUrl(String mMetadataUrl) { } public String getServiceUrl() { - return (String) getStateHelper().eval(PropertyKeys.serviceUrl); + Object url = getStateHelper().eval(PropertyKeys.serviceUrl); + return (String) url; } public void setServiceUrl(String mServiceUrl) { @@ -98,7 +105,7 @@ public Boolean isAsync() { } public void setAsync(boolean async) { - getStateHelper().put(PropertyKeys.async, async); + getStateHelper().put(PropertyKeys.async, Boolean.valueOf(async)); } public Boolean isUseCache() { @@ -106,7 +113,7 @@ public Boolean isUseCache() { } public void setUseCache(boolean cache) { - getStateHelper().put(PropertyKeys.useCache, cache); + getStateHelper().put(PropertyKeys.useCache, Boolean.valueOf(cache)); } public Boolean isForceDownload() { @@ -114,7 +121,7 @@ public Boolean isForceDownload() { } public void setForceDownload(boolean force) { - getStateHelper().put(PropertyKeys.forceDownload, force); + getStateHelper().put(PropertyKeys.forceDownload, Boolean.valueOf(force)); } @Override @@ -145,7 +152,7 @@ public void encodeBegin(FacesContext context) throws IOException { /** * Requests a GeoLabel and writes it to the component - * + * * @param context * @throws IOException */ @@ -153,38 +160,48 @@ private void writeLocalLabel(FacesContext context) throws IOException { ResponseWriter writer = context.getResponseWriter(); writer.startElement("div", this); writer.writeAttribute("id", getClientId(context), null); + try { GeoLabelRequestBuilder requestBuilder; - if (getServiceUrl() != null && !getServiceUrl().isEmpty()) + String serviceUrl = getServiceUrl(); + if (serviceUrl != null && !serviceUrl.isEmpty()) // Custom service url - requestBuilder = GeoLabelClientV1.createGeoLabelRequest(getServiceUrl()); + requestBuilder = GeoLabelClientV1.createGeoLabelRequest(serviceUrl); else // Default service url requestBuilder = GeoLabelClientV1.createGeoLabelRequest(); // Set metadata - if (getMetadataUrl() != null && !getMetadataUrl().isEmpty()) - requestBuilder.setMetadataDocument(getMetadataUrl()); - else if (getMetadataContent() != null && !getMetadataContent().isEmpty()) - requestBuilder.setMetadataDocument(IOUtils.toInputStream(getMetadataContent(), Charset.forName("utf-8"))); // TODO - // charset + if (getMetadataUrl() != null && !getMetadataUrl().isEmpty()) { + String url = getMetadataUrl(); + requestBuilder.setMetadataDocument(url); + } + else if (getMetadataContent() != null && !getMetadataContent().isEmpty()) { + String content = getMetadataContent(); + requestBuilder.setMetadataDocument(IOUtils.toInputStream(content, Charset.forName(INPUTSTREAM_CHARSET))); + } + // Set feedback - if (getFeedbackUrl() != null && !getFeedbackUrl().isEmpty()) - requestBuilder.setFeedbackDocument(getFeedbackUrl()); + if (getFeedbackUrl() != null && !getFeedbackUrl().isEmpty()) { + String url = getFeedbackUrl(); + requestBuilder.setFeedbackDocument(url); + } else if (getFeedbackContent() != null && !getFeedbackContent().isEmpty()) - requestBuilder.setFeedbackDocument(IOUtils.toInputStream(getFeedbackContent(), Charset.forName("utf-8"))); // TODO - // charset + requestBuilder.setFeedbackDocument(IOUtils.toInputStream(getFeedbackContent(), + Charset.forName(INPUTSTREAM_CHARSET))); // Further params if (getSize() != null) - requestBuilder.setDesiredSize(getSize()); + requestBuilder.setDesiredSize(getSize().intValue()); if (isForceDownload() != null) - requestBuilder.setForceDownload(isForceDownload()); + requestBuilder.setForceDownload(isForceDownload().booleanValue()); if (isUseCache() != null) - requestBuilder.setUseCache(isUseCache()); + requestBuilder.setUseCache(isUseCache().booleanValue()); + + log.debug("Requesting label with {}", requestBuilder); InputStream svg = requestBuilder.getSVG(); String svgString = IOUtils.toString(svg); @@ -220,7 +237,7 @@ else if (getFeedbackContent() != null && !getFeedbackContent().isEmpty()) /** * Writes a script call for the client to request the GeoLabel in an upcoming call (PPR) - * + * * @param context * @throws IOException */ @@ -233,7 +250,7 @@ private void writeClientLabel(FacesContext context) throws IOException { writer.startElement("div", this); Resource createResource = context.getApplication().getResourceHandler().createResource("spinner.gif"); - int size = getSize() == null ? 16 : getSize(); + int size = getSize() == null ? 16 : getSize().intValue(); writer.writeAttribute("style", "width:" + size + "px;" + "height:" + size + "px;" + "background-image: url('" + createResource.getRequestPath() + "');" + "background-repeat:no-repeat;" @@ -254,7 +271,7 @@ private void writeClientLabel(FacesContext context) throws IOException { /** * Marks a specific GEO label service for the current request as broken. Important to not send any further * GeoLabel requests in case of an error. - * + * * @param context */ private static void setServiceFailed(String endpoint, FacesContext context) { @@ -267,7 +284,7 @@ private static void setServiceFailed(String endpoint, FacesContext context) { /** * Check whether a specific GEO label service is known to be broken for the current request - * + * * @param context * @return */ diff --git a/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponentTag.java b/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponentTag.java index 0859a67..67b6894 100644 --- a/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponentTag.java +++ b/jsf/src/main/java/org/n52/geolabel/component/GeoLabelComponentTag.java @@ -48,41 +48,32 @@ public String getRendererType() { @Override protected void setProperties(UIComponent component) { super.setProperties(component); - if (metadataUrl != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.metadataUrl.name(), metadataUrl); - } + if (this.metadataUrl != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.metadataUrl.name(), this.metadataUrl); - if (feedbackUrl != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.feedbackUrl.name(), feedbackUrl); - } + if (this.feedbackUrl != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.feedbackUrl.name(), this.feedbackUrl); - if (metadataContent != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.metadataContent.name(), metadataContent); - } + if (this.metadataContent != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.metadataContent.name(), this.metadataContent); - if (feedbackContent != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.feedbackContent.name(), feedbackContent); - } + if (this.feedbackContent != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.feedbackContent.name(), this.feedbackContent); - if (size != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.size.name(), size); - } + if (this.size != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.size.name(), this.size); - if (async != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.async.name(), async); - } + if (this.async != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.async.name(), this.async); - if (forceDownload != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.forceDownload.name(), forceDownload); - } + if (this.forceDownload != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.forceDownload.name(), this.forceDownload); - if (useCache != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.useCache.name(), useCache); - } + if (this.useCache != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.useCache.name(), this.useCache); - if (serviceUrl != null) { - component.setValueExpression(GeoLabelComponent.PropertyKeys.serviceUrl.name(), serviceUrl); - } + if (this.serviceUrl != null) + component.setValueExpression(GeoLabelComponent.PropertyKeys.serviceUrl.name(), this.serviceUrl); } diff --git a/server/pom.xml b/server/pom.xml index 390f1e6..21e1dfa 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -129,6 +129,11 @@ commons ${project.parent.version} + + ${project.parent.groupId} + client + ${project.parent.version} + org.slf4j @@ -231,12 +236,6 @@ ${jersey.version} - - ${project.parent.groupId} - client - ${project.parent.version} - - commons-io commons-io @@ -255,7 +254,6 @@ - junit junit @@ -270,6 +268,13 @@ test + + org.hamcrest + hamcrest-all + 1.3 + test + + diff --git a/server/src/main/java/org/n52/geolabel/server/beans/LandingPageBean.java b/server/src/main/java/org/n52/geolabel/server/beans/LandingPageBean.java index fc63301..bea9bf1 100644 --- a/server/src/main/java/org/n52/geolabel/server/beans/LandingPageBean.java +++ b/server/src/main/java/org/n52/geolabel/server/beans/LandingPageBean.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.geolabel.server.beans; import java.net.MalformedURLException; @@ -30,85 +31,91 @@ @RequestScoped public class LandingPageBean { - public static class Example { - String metadata; - String feedback; - String title; + public static class Example { + String metadata; + String feedback; + String title; - public Example(String title, String metadata) { - this.title = title; - this.metadata = metadata; - } + public Example(String title, String metadata) { + this.title = title; + this.metadata = metadata; + } - public Example(String title, String metadata, String feedback) { - this.title = title; - this.metadata = metadata; - this.feedback = feedback; - } + public Example(String title, String metadata, String feedback) { + this.title = title; + this.metadata = metadata; + this.feedback = feedback; + } - public String getFeedbackUrl() { + public String getFeedbackUrl() { return this.feedback; - } + } - public String getMetadataUrl() { + public String getMetadataUrl() { return this.metadata; - } + } - public String getTitle() { + public String getTitle() { return this.title; - } - } - - @org.hibernate.validator.constraints.URL - private String metadataUrl = "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_v10.xml"; - @org.hibernate.validator.constraints.URL - private String feedbackUrl = ""; + } + } - private List examplesList = new ArrayList(); + @org.hibernate.validator.constraints.URL + private String metadataUrl = "http://schemas.geoviqua.org/GVQ/4.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_GEOlabel.xml"; + @org.hibernate.validator.constraints.URL + private String feedbackUrl = "http://schemas.geoviqua.org/GVQ/4.0/example_documents/UQMs/DigitalClimaticAtlas_UserFeedback_v1.xml"; - public LandingPageBean() { - this.examplesList.add(new Example("Climate Atlas", - "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/PQMs/DigitalClimaticAtlas_mt_an_v10.xml")); + private List examplesList = new ArrayList<>(); + public LandingPageBean() { + this.examplesList.add(new Example("GLC 2000", + "http://schemas.geoviqua.org/GVQ/4.0/example_documents/PQMs/GLC_2000_GVQ_raw.xml")); this.examplesList.add(new Example("Feedback Use Case", null, - "http://schemas.geoviqua.org/GVQ/3.1.0/example_documents/FeedbackUseCase_7_7_metadata.xml")); - } + "http://schemas.geoviqua.org/GVQ/4.0/example_documents/FeedbackUseCase_7_7_metadata.xml")); + this.examplesList.add(new Example("Rice Fields User Feedback", + null, + "http://schemas.geoviqua.org/GVQ/4.0/example_documents/UQMs/RiceFields_UserFeedback_v3.xml")); + this.examplesList.add(new Example("Combinded Producer and User Data", + "http://schemas.geoviqua.org/GVQ/4.0/example_documents/PQM_UQM_combined/DigitalClimaticAtlas_mt_an_v10.xml", + "http://schemas.geoviqua.org/GVQ/4.0/example_documents/PQM_UQM_combined/DigitalClimaticAtlas_mt_an_v10.xml")); + } - public String getMetadataUrl() { + public String getMetadataUrl() { return this.metadataUrl; - } + } - public String getFeedbackUrl() { + public String getFeedbackUrl() { return this.feedbackUrl; - } + } - public void setMetadataUrl(String metadataUrl) { - this.metadataUrl = metadataUrl; - } + public void setMetadataUrl(String metadataUrl) { + this.metadataUrl = metadataUrl; + } - public void setFeedbackUrl(String feedbackUrl) { - this.feedbackUrl = feedbackUrl; - } + public void setFeedbackUrl(String feedbackUrl) { + this.feedbackUrl = feedbackUrl; + } - public List getExamplesList() { + public List getExamplesList() { return this.examplesList; - } - - /** - * Returns the absolute GEO label service API endpoint of this webapp - * instance. For example required by JSF components as these work - * Independent of this service. - * - * @return - * @throws MalformedURLException - */ - public String getServiceEndpoint() throws MalformedURLException { - ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); - HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); - URL requesturl = new URL(request.getRequestURL().toString()); - URL serviceUrl = new URL(requesturl.getProtocol(), requesturl.getHost(), requesturl.getPort(), - request.getContextPath() + "/api/v1/svg/"); - return serviceUrl.toString(); - } + } + + /** + * Returns the absolute GEO label service API endpoint of this webapp instance. For example required by + * JSF components as these work Independent of this service. + * + * @return + * @throws MalformedURLException + */ + public String getServiceEndpoint() throws MalformedURLException { + ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); + HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); + URL requesturl = new URL(request.getRequestURL().toString()); + URL serviceUrl = new URL(requesturl.getProtocol(), + requesturl.getHost(), + requesturl.getPort(), + request.getContextPath() + "/api/v1/svg/"); + return serviceUrl.toString(); + } } diff --git a/server/src/main/java/org/n52/geolabel/server/config/GeoLabelConfig.java b/server/src/main/java/org/n52/geolabel/server/config/GeoLabelConfig.java index 5abb1a8..4dbb036 100644 --- a/server/src/main/java/org/n52/geolabel/server/config/GeoLabelConfig.java +++ b/server/src/main/java/org/n52/geolabel/server/config/GeoLabelConfig.java @@ -24,8 +24,8 @@ import org.n52.geolabel.server.config.ExceptionMappers.IOExceptionMapper; import org.n52.geolabel.server.config.ExceptionMappers.ParamExceptionMapper; import org.n52.geolabel.server.mapping.MetadataTransformer; -import org.n52.geolabel.server.resources.CacheResourceV1; import org.n52.geolabel.server.resources.LMLResourceV1; +import org.n52.geolabel.server.resources.TransformationsResourceV1; import org.n52.geolabel.server.resources.SVGResourceV1; import org.n52.geolabel.server.resources.StaticLabelResourceV1; @@ -40,6 +40,7 @@ public class GeoLabelConfig extends GuiceServletContextListener { public static int CONNECT_TIMEOUT = 10000; + public static int READ_TIMEOUT = 20000; @Override @@ -50,15 +51,17 @@ protected void configureServlets() { bind(LMLResourceV1.class); bind(SVGResourceV1.class); bind(StaticLabelResourceV1.class); - bind(CacheResourceV1.class); + bind(TransformationsResourceV1.class); bind(ParamExceptionMapper.class); bind(IOExceptionMapper.class); bind(ContainerExceptionMapper.class); + bind(TransformationDescriptionResources.class); + bind(MetadataTransformer.class); - Map jerseyInitPrams = new HashMap(); + Map jerseyInitPrams = new HashMap<>(); jerseyInitPrams.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, "true"); // Simple CORS filter diff --git a/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionLoader.java b/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionLoader.java new file mode 100644 index 0000000..344277b --- /dev/null +++ b/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionLoader.java @@ -0,0 +1,240 @@ +/** + * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH + * + * 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.n52.geolabel.server.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.xml.xpath.XPathExpressionException; + +import org.codehaus.jackson.map.ObjectMapper; +import org.n52.geolabel.server.config.TransformationDescriptionResources.Source; +import org.n52.geolabel.server.mapping.description.TransformationDescription; +import org.n52.geolabel.server.mapping.description.TransformationDescription.TransformationDescriptionWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.io.ByteStreams; +import com.google.common.io.Files; +import com.google.common.io.Resources; + +@Singleton +public class TransformationDescriptionLoader { + + protected static final Logger log = LoggerFactory.getLogger(TransformationDescriptionLoader.class); + + private TransformationDescriptionResources resources; + + private static Set descriptions; + + private static Map transformationDescriptionUsedSource = new HashMap<>(); + + @Inject + public TransformationDescriptionLoader(TransformationDescriptionResources resources) { + this.resources = resources; + } + + private TransformationDescription readTransformationDescription(InputStream input) throws IOException { + /** + * using JSONJAXB + */ + // try { + // JSONJAXBContext context = new JSONJAXBContext(JSONConfiguration.mappedJettison().build(), + // LabelTransformationDescription.class); + // // JSONConfiguration jsonConfiguration = context.getJSONConfiguration(); + // JSONUnmarshaller unmarshaller = context.createJSONUnmarshaller(); + // + // Object obj = unmarshaller.unmarshalFromJSON(input, LabelTransformationDescription.class); + // LabelTransformationDescription transformationDescription = (LabelTransformationDescription) obj; + // + // add(transformationDescription); + // } + // catch (JAXBException e) { + // throw new IOException("Error while parsing transformation description stream", e); + // } + + /** + * using Jackson + */ + ObjectMapper m = new ObjectMapper(); + TransformationDescriptionWrapper wrapper = m.readValue(input, TransformationDescriptionWrapper.class); + + return wrapper.transformationDescription; + } + + /** + * Reads {@link LabelTransformationDescription} from passed XML {@link File} . + * + */ + private TransformationDescription readTransformationDescription(File descriptionFile) throws FileNotFoundException, + IOException { + return readTransformationDescription(new FileInputStream(descriptionFile)); + } + + /** + * Reads {@link TransformationDescription}s from resources based on all files in a specified folder. + * + */ + @Deprecated + public void loadLocal(String folder) throws IOException { + Enumeration descriptionResources = getClass().getClassLoader().getResources(folder); + + while (descriptionResources.hasMoreElements()) { + URL element = descriptionResources.nextElement(); + log.debug("Loading local mapping: {}", element); + + try { + URI descriptionResourceURI = element.toURI(); + File descriptionResourceFile = new File(descriptionResourceURI); + for (File descriptionFile : descriptionResourceFile.listFiles()) + try { + log.debug("Loading transformation description: {}", descriptionFile); + // String fileExtension = Files.getFileExtension(descriptionFile.getName()); + readTransformationDescription(descriptionFile); + } + catch (IOException e) { + log.error("Could not read transformation description " + descriptionFile.getName() + ".", e); + } + } + catch (URISyntaxException e) { + log.error("Could not read transformation description.", e); + } + } + } + + public Set load() { + if (descriptions == null) + descriptions = internalLoad(this.resources); + + return descriptions; + } + + private Set internalLoad(final TransformationDescriptionResources res) { + log.info("Loading resources from {}", res); + + final Set ds = new HashSet<>(); + + // load from server with fallback + Set> entrySet = this.resources.getResources().entrySet(); + for (Entry entry : entrySet) { + log.debug("Loading transformation description from URL {} with fallback {}", + entry.getKey(), + entry.getValue()); + + TransformationDescription td = null; + try { + File temp = File.createTempFile("geolabel_transformationDescription_", ".json"); + ByteStreams.copy(Resources.newInputStreamSupplier(entry.getKey()), Files.newOutputStreamSupplier(temp)); + log.debug("Saved transformation description from {} to {}", entry.getKey(), temp); + + td = readTransformationDescription(temp); + log.debug("Loaded transformation description from {} ", entry.getKey()); + setUsedSource(entry.getKey(), Source.ONLINE); + } + catch (Exception e) { + log.warn("There was a problem loading transformation description from {}: {} : {}", + entry.getValue(), + e.getClass(), + e.getMessage()); + } + + if (td == null) { + log.debug("Using fallback {} for URL {}", entry.getValue(), entry.getKey()); + InputStream stream = getClass().getResourceAsStream(entry.getValue()); + + try { + td = readTransformationDescription(stream); + log.debug("Loaded transformation description from {} ", entry.getValue()); + setUsedSource(entry.getKey(), Source.FALLBACK); + } + catch (IOException e) { + log.error("There was a problem loading transformation description from {}: {} : {}", + entry.getValue(), + e.getClass(), + e.getMessage()); + } + } + + if (td != null) { + ds.add(td); + log.debug("Read transformation description: {}", td); + } + else + log.error("Could load neither from URL nor fallback!"); + } + + // init desriptions + for (TransformationDescription td : ds) + try { + td.initXPaths(); + log.debug("Added description: {}", td); + } + catch (XPathExpressionException e) { + log.error("Error while compiling XPaths in tranformation description {}", td, e); + } + + log.debug("Loaded {} transformation descriptions with the names {}", Integer.valueOf(ds.size()), getNames(ds)); + + return ds; + } + + private String getNames(Set ds) { + StringBuilder sb = new StringBuilder(); + + for (TransformationDescription td : ds) { + sb.append(td.name); + sb.append(" "); + } + return sb.toString(); + } + + public void setUsedSource(URL url, Source online) { + transformationDescriptionUsedSource.put(url, online); + } + + public Map getUsedSources() { + return transformationDescriptionUsedSource; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TransformationDescriptionLoader ["); + if (this.resources != null) { + builder.append("resources="); + builder.append(this.resources); + } + builder.append("]"); + return builder.toString(); + } + + +} diff --git a/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionResources.java b/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionResources.java new file mode 100644 index 0000000..f10cdb1 --- /dev/null +++ b/server/src/main/java/org/n52/geolabel/server/config/TransformationDescriptionResources.java @@ -0,0 +1,75 @@ +/** + * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH + * + * 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.n52.geolabel.server.config; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TransformationDescriptionResources { + + protected static final Logger log = LoggerFactory.getLogger(TransformationDescriptionResources.class); + + private static final String TRANSFORMATIONS_RESOURCE = "transformations"; + + public static enum Source { + ONLINE, FALLBACK, NA; + } + + /** + * map between normative URL and fallback + */ + private Map resources = new HashMap<>(); + + public TransformationDescriptionResources() { + try { + this.resources.put(new URL("http://geoviqua.github.io/geolabel/mappings/transformer.json"), + "/" + TRANSFORMATIONS_RESOURCE + "/transformer.json"); + } + catch (MalformedURLException e) { + log.error("Could not create transformation description resources.", e); + } + } + + public TransformationDescriptionResources(Map resources) { + this.resources.putAll(resources); + } + + public Map getResources() { + return this.resources; + } + + public void setResources(Map transformationDescriptionResources) { + this.resources = transformationDescriptionResources; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TransformationDescriptionResources ["); + if (this.resources != null) { + builder.append("resources="); + builder.append(this.resources); + } + builder.append("]"); + return builder.toString(); + } + +} diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformer.java b/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformer.java index 9b99341..33f2efb 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformer.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformer.java @@ -16,37 +16,27 @@ package org.n52.geolabel.server.mapping; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; import java.util.Date; -import java.util.Enumeration; -import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Singleton; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPathExpressionException; import org.n52.geolabel.commons.Label; import org.n52.geolabel.server.config.GeoLabelConfig; -import org.n52.geolabel.server.mapping.description.LabelTransformationDescription; +import org.n52.geolabel.server.config.TransformationDescriptionLoader; +import org.n52.geolabel.server.config.TransformationDescriptionResources; +import org.n52.geolabel.server.mapping.description.TransformationDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -62,8 +52,7 @@ @Singleton public class MetadataTransformer { - private static final String TRANSFORMATIONS_RESOURCE = "transformations"; - final static Logger log = LoggerFactory.getLogger(MetadataTransformer.class); + protected static final Logger log = LoggerFactory.getLogger(MetadataTransformer.class); public static int CACHE_MAX_LABELS = 100; // TODO make available as property public static int CACHE_MAX_HOURS = 48;// TODO make available as property @@ -133,14 +122,68 @@ public int hashCode() { @Override public String toString() { StringBuilder builder = new StringBuilder(); - builder.append("metadata url: "); - if (this.metadataUrl != null) + builder.append("LabelUrlKey ["); + if (this.metadataUrl != null) { + builder.append("metadataUrl="); builder.append(this.metadataUrl); - builder.append("feedback url: "); - if (this.feedbackUrl != null) + builder.append(", "); + } + if (this.feedbackUrl != null) { + builder.append("feedbackUrl="); builder.append(this.feedbackUrl); + builder.append(", "); + } + if (this.cacheWriteTime != null) { + builder.append("cacheWriteTime="); + builder.append(this.cacheWriteTime); + } + builder.append("]"); return builder.toString(); } + + } + + public class RemoteTransformationDescription { + + protected URL online; + + protected String fallbackFile; + + protected RemoteTransformationDescription description; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ( (this.fallbackFile == null) ? 0 : this.fallbackFile.hashCode()); + result = prime * result + ( (this.online == null) ? 0 : this.online.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RemoteTransformationDescription other = (RemoteTransformationDescription) obj; + if (this.fallbackFile == null) { + if (other.fallbackFile != null) + return false; + } + else if ( !this.fallbackFile.equals(other.fallbackFile)) + return false; + if (this.online == null) { + if (other.online != null) + return false; + } + else if ( !this.online.equals(other.online)) + return false; + return true; + } + } private LoadingCache labelUrlCache = CacheBuilder.newBuilder().maximumSize(CACHE_MAX_LABELS).expireAfterWrite(CACHE_MAX_HOURS, @@ -153,87 +196,22 @@ public Label load(LabelUrlKey key) throws Exception { Label label = new Label(); if (key.feedbackUrl != null) - updateGeoLabel(key.feedbackUrl, label); + label = updateGeoLabel(key.feedbackUrl, label); if (key.metadataUrl != null) - updateGeoLabel(key.metadataUrl, label); + label = updateGeoLabel(key.metadataUrl, label); return label; } }); - @Inject - MetadataTransformer() { - - } - - private List transformationDescriptions; - - public List getTransformationDescriptions() { - if (this.transformationDescriptions == null) - this.transformationDescriptions = new ArrayList(); - return this.transformationDescriptions; - } - - /** - * Reads {@link LabelTransformationDescription} from passed XML stream. - * - * @param input - * @throws IOException - */ - public void readTransformationDescription(InputStream input) throws IOException { - try { - Unmarshaller unmarshaller = JAXBContext.newInstance(LabelTransformationDescription.class).createUnmarshaller(); - LabelTransformationDescription transformationDescription = (LabelTransformationDescription) unmarshaller.unmarshal(input); - - transformationDescription.initXPaths(); - getTransformationDescriptions().add(transformationDescription); - } - catch (JAXBException e) { - throw new IOException("Error while parsing transformation description stream", e); - } - catch (XPathExpressionException e) { - throw new IOException("Error while compiling XPaths in tranformation description", e); - } - finally { - input.close(); - } - - } + private Set transformationDescriptions; - /** - * Reads {@link LabelTransformationDescription} from passed XML {@link File} . - * - * @param descriptionFile - * @throws FileNotFoundException - * @throws IOException - */ - private void readTransformationDescription(File descriptionFile) throws FileNotFoundException, IOException { - readTransformationDescription(new FileInputStream(descriptionFile)); - } + private TransformationDescriptionLoader loader; - /** - * Reads {@link LabelTransformationDescription}s from resources. - * - * @throws IOException - */ - private void readTransformationDescriptions() throws IOException { - Enumeration descriptionResources = getClass().getClassLoader().getResources(TRANSFORMATIONS_RESOURCE); - while (descriptionResources.hasMoreElements()) - try { - URI descriptionResourceURI = descriptionResources.nextElement().toURI(); - File descriptionResourceFile = new File(descriptionResourceURI); - for (File descriptionFile : descriptionResourceFile.listFiles()) - try { - log.debug("Loading transformation description: {}", descriptionFile); - readTransformationDescription(descriptionFile); - } - catch (IOException e) { - log.error("Could not read transformation description " + descriptionFile.getName() + ".", e); - } - } - catch (URISyntaxException e) { - log.error("Could not read transformation description.", e); - } + @Inject + public MetadataTransformer(TransformationDescriptionResources resources) { + this.loader = new TransformationDescriptionLoader(resources); + log.debug("NEW {}", this); } /** @@ -264,13 +242,16 @@ public Label updateGeoLabel(InputStream xmlInputStream, Label label) throws IOEx throw new IOException("Could not parse supplied metadata xml", e); } - List tds = getTransformationDescriptions(); - for (LabelTransformationDescription transformer : tds) + for (TransformationDescription transformer : this.transformationDescriptions) transformer.updateGeoLabel(label, doc); return label; } + private void readTransformationDescriptions() { + this.transformationDescriptions = this.loader.load(); + } + /** * See {@link MetadataTransformer#updateGeoLabel(InputStream, Label)}.Loads metadata stream from * {@link URL}. @@ -281,10 +262,19 @@ public Label updateGeoLabel(InputStream xmlInputStream, Label label) throws IOEx * @throws IOException */ public Label updateGeoLabel(URL metadataUrl, Label label) throws IOException { - URLConnection con = metadataUrl.openConnection(); - con.setConnectTimeout(GeoLabelConfig.CONNECT_TIMEOUT); - con.setReadTimeout(GeoLabelConfig.READ_TIMEOUT); - return updateGeoLabel(con.getInputStream(), label); + try { + URLConnection con = metadataUrl.openConnection(); + con.setConnectTimeout(GeoLabelConfig.CONNECT_TIMEOUT); + con.setReadTimeout(GeoLabelConfig.READ_TIMEOUT); + InputStream is = con.getInputStream(); + + return updateGeoLabel(is, label); + } + catch (Exception e) { + log.debug("Could not update label with URL {}", metadataUrl, e); + label.setError(e); + return label; + } } /** @@ -320,8 +310,11 @@ public Label createGeoLabel(URL metadataUrl) throws IOException { * @throws IOException */ public Label getLabel(URL metadataURL, URL feedbackURL) throws IOException { + log.debug("Creating label for metadata {} and feedback {}", metadataURL, feedbackURL); + try { - return this.labelUrlCache.get(new LabelUrlKey(metadataURL, feedbackURL)); + LabelUrlKey labelUrlKey = new LabelUrlKey(metadataURL, feedbackURL); + return this.labelUrlCache.get(labelUrlKey); } catch (ExecutionException e) { throw new IOException(e.getCause()); @@ -331,4 +324,5 @@ public Label getLabel(URL metadataURL, URL feedbackURL) throws IOException { public Set getCacheContent() { return this.labelUrlCache.asMap().keySet(); } + } diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformerProvider.java b/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformerProvider.java index ffdaf19..8720846 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformerProvider.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/MetadataTransformerProvider.java @@ -15,13 +15,23 @@ */ package org.n52.geolabel.server.mapping; +import javax.inject.Inject; import javax.inject.Provider; +import org.n52.geolabel.server.config.TransformationDescriptionResources; + public class MetadataTransformerProvider implements Provider { + private TransformationDescriptionResources resources; + + @Inject + public MetadataTransformerProvider(TransformationDescriptionResources resources) { + this.resources = resources; + } + @Override public MetadataTransformer get() { - return new MetadataTransformer(); + return new MetadataTransformer(this.resources); } } diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/CitationsFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/CitationsFacetDescription.java index b2e7c36..233c0e3 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/CitationsFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/CitationsFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -28,10 +26,9 @@ /** * Checks availability of citations information */ -@XmlRootElement(name = "citations") public class CitationsFacetDescription extends FacetTransformationDescription { - @XmlElement - private String citationsCountPath; + + private String citationsCountPath; private XPathExpression citationsCountExpression; @@ -60,4 +57,12 @@ public CitationsFacet getAffectedFacet(Label label) { return label.getCitationsFacet(); } + public String getCitationsCountPath() { + return this.citationsCountPath; + } + + public void setCitationsCountPath(String citationsCountPath) { + this.citationsCountPath = citationsCountPath; + } + } \ No newline at end of file diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/FacetTransformationDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/FacetTransformationDescription.java index 67adb28..58ab01c 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/FacetTransformationDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/FacetTransformationDescription.java @@ -18,35 +18,128 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; +import org.codehaus.jackson.annotate.JsonSubTypes; +import org.codehaus.jackson.annotate.JsonTypeInfo; +import org.codehaus.jackson.map.annotate.JsonRootName; import org.n52.geolabel.commons.Label; import org.n52.geolabel.commons.LabelFacet; import org.n52.geolabel.commons.LabelFacet.Availability; +import org.n52.geolabel.server.mapping.description.FeedbackFacetDescription.ExpertFeedbackFacetDescription; +import org.n52.geolabel.server.mapping.description.FeedbackFacetDescription.UserFeedbackFacetDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -@XmlSeeAlso({ProducerProfileFacetDescription.class, - LineageFacetDescription.class, - ProducerCommentsFacetDescription.class, - StandardsComplianceFacetDescription.class, - QualityInformationFacetDescription.class, - FeedbackFacetDescription.class, - CitationsFacetDescription.class}) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) +@JsonSubTypes({@JsonSubTypes.Type(value = ProducerProfileFacetDescription.class, name = "producerProfile"), + @JsonSubTypes.Type(value = LineageFacetDescription.class, name = "lineage"), + @JsonSubTypes.Type(value = ExpertFeedbackFacetDescription.class, name = "expertReview"), + @JsonSubTypes.Type(value = UserFeedbackFacetDescription.class, name = "userFeedback"), + @JsonSubTypes.Type(value = ProducerCommentsFacetDescription.class, name = "producerComments"), + @JsonSubTypes.Type(value = StandardsComplianceFacetDescription.class, name = "standardsCompliance"), + @JsonSubTypes.Type(value = QualityInformationFacetDescription.class, name = "qualityInformation"), + @JsonSubTypes.Type(value = CitationsFacetDescription.class, name = "citations")}) public abstract class FacetTransformationDescription { private static Logger log = LoggerFactory.getLogger(FacetTransformationDescription.class); + @JsonRootName("hoverover") + public static class HoveroverWrapper { + public HoveroverInformation hoverover; + } + + public static class HoveroverInformation { + + private String facetName; + + private String template; + + private Map text; + + public HoveroverInformation() { + // + } + + public String getFacetName() { + return this.facetName; + } + + public void setFacetName(String factName) { + this.facetName = factName; + } + + public String getTemplate() { + return this.template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public Map getText() { + return this.text; + } + + public void setText(Map text) { + this.text = text; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("HoveroverInformation ["); + if (this.facetName != null) { + builder.append("facetName="); + builder.append(this.facetName); + builder.append(", "); + } + if (this.template != null) { + builder.append("template="); + builder.append(this.template); + builder.append(", "); + } + if (this.text != null) { + builder.append("text="); + builder.append(this.text); + builder.append(", "); + } + builder.append("]"); + return builder.toString(); + } + + } + + @JsonRootName("drilldown") + public static class DrilldownWrapper { + public Drilldown url; + } + + public static class Drilldown { + public String url; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Drilldown ["); + if (this.url != null) { + builder.append("url="); + builder.append(this.url); + } + builder.append("]"); + return builder.toString(); + } + } + protected interface ExpressionResultFunction { boolean eval(String value); } @@ -91,11 +184,14 @@ else if (evaluationResult instanceof Collection< ? >) { + evaluationResult.getClass().getSimpleName()); } - @XmlElement private String availabilityPath; private XPathExpression availabilityExpression; + protected HoveroverInformation hoverover; + + protected Drilldown drilldown; + public abstract T getAffectedFacet(Label label); public void initXPaths(XPath xPath) throws XPathExpressionException { @@ -104,8 +200,12 @@ public void initXPaths(XPath xPath) throws XPathExpressionException { } public T updateFacet(final T facet, Document metadataXml) throws XPathExpressionException { - if (this.availabilityExpression == null) + if (this.availabilityExpression == null) { + log.warn("Availability expression is null, returning faced unchanged: {} for document {}", + facet, + metadataXml); return facet; + } final AtomicBoolean hasTextNodes = new AtomicBoolean(false); log.debug("Checking availability of facet {} using {} in document {}", @@ -139,9 +239,35 @@ public Label updateLabel(Label label, Document metadataXml) { return label; } catch (XPathExpressionException e) { - throw new RuntimeException("Error while executing XPath expression", e); + log.error("Error while executing XPath expression for facet {} in label {}", getClass().getName(), label); + throw new RuntimeException(String.format("Error while executing XPath expression for facet %s in label %s", + getClass().getName(), + label), e); } + } + + public String getAvailabilityPath() { + return this.availabilityPath; + } + + public void setAvailabilityPath(String availabilityPath) { + this.availabilityPath = availabilityPath; + } + + public HoveroverInformation getHoverover() { + return this.hoverover; + } + + public void setHoverover(HoveroverInformation hoverover) { + this.hoverover = hoverover; + } + public Drilldown getDrilldown() { + return this.drilldown; + } + + public void setDrilldown(Drilldown drilldown) { + this.drilldown = drilldown; } @Override @@ -156,6 +282,16 @@ public String toString() { if (this.availabilityExpression != null) { builder.append("availabilityExpression="); builder.append(this.availabilityExpression); + builder.append(", "); + } + if (this.hoverover != null) { + builder.append("hoverover="); + builder.append(this.hoverover); + builder.append(", "); + } + if (this.drilldown != null) { + builder.append("drilldown="); + builder.append(this.drilldown); } builder.append("]"); return builder.toString(); diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/FeedbackFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/FeedbackFacetDescription.java index 9572380..0a859ea 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/FeedbackFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/FeedbackFacetDescription.java @@ -13,11 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -29,69 +27,62 @@ /** * Base class for feedback availability */ -@XmlSeeAlso({ FeedbackFacetDescription.UserFeedbackFacetDescription.class, - FeedbackFacetDescription.ExpertFeedbackFacetDescription.class }) public abstract class FeedbackFacetDescription extends FacetTransformationDescription { - @XmlElement - private String feedbacksCountPath; - @XmlElement - private String ratingsPath; + private String feedbacksCountPath; + + private String ratingsPath; - private XPathExpression ratingsExpression; - private XPathExpression feedbacksCountExpression; + private XPathExpression ratingsExpression; + private XPathExpression feedbacksCountExpression; - @Override - public void initXPaths(XPath xPath) throws XPathExpressionException { + @Override + public void initXPaths(XPath xPath) throws XPathExpressionException { if (this.ratingsPath != null) this.ratingsExpression = xPath.compile(this.ratingsPath); if (this.feedbacksCountPath != null) this.feedbacksCountExpression = xPath.compile(this.feedbacksCountPath); - super.initXPaths(xPath); - } + super.initXPaths(xPath); + } - @Override - public FeedbackFacet updateFacet(final FeedbackFacet facet, Document metadataXml) throws XPathExpressionException { + @Override + public FeedbackFacet updateFacet(final FeedbackFacet facet, Document metadataXml) throws XPathExpressionException { visitExpressionResultStrings(this.ratingsExpression, metadataXml, new ExpressionResultFunction() { - @Override - public boolean eval(String value) { - facet.addRating(Double.parseDouble(value)); - return true; - } - }); + @Override + public boolean eval(String value) { + facet.addRating(Double.parseDouble(value)); + return true; + } + }); visitExpressionResultStrings(this.feedbacksCountExpression, metadataXml, new ExpressionResultFunction() { - @Override - public boolean eval(String value) { - facet.addFeedbacks(Integer.parseInt(value)); - return true; - } - }); + @Override + public boolean eval(String value) { + facet.addFeedbacks(Integer.parseInt(value)); + return true; + } + }); - return super.updateFacet(facet, metadataXml); - } + return super.updateFacet(facet, metadataXml); + } - /** - * * Checks availability of user feedback - * - */ - @XmlRootElement(name = "userFeedback") - public static class UserFeedbackFacetDescription extends FeedbackFacetDescription { - @Override - public FeedbackFacet getAffectedFacet(Label label) { - return label.getUserFeedbackFacet(); - } - } + /** + * Checks availability of user feedback + */ + public static class UserFeedbackFacetDescription extends FeedbackFacetDescription { + @Override + public FeedbackFacet getAffectedFacet(Label label) { + return label.getUserFeedbackFacet(); + } + } - /** - * @ Checks availability of expert reviews information - * - */ - @XmlRootElement(name = "expertFeedback") - public static class ExpertFeedbackFacetDescription extends FeedbackFacetDescription { - @Override - public FeedbackFacet getAffectedFacet(Label label) { - return label.getExpertFeedbackFacet(); - } - } + /** + * Checks availability of expert reviews information + */ + public static class ExpertFeedbackFacetDescription extends FeedbackFacetDescription { + @Override + public FeedbackFacet getAffectedFacet(Label label) { + return label.getExpertFeedbackFacet(); + } + } } \ No newline at end of file diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescription.java deleted file mode 100644 index fcf1a3e..0000000 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescription.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH - * - * 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.n52.geolabel.server.mapping.description; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementRef; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.n52.geolabel.commons.Label; -import org.w3c.dom.Document; - -@XmlRootElement(name = "transformationDescription") -public class LabelTransformationDescription { - - static class NamespaceMapping { - @XmlAttribute - public String prefix; - @XmlAttribute - public String namespace; - - NamespaceMapping() { - } - - public NamespaceMapping(String prefix, String namespace) { - this.prefix = prefix; - this.namespace = namespace; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("NamespaceMapping ["); - if (this.prefix != null) { - builder.append("prefix="); - builder.append(this.prefix); - builder.append(", "); - } - if (this.namespace != null) { - builder.append("namespace="); - builder.append(this.namespace); - } - builder.append("]"); - return builder.toString(); - } - - } - - @XmlElementWrapper - @XmlElement(name = "mapping") - NamespaceMapping[] namespaceMappings; - - @XmlElementWrapper - @XmlElementRef - FacetTransformationDescription[] facetDescriptions; - - public void initXPaths() throws XPathExpressionException { - XPathFactory factory = XPathFactory.newInstance(); - - XPath xPath = factory.newXPath(); - - final Map namespaceMap = new HashMap(); - for (NamespaceMapping mapping : this.namespaceMappings) - namespaceMap.put(mapping.prefix, mapping.namespace); - - xPath.setNamespaceContext(new NamespaceContext() { - - @SuppressWarnings("rawtypes") - @Override - public Iterator getPrefixes(String namespaceURI) { - return null; - } - - @Override - public String getPrefix(String namespaceURI) { - return null; - } - - @Override - public String getNamespaceURI(String prefix) { - return namespaceMap.get(prefix); - } - }); - - for (FacetTransformationDescription< ? > facetDescription : this.facetDescriptions) - facetDescription.initXPaths(xPath); - } - - public void updateGeoLabel(Label label, Document metadataXml) { - for (FacetTransformationDescription< ? > facetDescription : this.facetDescriptions) - facetDescription.updateLabel(label, metadataXml); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("LabelTransformationDescription ["); - if (this.namespaceMappings != null) { - builder.append("namespaceMappings="); - builder.append(Arrays.toString(this.namespaceMappings)); - builder.append(", "); - } - if (this.facetDescriptions != null) { - builder.append("facetDescriptions="); - builder.append(Arrays.toString(this.facetDescriptions)); - } - builder.append("]"); - return builder.toString(); - } - -} diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/LineageFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/LineageFacetDescription.java index 3e3586f..a834763 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/LineageFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/LineageFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; @@ -30,10 +28,9 @@ * Checks availability of lineage information * */ -@XmlRootElement(name = "lineage") public class LineageFacetDescription extends FacetTransformationDescription { - @XmlElement - private String processStepCountPath; + + private String processStepCountPath; private XPathExpression processStepCountExpression; diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerCommentsFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerCommentsFacetDescription.java index a980e7e..7a74b0f 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerCommentsFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerCommentsFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -29,10 +27,8 @@ * Checks availability of producer comments information * */ -@XmlRootElement(name = "producerComments") public class ProducerCommentsFacetDescription extends FacetTransformationDescription { - @XmlElement private String producerCommentsPath; private XPathExpression producerCommentsExpression; diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerProfileFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerProfileFacetDescription.java index 83a5d3e..92721ce 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerProfileFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/ProducerProfileFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -28,16 +26,17 @@ /** * Checks availability of producer profile information */ -@XmlRootElement(name = "producerProfile") public class ProducerProfileFacetDescription extends FacetTransformationDescription { - @XmlElement - private String organizationNamePath; + + private String organizationNamePath; private XPathExpression organizationNameExpression; @Override public void initXPaths(XPath xPath) throws XPathExpressionException { + this.organizationNamePath = this.hoverover.getText().get("organizationNamePath"); + if (this.organizationNamePath != null) this.organizationNameExpression = xPath.compile(this.organizationNamePath); super.initXPaths(xPath); @@ -55,6 +54,11 @@ public boolean eval(String value) { } }); + String drilldownURL = String.format(this.drilldown.url, + "http://www.geolabel.net/api/v1/drilldown", + "fullmetadataurl"); + facet.setDrilldownURL(drilldownURL); + return super.updateFacet(facet, metadataXml); } diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/QualityInformationFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/QualityInformationFacetDescription.java index f102c12..ee55096 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/QualityInformationFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/QualityInformationFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -29,11 +27,10 @@ * Checks availability of quality information * */ -@XmlRootElement(name = "qualityInformation") public class QualityInformationFacetDescription extends FacetTransformationDescription { - @XmlElement - private String scopeLevelPath; + + private String scopeLevelPath; private XPathExpression scopeLevelExpression; diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/StandardsComplianceFacetDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/StandardsComplianceFacetDescription.java index 16dca94..ce5871b 100644 --- a/server/src/main/java/org/n52/geolabel/server/mapping/description/StandardsComplianceFacetDescription.java +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/StandardsComplianceFacetDescription.java @@ -15,8 +15,6 @@ */ package org.n52.geolabel.server.mapping.description; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; @@ -28,10 +26,9 @@ /** * Checks availability of standards compliance information */ -@XmlRootElement(name = "standardsCompliance") public class StandardsComplianceFacetDescription extends FacetTransformationDescription { - @XmlElement - private String standardsPath; + + private String standardsPath; private XPathExpression standardsExpression; diff --git a/server/src/main/java/org/n52/geolabel/server/mapping/description/TransformationDescription.java b/server/src/main/java/org/n52/geolabel/server/mapping/description/TransformationDescription.java new file mode 100644 index 0000000..266bbe6 --- /dev/null +++ b/server/src/main/java/org/n52/geolabel/server/mapping/description/TransformationDescription.java @@ -0,0 +1,151 @@ +/** + * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH + * + * 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.n52.geolabel.server.mapping.description; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.codehaus.jackson.map.annotate.JsonRootName; +import org.n52.geolabel.commons.Label; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +public class TransformationDescription { + + protected static final Logger log = LoggerFactory.getLogger(TransformationDescription.class); + + @JsonRootName("transformationDescription") + public static class TransformationDescriptionWrapper { + public TransformationDescription transformationDescription; + } + + public static class NamespaceMapping { + + public String prefix; + + public String namespace; + + NamespaceMapping() { + // + } + + public NamespaceMapping(String prefix, String namespace) { + this.prefix = prefix; + this.namespace = namespace; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("NamespaceMapping ["); + if (this.prefix != null) { + builder.append("prefix="); + builder.append(this.prefix); + builder.append(", "); + } + if (this.namespace != null) { + builder.append("namespace="); + builder.append(this.namespace); + } + builder.append("]"); + return builder.toString(); + } + + } + + public String name; + + public NamespaceMapping[] namespaceMappings; + + // @XmlElementWrapper + // @XmlElementRef + public FacetTransformationDescription< ? >[] facetDescriptions; + + public void initXPaths() throws XPathExpressionException { + if (this.namespaceMappings != null) { + XPathFactory factory = XPathFactory.newInstance(); + XPath xPath = factory.newXPath(); + + final Map namespaceMap = new HashMap<>(); + for (NamespaceMapping mapping : this.namespaceMappings) + namespaceMap.put(mapping.prefix, mapping.namespace); + + xPath.setNamespaceContext(new NamespaceContext() { + + @SuppressWarnings("rawtypes") + @Override + public Iterator getPrefixes(String namespaceURI) { + return null; + } + + @Override + public String getPrefix(String namespaceURI) { + return null; + } + + @Override + public String getNamespaceURI(String prefix) { + return namespaceMap.get(prefix); + } + }); + + if (this.facetDescriptions != null) + for (FacetTransformationDescription< ? > facetDescription : this.facetDescriptions) + facetDescription.initXPaths(xPath); + else + log.error("No facet descriptions given, cannot initialize XPaths."); + } + else + log.warn("No mappings defined!"); + } + + public void updateGeoLabel(Label label, Document metadataXml) { + for (FacetTransformationDescription< ? > facetDescription : this.facetDescriptions) + facetDescription.updateLabel(label, metadataXml); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("LabelTransformationDescription ["); + if (this.name != null) { + builder.append("name="); + builder.append(this.name); + builder.append(", "); + } + if (this.namespaceMappings != null) { + builder.append("namespaceMappings="); + builder.append(Arrays.toString(this.namespaceMappings)); + builder.append(", "); + } + if (this.facetDescriptions != null) { + builder.append("facetDescriptions="); + builder.append(Arrays.toString(this.facetDescriptions)); + } + builder.append("]"); + return builder.toString(); + } + +} diff --git a/server/src/main/java/org/n52/geolabel/server/resources/SVGResourceV1.java b/server/src/main/java/org/n52/geolabel/server/resources/SVGResourceV1.java index cc60d68..137e00c 100644 --- a/server/src/main/java/org/n52/geolabel/server/resources/SVGResourceV1.java +++ b/server/src/main/java/org/n52/geolabel/server/resources/SVGResourceV1.java @@ -75,8 +75,10 @@ public Response getLabelSVGByURL(@ApiParam("Url to LML document") @QueryParam(Co con.setReadTimeout(GeoLabelConfig.READ_TIMEOUT); label = Label.fromXML(con.getInputStream()); } - else - label = this.lmlResource.get().getLabelByURL(metadataURL, feedbackURL); + else { + LMLResourceV1 lmlR = this.lmlResource.get(); + label = lmlR.getLabelByURL(metadataURL, feedbackURL); + } return createLabelSVGResponse(size != null ? size.intValue() : 200, id, label); } diff --git a/server/src/main/java/org/n52/geolabel/server/resources/TransformationsResourceV1.java b/server/src/main/java/org/n52/geolabel/server/resources/TransformationsResourceV1.java new file mode 100644 index 0000000..e1c594d --- /dev/null +++ b/server/src/main/java/org/n52/geolabel/server/resources/TransformationsResourceV1.java @@ -0,0 +1,129 @@ +/** + * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH + * + * 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.n52.geolabel.server.resources; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Map; +import java.util.Map.Entry; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.annotation.XmlElementRef; +import javax.xml.bind.annotation.XmlRootElement; + +import org.n52.geolabel.server.config.TransformationDescriptionLoader; +import org.n52.geolabel.server.config.TransformationDescriptionResources; +import org.n52.geolabel.server.config.TransformationDescriptionResources.Source; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.wordnik.swagger.annotations.Api; +import com.wordnik.swagger.annotations.ApiOperation; + +@Path("/v1/transformations") +@Api(value = "/v1/transformations", description = "Access to the transformation rules used to generate a label") +@Singleton +public class TransformationsResourceV1 { + + protected static final Logger log = LoggerFactory.getLogger(TransformationsResourceV1.class); + + @XmlRootElement(name = "transformation") + public static class Transformation { + + public String url; + + public String fallback; + + public String used; + + Transformation() { + // + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Transformation ["); + if (this.url != null) { + builder.append("url="); + builder.append(this.url); + builder.append(", "); + } + if (this.fallback != null) { + builder.append("fallback="); + builder.append(this.fallback); + builder.append(", "); + } + if (this.used != null) { + builder.append("used="); + builder.append(this.used); + } + builder.append("]"); + return builder.toString(); + } + } + + @XmlRootElement(name = "transformations") + public static class TransformationsHolder { + + @XmlElementRef + private ArrayList transformations = new ArrayList<>(); + + public TransformationsHolder() { + // + } + + public TransformationsHolder(Map transformationDescriptionResources, Map usedSources) { + for (Entry entry : transformationDescriptionResources.entrySet()) { + Transformation t = new Transformation(); + t.url = entry.getKey().toString(); + t.fallback = entry.getValue(); + Source source = usedSources.get(entry.getKey()); + t.used = (source == null) ? Source.NA.toString() : source.toString(); + + this.transformations.add(t); + log.debug("Created transformation {}", t); + } + } + + } + + private TransformationDescriptionLoader loader; + + private TransformationDescriptionResources resources; + + @Inject + public TransformationsResourceV1(TransformationDescriptionResources resources, + TransformationDescriptionLoader loader) { + this.resources = resources; + this.loader = loader; + } + + @GET + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "Returns a list of used transformations") + public TransformationsHolder getTransformationsInfo() { + TransformationsHolder holder = new TransformationsHolder(this.resources.getResources(), + this.loader.getUsedSources()); + + return holder; + } +} diff --git a/server/src/main/resources/transformations/transformer.json b/server/src/main/resources/transformations/transformer.json new file mode 100644 index 0000000..7732bfd --- /dev/null +++ b/server/src/main/resources/transformations/transformer.json @@ -0,0 +1,147 @@ +{ + "transformationDescription":{ + "name":"transformer", + "namespaceMappings":[ + { + "prefix":"gmd", + "namespace":"http://www.isotc211.org/2005/gmd" + }, + { + "prefix":"gvq", + "namespace":"http://www.geoviqua.org/QualityInformationModel/3.1" + }, + { + "prefix":"gmd19157", + "namespace":"http://www.geoviqua.org/gmd19157" + } + ], + "facetDescriptions":[ + { + "producerProfile":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='contact']/*[local-name()='CI_ResponsibleParty'] | //*[local-name()='ptcontac']/*[local-name()='cntinfo'] | //*[local-name()='pointOfContact']/*[local-name()='CI_ResponsibleParty'])))", + "hoverover":{ + "facetName":"Producer Profile", + "template":"Organisation name: %s.", + "text":{ + "organizationNamePath": "normalize-space(string(//*[local-name()='contact']/*[local-name()='CI_ResponsibleParty']/*[local-name()='organisationName'] | //*[local-name()='ptcontac']/*[local-name()='cntinfo']//*[local-name()='cntorg'] | //*[local-name()='pointOfContact']/*[local-name()='CI_ResponsibleParty']/*[local-name()='organisationName']))" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&facet=producer_profile" + } + } + }, + { + "producerComments":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='identificationInfo']//*[local-name()='supplementalInformation'] | //*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem'])))", + "hoverover":{ + "facetName":"Producer Comments", + "template":"Supplemental information: %s. Known problems: %s.", + "text":{ + "supplementalInformation":"normalize-space(string(//*[local-name()='identificationInfo']//*[local-name()='supplementalInformation']))", + "knownProblemsPath":"normalize-space(string(//*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem']))" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&facet=producer_comments" + } + } + }, + { + "lineage":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='trace']/*[local-name()='LI_Lineage']/*[local-name()='processStep'] | //*[local-name()='lineage']/*[local-name()='LI_Lineage']/*[local-name()='statement'] | //*[local-name()='lineage']/*[local-name()='LI_Lineage']/*[local-name()='processStep'])))", + "hoverover":{ + "facetName":"Lineage Information", + "template":"Number of process steps: %d.", + "text":{ + "processStepCountPath":"count(//*[local-name()='lineage']//*[local-name()='processStep'] | //*[local-name()='LI_Lineage']//*[local-name()='processStep'] | //*[local-name()='LI_Lineage']//*[local-name()='LE_ProcessStep'])" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&facet=lineage" + } + } + }, + { + "standardsCompliance":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='metadataStandardName'] | //*[local-name()='metstdv'])))", + "hoverover":{ + "facetName":"Standards Compliance", + "template":"Standard name: %s, version %s.", + "text":{ + "standardNamePath":"normalize-space(string(//*[local-name()='metadataStandardName'] | //*[local-name()='metstdv']))", + "standardVersion":"normalize-space(string(//*[local-name()='metadataStandardVersion']))" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&facet=standards_complaince" + } + } + }, + { + "qualityInformation":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue'])))", + "hoverover":{ + "facetName":"Quality Information", + "template":"Quality information scope: %s", + "text":{ + "scopeLevelPath":"concat(substring(concat(substring('pixel level', 1 div boolean(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href)), substring('dataset level', 1 div not(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href))), 1 div boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue'])))), substring('', 1 div not(boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue']))))))" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&facet=quality_information" + } + } + }, + { + "userFeedback":{ + "availabilityPath":"boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))", + "hoverover":{ + "facetName":"User Feedback", + "template":"Number of feedbacks: %d. Average rating: %d (%d ratings).", + "text":{ + "feedbacksCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count'])", + "averageRatingPath":"number((number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average'])))))) div number(concat(substring(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']), 1 div boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))), substring(1, 1 div not(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))))))", + "ratingsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count'])" + } + }, + "drilldown":{ + "url":"%s?feedback=%s&facet=user_feedback" + } + } + }, + { + "expertReview":{ + "availabilityPath":"boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']))", + "hoverover":{ + "facetName":"Expert Review", + "template":"Number of reviews: %d. Average rating: %d (%d ratings).", + "text":{ + "reviewsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])", + "averageRatingPath":"number((number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']))), substring(0, 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average']))), substring(0, 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average'])))))) div concat(substring(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']), 1 div boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']))), substring(1, 1 div not(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])))))", + "ratingsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])" + } + }, + "drilldown":{ + "url":"%s?feedback=%s&facet=expert_review" + } + } + }, + { + "citations":{ + "availabilityPath":"boolean(number(count(//*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation'] | //*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='identificationInfo']/*[local-name()='MD_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'])) + number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']))", + "hoverover":{ + "facetName":"Citations Information", + "template":"Number of citations: %d.", + "text":{ + "citationsCountPath":"number(number(count(//*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation'] | //*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='identificationInfo']/*[local-name()='MD_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'])) + number(concat(substring(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text(), 1 div boolean(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text())), substring('0', 1 div not(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text())))))" + } + }, + "drilldown":{ + "url":"%s?metadata=%s&feedback=%s&facet=citations_information" + } + } + } + ] + } +} \ No newline at end of file diff --git a/server/src/main/resources/transformations/transformerGVQ.json b/server/src/main/resources/transformations/transformerGVQ.json new file mode 100644 index 0000000..400555d --- /dev/null +++ b/server/src/main/resources/transformations/transformerGVQ.json @@ -0,0 +1,101 @@ +{ + "transformationDescription":{ + "name":"transformerGVQ", + "namespaceMappings":[ + { + "prefix":"gmd", + "namespace":"http://www.isotc211.org/2005/gmd" + }, + { + "prefix":"gvq", + "namespace":"http://www.geoviqua.org/QualityInformationModel/3.1" + }, + { + "prefix":"gmd19157", + "namespace":"http://www.geoviqua.org/gmd19157" + } + ], + "facetDescriptions":[ + { + "producerComments":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem'])))", + "hoverover":{ + "facetName":"Producer Comments", + "template":"Supplemental information: %s. Known problems: %s.", + "text":{ + "supplementalInformation":"", + "knownProblemsPath":"normalize-space(string(//*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem']))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=producer_comments" + } + } + }, + { + "qualityInformation":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report'])))", + "hoverover":{ + "facetName":"Quality Information", + "template":"Quality information scope: %s", + "text":{ + "scopeLevelPath":"concat(substring(concat(substring('pixel level', 1 div boolean(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href)), substring('dataset level', 1 div not(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href))), 1 div boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report'])))), substring('', 1 div not(boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']//*[local-name()='GVQ_DiscoveredIssue'] | //*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']))))))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=quality_information" + } + } + }, + { + "userFeedback":{ + "availabilityPath":"boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))", + "hoverover":{ + "facetName":"User Feedback", + "template":"Number of feedbacks: %d. Average rating: %d (%d ratings).", + "text":{ + "feedbacksCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count'])", + "averageRatingPath":"number((number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='1']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='2']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average']))), substring('0', 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='3']]/*[local-name()='average'])))))) div number(concat(substring(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']), 1 div boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))), substring(1, 1 div not(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count']))))))", + "ratingsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='1' or text()='2' or text()='3']]/*[local-name()='count'])" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=user_feedback" + } + } + }, + { + "expertReview":{ + "availabilityPath":"boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']))", + "hoverover":{ + "facetName":"Expert Review", + "template":"Number of reviews: %d. Average rating: %d (%d ratings).", + "text":{ + "reviewsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='feedbackItemsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])", + "averageRatingPath":"number((number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']))), substring(0, 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='4']]/*[local-name()='average']))))) + number(concat(substring(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average']), 1 div boolean(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average']))), substring(0, 1 div not(number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='count'] * //../../*[local-name()='category'][*[local-name()='value'][text()='5']]/*[local-name()='average'])))))) div concat(substring(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']), 1 div boolean(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count']))), substring(1, 1 div not(sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])))))", + "ratingsCountPath":"sum(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='userRatingsByExpertiseLevel']/*[local-name()='category'][*[local-name()='value'][text()='4' or text()='5']]/*[local-name()='count'])" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=expert_review" + } + } + }, + { + "citations":{ + "availabilityPath":"boolean(number(count(//*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='identificationInfo']/*[local-name()='MD_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'])) + number(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']))", + "hoverover":{ + "facetName":"Citations Information", + "template":"Number of citations: %d.", + "text":{ + "citationsCountPath":"number(number(count(//*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='identificationInfo']/*[local-name()='MD_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] | //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'])) + number(concat(substring(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text(), 1 div boolean(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text())), substring('0', 1 div not(//*[local-name()='GVQ_FeedbackCollection']/*[local-name()='summary']/*[local-name()='numberOfPublications']/text())))))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=citations" + } + } + } + ] + } +} \ No newline at end of file diff --git a/server/src/main/resources/transformations/transformerGVQ.xml b/server/src/main/resources/transformations/transformerGVQ.xml deleted file mode 100644 index b3e4333..0000000 --- a/server/src/main/resources/transformations/transformerGVQ.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - //gvq:dataQualityInfo//gvq:GVQ_DiscoveredIssue/gvq:knownProblem - - - //gvq:dataQualityInfo//gvq:GVQ_DiscoveredIssue/gvq:knownProblem - - - - - - //gvq:dataQualityInfo/gvq:GVQ_DataQuality - - - //gvq:dataQualityInfo/gvq:GVQ_DataQuality/gmd19157:scope//gmd:MD_ScopeCode/@codeListValue - - - - - - - - - - - - - - - - - - - - - 3] - ]]> - - - - 3]) - ]]> - - - - 3]/../gvq:rating/gvq:score - ]]> - - - - - - //gmd:identificationInfo/gvq:GVQ_DataIdentification/*:referenceDoc/gvq:GVQ_Publication - | - //gvq:dataQualityInfo/gvq:GVQ_DataQuality/*:report//*:referenceDoc/gvq:GVQ_Publication - | - //*:discoveredIssue/gvq:GVQ_DiscoveredIssue//*:referenceDoc/gvq:GVQ_Publication - | - //gvq:item/*:citation - | - //gvq:item/gvq:usage//*:referenceDoc/gvq:GVQ_Publication - - - count( - //gmd:identificationInfo/gvq:GVQ_DataIdentification/*:referenceDoc/gvq:GVQ_Publication - | - //gvq:dataQualityInfo/gvq:GVQ_DataQuality/*:report//*:referenceDoc/gvq:GVQ_Publication - | - //*:discoveredIssue/gvq:GVQ_DiscoveredIssue//*:referenceDoc/gvq:GVQ_Publication - | - //gvq:item/*:citation - | - //gvq:item/gvq:usage//*:referenceDoc/gvq:GVQ_Publication) - - - - - \ No newline at end of file diff --git a/server/src/main/resources/transformations/transformerRest.json b/server/src/main/resources/transformations/transformerRest.json new file mode 100644 index 0000000..b5a6988 --- /dev/null +++ b/server/src/main/resources/transformations/transformerRest.json @@ -0,0 +1,105 @@ +{ + "transformationDescription":{ + "name":"transformerRest", + "namespaceMappings":[ + { + "prefix":"gmd", + "namespace":"http://www.isotc211.org/2005/gmd" + } + ], + "facetDescriptions":[ + { + "producerProfile":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='contact']/*[local-name()='CI_ResponsibleParty'] | //*[local-name()='ptcontac']/*[local-name()='cntinfo'] | //*[local-name()='pointOfContact']/*[local-name()='CI_ResponsibleParty'])))", + "hoverover":{ + "facetName":"Producer Profile", + "template":"Organisation name: %s.", + "text":{ + "organizationNamePath":"normalize-space(string(//*[local-name()='contact']/*[local-name()='CI_ResponsibleParty']/*[local-name()='organisationName'] | //*[local-name()='ptcontac']/*[local-name()='cntinfo']//*[local-name()='cntorg'] | //*[local-name()='pointOfContact']/*[local-name()='CI_ResponsibleParty']/*[local-name()='organisationName']))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=producer_profile" + } + } + }, + { + "producerComments":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='identificationInfo']//*[local-name()='supplementalInformation'])))", + "hoverover":{ + "facetName":"Producer Comments", + "template":"Supplemental information: %s. %sKnown problems: %s.", + "text":{ + "supplementalInformation":"normalize-space(string(//*[local-name()='identificationInfo']//*[local-name()='supplementalInformation']))", + "knownProblemsPath":"" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=producer_comments" + } + } + }, + { + "lineage":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='trace']/*[local-name()='LI_Lineage']/*[local-name()='processStep'] | //*[local-name()='lineage']/*[local-name()='LI_Lineage']/*[local-name()='statement'] | //*[local-name()='lineage']/*[local-name()='LI_Lineage']/*[local-name()='processStep'])))", + "hoverover":{ + "facetName":"Lineage Information", + "template":"Number of process steps: %d.", + "text":{ + "processStepCountPath":"count(//*[local-name()='lineage']//*[local-name()='processStep'] | //*[local-name()='LI_Lineage']//*[local-name()='processStep'] | //*[local-name()='LI_Lineage']//*[local-name()='LE_ProcessStep'])" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=lineage" + } + } + }, + { + "standardsCompliance":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='metadataStandardName'] | //*[local-name()='metstdv'])))", + "hoverover":{ + "facetName":"Standards Compliance", + "template":"Standard name: %s, version %s.", + "text":{ + "standardNamePath":"normalize-space(string(//*[local-name()='metadataStandardName'] | //*[local-name()='metstdv']))", + "standardVersion":"normalize-space(string(//*[local-name()='metadataStandardVersion']))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=standards_complaince" + } + } + }, + { + "qualityInformation":{ + "availabilityPath":"boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report'])))", + "hoverover":{ + "facetName":"Quality Information", + "template":"Quality information scope: %s", + "text":{ + "scopeLevelPath":"concat(substring(concat(substring('pixel level', 1 div boolean(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href)), substring('dataset level', 1 div not(//*[local-name()='dataQualityInfo']/*[local-name()='DQ_DataQuality']/*[local-name()='report']//*[local-name()='result']/*[local-name()='DQ_QuantitativeResult']/*[local-name()='value']/*[local-name()='Record']//@href))), 1 div boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report'])))), substring('', 1 div not(boolean(normalize-space(string(//*[local-name()='dataQualityInfo']/*[local-name()='report']))))))" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=quality_information" + } + } + }, + { + "citations":{ + "availabilityPath":"boolean(count(//*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation']))", + "hoverover":{ + "facetName":"Citations Information", + "template":"Number of citations: %d.", + "text":{ + "citationsCountPath":"count(//*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation'])" + } + }, + "drilldown":{ + "url":"http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=citations" + } + } + } + ] + } +} \ No newline at end of file diff --git a/server/src/main/resources/transformations/transformerRest.xml b/server/src/main/resources/transformations/transformerRest.xml deleted file mode 100644 index a3eb0bb..0000000 --- a/server/src/main/resources/transformations/transformerRest.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - //*:contact/*:CI_ResponsibleParty | - //*:ptcontac/*:cntinfo | - //*:pointOfContact/*:CI_ResponsibleParty - - - //gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName | - //gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:organisationName - - - - - - //*:LI_Lineage | - //*:lineage - - - count( - //*:LI_Lineage//*:processStep | - //*:lineage//*:processStep) - - - - - - - //gmd:identificationInfo//gmd:supplementalInformation - - - //gmd:identificationInfo//gmd:supplementalInformation - - - - - - //*:metadataStandardName | - //*:metstdv - - - normalize-space(string-join( - (//*:metadataStandardName/normalize-space(), - //*:metstdv/normalize-space(), - //*:metadataStandardVersion/normalize-space()), ', ')) - - - - - - - //gmd:dataQualityInfo - - - //gmd:dataQualityInfo//gmd:scope//gmd:MD_ScopeCode/@codeListValue - - - - - - - //*:LI_Lineage/*:processStep//*:sourceCitation/*:CI_Citation - - - count(//*:LI_Lineage/*:processStep//*:sourceCitation/*:CI_Citation) - - - - - - \ No newline at end of file diff --git a/server/src/main/webapp/index.xhtml b/server/src/main/webapp/index.xhtml index 8170713..1656985 100644 --- a/server/src/main/webapp/index.xhtml +++ b/server/src/main/webapp/index.xhtml @@ -13,7 +13,7 @@
-

Test

+

GEO label Example

@@ -70,7 +70,7 @@
-

Examples

+

More Examples

    diff --git a/server/src/test/java/org/n52/geolabel/server/mapping/MetadataTransformerTest.java b/server/src/test/java/org/n52/geolabel/server/mapping/MetadataTransformerTest.java index 5bac542..e906ae8 100644 --- a/server/src/test/java/org/n52/geolabel/server/mapping/MetadataTransformerTest.java +++ b/server/src/test/java/org/n52/geolabel/server/mapping/MetadataTransformerTest.java @@ -18,10 +18,12 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; +import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; @@ -29,24 +31,24 @@ import java.util.EnumSet; import org.junit.Test; +import org.n52.geolabel.commons.ErrorFacet; import org.n52.geolabel.commons.Label; import org.n52.geolabel.commons.LabelFacet.Availability; import org.n52.geolabel.commons.test.Facet; +import org.n52.geolabel.server.config.TransformationDescriptionResources; public class MetadataTransformerTest { public static MetadataTransformer newMetadataTransformer() { - return new MetadataTransformer(); + return new MetadataTransformer(new TransformationDescriptionResources()); } @Test public void testParseMetadata() throws IOException { MetadataTransformer metadataTransformer = newMetadataTransformer(); - InputStream input = getClass().getResourceAsStream("transformer.xml"); - metadataTransformer.readTransformationDescription(input); - InputStream metadataStream = getClass().getResourceAsStream("metadata.xml"); + InputStream metadataStream = getClass().getResourceAsStream("/testfiles/metadata/GLC2000.xml"); // StringWriter writer = new StringWriter(); // IOUtils.copy(metadataStream, writer, "utf-8"); // String theString = writer.toString(); @@ -231,6 +233,21 @@ public void testIndiaGVQ() throws IOException { }); } + @Test + public void testMtri2an1ib() throws IOException { + testMetadataExample("DigitalClimaticAtlas_mt_an_GEOlabel.xml", new LabelControlHolder() { + { + this.availableFacets = EnumSet.complementOf(EnumSet.of(Facet.USER_FEEDBACK, Facet.EXPERT_REVIEW)); + this.organizationsNames = new String[] {"JRC"}; + this.producerCommentsStart = new String[] {"The GVM unit"}; + this.processStepCount = Integer.valueOf(3); + this.standards = new String[] {"ISO 19115:2003/19139, 1.0"}; + this.scopeLevels = new String[] {"dataset"}; + this.citationCount = Integer.valueOf(5); + } + }); + } + private void testMetadataExample(String exampleFile, LabelControlHolder control) throws IOException { MetadataTransformer metadataTransformer = newMetadataTransformer(); InputStream metadataStream = getClass().getClassLoader().getResourceAsStream("testfiles/metadata/" @@ -313,8 +330,8 @@ private void testMetadataExample(String exampleFile, LabelControlHolder control) @SuppressWarnings("unused") @Test - public void testLabelUrlKey() throws MalformedURLException { - new MetadataTransformer() { + public void testLabelUrlKey() throws IOException { + new MetadataTransformer(new TransformationDescriptionResources()) { { URL testURL1 = new URL("http://test1.resource1"); URL testURL2 = new URL("http://test2.resource2"); @@ -331,7 +348,24 @@ public void testLabelUrlKey() throws MalformedURLException { assertTrue(new LabelUrlKey(testURL1, testURL2).hashCode() == new LabelUrlKey(testURL2, testURL1).hashCode()); } }; + } + + @Test + public void testResourceNotFoundErrorMessage() throws IOException { + MetadataTransformer metadataTransformer = newMetadataTransformer(); + Label label = metadataTransformer.createGeoLabel(new URL("http://does.not/exist.xml")); + + ErrorFacet ef = label.getErrorFacet(); + assertEquals("error facet availability", Availability.AVAILABLE, ef.getAvailability()); + assertNotNull("error message null", ef.getErrorMessage()); + + StringWriter sw = new StringWriter(); + label.toSVG(sw, "testid", 100); + String svgString = sw.toString(); + assertTrue("error string is given", svgString.contains("does.not")); + assertTrue("error string is given", svgString.contains("Error:")); + assertTrue("error string is given", svgString.contains("Message:")); } } diff --git a/server/src/test/java/org/n52/geolabel/server/mapping/TransformationDescriptionTest.java b/server/src/test/java/org/n52/geolabel/server/mapping/TransformationDescriptionTest.java new file mode 100644 index 0000000..141b89e --- /dev/null +++ b/server/src/test/java/org/n52/geolabel/server/mapping/TransformationDescriptionTest.java @@ -0,0 +1,173 @@ +/** + * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH + * + * 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.n52.geolabel.server.mapping; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.codehaus.jackson.JsonGenerationException; +import org.codehaus.jackson.map.JsonMappingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.junit.Test; +import org.n52.geolabel.server.config.TransformationDescriptionLoader; +import org.n52.geolabel.server.config.TransformationDescriptionResources; +import org.n52.geolabel.server.mapping.description.CitationsFacetDescription; +import org.n52.geolabel.server.mapping.description.FacetTransformationDescription; +import org.n52.geolabel.server.mapping.description.ProducerCommentsFacetDescription; +import org.n52.geolabel.server.mapping.description.TransformationDescription; +import org.n52.geolabel.server.mapping.description.TransformationDescription.NamespaceMapping; + +/** + * transformer file structure: + { + "transformationDescription":{ + "name":"transformer", + "namespaceMappings":[], + "facetDescriptions": + [ + { + "producerProfile":{} + }, + { + "producerComments":{} + }, + { + "lineage":{} + }, + { + "standardsCompliance":{} + }, + { + "qualityInformation":{} + }, + { + "userFeedback":{} + }, + { + "expertReview":{} + }, + { + "citations":{} + } + ] + } + } + + */ +public class TransformationDescriptionTest { + + @SuppressWarnings("boxing") + @Test + public void loadGvqJsonTransformationDescription() throws MalformedURLException { + + Map resources = new HashMap<>(); + resources.put(new URL("http://do.not.even.look/for/it"), "transformations/transformerGVQ.json"); + TransformationDescriptionLoader loader = new TransformationDescriptionLoader(new TransformationDescriptionResources()); + + Set tds = loader.load(); + TransformationDescription description = tds.iterator().next(); + + assertThat("mappings read", description.namespaceMappings.length, is(equalTo(3))); + assertTrue(description.namespaceMappings[0].prefix.equals("gmd")); + assertTrue(description.namespaceMappings[0].namespace.equals("http://www.isotc211.org/2005/gmd")); + + assertTrue(description.facetDescriptions.length == 5); + + assertThat("class is correct umarshalled", + description.facetDescriptions[0].getClass().getName(), + is(equalTo(ProducerCommentsFacetDescription.class.getName()))); + assertThat("availability path is correct", + description.facetDescriptions[0].getAvailabilityPath(), + is(equalTo("boolean(normalize-space(string(//*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem'])))"))); + assertThat("drilldown is correct", + description.facetDescriptions[0].getDrilldown().url, + is(equalTo("http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=producer_comments"))); + } + + @SuppressWarnings("boxing") + @Test + public void loadJsonTransformationDescription() throws MalformedURLException { + + Map resources = new HashMap<>(); + resources.put(new URL("http://do.not.even.look/for/it"), "/transformations/transformer.json"); + TransformationDescriptionLoader loader = new TransformationDescriptionLoader(new TransformationDescriptionResources(resources)); + + Set tds = loader.load(); + TransformationDescription description = tds.iterator().next(); + + assertThat("name", description.name, is(equalTo("transformer"))); + assertThat("mappings read", description.namespaceMappings.length, is(equalTo(3))); + assertTrue(description.namespaceMappings[0].prefix.equals("gmd")); + assertTrue(description.namespaceMappings[0].namespace.equals("http://www.isotc211.org/2005/gmd")); + + assertThat("all facets read", description.facetDescriptions.length, is(equalTo(8))); + + assertThat("class is correct umarshalled", + description.facetDescriptions[1].getClass().getName(), + is(equalTo(ProducerCommentsFacetDescription.class.getName()))); + assertThat("availability path is correct", + description.facetDescriptions[1].getAvailabilityPath(), + containsString("knownProblem")); + assertThat("availability path is correct", + description.facetDescriptions[1].getAvailabilityPath(), + containsString("GVQ_DiscoveredIssue")); + assertThat("drilldown is correct", + description.facetDescriptions[1].getDrilldown().url, + is(equalTo("http://www.geolabel.net/api/v1/drilldown?metadata=%s&facet=producer_comments"))); + } + + public void marshalDescription() throws JsonGenerationException, JsonMappingException, IOException { + TransformationDescription d = new TransformationDescription(); + d.name = "testname"; + + d.facetDescriptions = new FacetTransformationDescription< ? >[2]; + CitationsFacetDescription cfd = new CitationsFacetDescription(); + cfd.setCitationsCountPath("/test/path"); + d.facetDescriptions[0] = cfd; + + d.namespaceMappings = new NamespaceMapping[2]; + d.namespaceMappings[0] = new NamespaceMapping("lala", "http://la.la"); + d.namespaceMappings[1] = new NamespaceMapping("fb", "http://foo.bar"); + + // JSONJAXBContext context = new JSONJAXBContext(JSONConfiguration.mappedJettison().build(), + // TransformationDescription.class); + // // JSONConfiguration jsonConfiguration = context.getJSONConfiguration(); + // JSONMarshaller marshaller = context.createJSONMarshaller(); + // StringWriter writer = new StringWriter(); + // marshaller.marshallToJSON(d, writer); + + ObjectMapper m = new ObjectMapper(); + // JsonNode rootNode = m.readTree(input); + // System.out.println(rootNode); + + // Map map = m.readValue(input, Map.class); + // System.out.println(map); + + String s = m.writeValueAsString(d); + System.out.println(s); + } +} diff --git a/server/src/test/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescriptionTest.java b/server/src/test/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescriptionTest.java deleted file mode 100644 index 8b30cc2..0000000 --- a/server/src/test/java/org/n52/geolabel/server/mapping/description/LabelTransformationDescriptionTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2013 52°North Initiative for Geospatial Open Source Software GmbH - * - * 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.n52.geolabel.server.mapping.description; - -import static org.junit.Assert.*; - -import java.io.IOException; - -import org.junit.Test; -import org.n52.geolabel.server.mapping.MetadataTransformer; -import org.n52.geolabel.server.mapping.MetadataTransformerTest; -import org.n52.geolabel.server.mapping.description.LabelTransformationDescription; - -public class LabelTransformationDescriptionTest { - - @Test - public void testParseTransformationDescription() throws IOException { - - MetadataTransformer metadataTransformer = MetadataTransformerTest - .newMetadataTransformer(); - metadataTransformer - .readTransformationDescription(MetadataTransformerTest.class - .getResourceAsStream("transformer.xml")); - - LabelTransformationDescription description = metadataTransformer - .getTransformationDescriptions().get(0); - - assertTrue(description.namespaceMappings.length == 1); - assertTrue(description.namespaceMappings[0].prefix.equals("gmd")); - assertTrue(description.namespaceMappings[0].namespace - .equals("http://www.isotc211.org/2005/gmd")); - - assertTrue(description.facetDescriptions.length == 8); - } -} diff --git a/server/src/test/resources/org/n52/geolabel/server/mapping/transformer.xml b/server/src/test/resources/org/n52/geolabel/server/mapping/transformer.xml deleted file mode 100644 index df514f9..0000000 --- a/server/src/test/resources/org/n52/geolabel/server/mapping/transformer.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - - //*[local-name()='contact']/*[local-name()='CI_ResponsibleParty'] | - //*[local-name()='ptcontac']/*[local-name()='cntinfo'] | - //*[local-name()='pointOfContact']/*[local-name()='CI_ResponsibleParty'] - - - //gmd:contact/gmd:CI_ResponsibleParty/gmd:organisationName | - //gmd:pointOfContact/gmd:CI_ResponsibleParty/gmd:organisationName - - - - - - //*[local-name()='LI_Lineage'] | - //*[local-name()='lineage'] - - - count( - //*[local-name()='LI_Lineage']//*[local-name()='processStep'] | - //*[local-name()='lineage']//*[local-name()='processStep']) - - - - - - //*[local-name()='identificationInfo']//*[local-name()='supplementalInformation']| - //*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem'] - - - //*[local-name()='identificationInfo']//*[local-name()='supplementalInformation']| - //*[local-name()='dataQualityInfo']//*[local-name()='GVQ_DiscoveredIssue']/*[local-name()='knownProblem'] - - - - - - //*[local-name()='metadataStandardName'] | - //*[local-name()='metstdv'] - - - normalize-space(string-join( - (//*[local-name()='metadataStandardName'], - //*[local-name()='metstdv'], - //*[local-name()='metadataStandardVersion']), ',')) - - - - - - //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality'] | - //*[local-name()='dataQualityInfo'] - - - //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='scope'] - //*[local-name()='MD_ScopeCode']/@codeListValue | - //*[local-name()='dataQualityInfo']//*[local-name()='scope'] - //*[local-name()='MD_ScopeCode']/@codeListValue - - - - - - - - - - - - - - - - - - - - - 3] - ]]> - - - - 3]) - ]]> - - - - 3] /../*[local-name()='rating']/*[local-name()='score'] - ]]> - - - - - - //*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation'] - | - //*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='item']/*[local-name()='citation'] | - //*[local-name()='item']/*[local-name()='usage']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - - - count( - //*[local-name()='LI_Lineage']/*[local-name()='processStep']//*[local-name()='sourceCitation']/*[local-name()='CI_Citation'] - | - //*[local-name()='identificationInfo']/*[local-name()='GVQ_DataIdentification']/*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='dataQualityInfo']/*[local-name()='GVQ_DataQuality']/*[local-name()='report']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='discoveredIssue']/*[local-name()='GVQ_DiscoveredIssue']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication'] - | - //*[local-name()='item']/*[local-name()='citation'] | - //*[local-name()='item']/*[local-name()='usage']//*[local-name()='referenceDoc']/*[local-name()='GVQ_Publication']) - - - - - - \ No newline at end of file diff --git a/server/src/test/resources/testfiles/metadata/DigitalClimaticAtlas_mt_an_GEOlabel.xml b/server/src/test/resources/testfiles/metadata/DigitalClimaticAtlas_mt_an_GEOlabel.xml new file mode 100644 index 0000000..0cc5377 --- /dev/null +++ b/server/src/test/resources/testfiles/metadata/DigitalClimaticAtlas_mt_an_GEOlabel.xml @@ -0,0 +1,1189 @@ + + + + mtri2an1ib + + + eng + + + 8859part1 + + + + + Miquel Ninyerola + + + Animal and Plant Biology and Ecology Department (Autonomous University of Barcelona) + + + Professor + + + + + + + miquel.ninyerola@uab.cat + + + + + + + author + + + + + 2008-02-08 + + + ISO 19115:2003/19139 + + + 1.0 + + + + + 2 + + + + + row + + + 4425 + + + 200 + + + + + + + column + + + 5540 + + + 200 + + + + + area + + + true + + + false + + + + -73900 4864900 + + + + + 1033900 4864900 + + + + + 1033900 3980100 + + + + + -73900 3980100 + + + + center + + + + + + + + + EPSG:23030 + + + + + + + + + + + Mean Annual Temperature (Digital Climatic Atlas of the Iberian Peninsula) + + + CDAIP + + + ACDPI + + + Temperatura mitjana anual (Atles climàtic Digital de la peninsula Ibèrica) + + + Temperatura media anual (Atlas climático Digital de la peninsula Ibérica) + + + + + 2004-07-03 + + + creation + + + + + + + mtri2an1ib + + + opengis.uab.cat + + + + + mapDigital + + + + + + Digital Climatic Atlas of the Iberian Peninsula + + + + + Please when using this dataset cite it as: "Ninyerola M, Pons X y Roure JM. 2005. Atlas Climático Digital de la Península Ibérica. Metodología y aplicaciones en bioclimatología y geobotánica. ISBN 932860-8-7. Universidad Autónoma de Barcelona, Bellaterra" + + + Digital Climatic Atlas of the Iberian Peninsula + + + + + Annual climatic digital maps, of mean temperature. Maps have been generated by means of statistical techniques, Geographic Information Systems and spatial interpolation. + + + It is well-known that the Iberian Peninsula presents interesting characteristics, as well as complex, in climatological and biogeographical terms. In addition, from geosciences and biosciences (hydrology, ecology, biogeography, etc) as well as from land managers (conservation agencies, etc) there is an obvious interest for climatology. Despite this interest, just data coming from meteorological stations is relevant enough. Even though, these stations present an irregular and discrete spatial distribution throughout the territory and hence spatial interpolation methods to obtain continuous surfaces are applied. + + + completed + + + + + + Xavier Pons + + + Geography Department (Autonomous University of Barcelona) + + + Professor + + + author + + + + + + + Joan M. Roure + + + Animal and Plant Biology and Ecology Department (Autonomous University of Barcelona) + + + Professor + + + author + + + + + + + Joan Masó + + + CREAF (Autonomous University of Barcelona) + + + Researcher + + + processor + + + + + + + Núria Julià + + + CREAF (Autonomous University of Barcelona) + + + Researcher + + + processor + + + + + + + asNeeded + + + dataset + + + Updated when a significant data retrieval from meteorological stations can be integrated. Spatial uncertainty maps in progress. + + + + + + + + GeoLabel.svg + + + A GEOLabel for this dataset + + + image/svg+xml;type=GEOLabel + + + + + + + Temperature + + + Spatial interpolation + + + theme + + + + + + + Iberian peninsula + + + place + + + + + + + There is no use or access limitation. + + + + + grid + + + + + + + 200000 + + + + + + + cat + + + climatologyMeteorologyAtmosphere + + + environment + + + + + Iberian peninsula excluding Andorra + + + + + -10.12421992 + + + 3.63115860 + + + 35.79574603 + + + 43.93704722 + + + + + + + + + Objective air temperature mapping for the Iberian Peninsula using spatial interpolation and GIS + + + + + 2007-07 + + + publication + + + + + + + + + + International Journal of Climatology + + + Volume 27, Issue 9 + + + 1231–1242 + + + + + 1097-0088 + + + + 110.1002/joc.1462 + + + describe + + + + journalArticle + + + + + http://onlinelibrary.wiley.com/doi/10.1002/joc.1462/abstract + + + + + + + + + Monthly precipitation mapping of the Iberian Peninsula using spatial interpolation tools implemented in a Geographic Information System + + + + + 2007-07 + + + publication + + + + + + + + + + Theoretical and Applied Climatology + + + Volume 89, Numbers 3-4 + + + 195-209 + + + + + 1434-4483 + + + + 10.1007/s00704-006-0264-2 + + + describe + + + + journalArticle + + + + + http://www.springerlink.com/content/06463p2677318556/ + + + + + + + + + + + Mean Annual Temperature + + + modelResult + + + + + + + Residuals from the multiple regression + + + qualityInformation + + + + + + + Standard deviation of the inter-model variability + + + qualityInformation + + + + + + + + + + + + Eduard Luque + + + CREAF (Autonomous University of Barcelona) + + + Researcher + + + + + + + e.luque@creaf.uab.cat + + + + + + + processor + + + + + + + If an offLine distribution (DVD) is required or if any problem with the Web Coverage Service (download capabilities) is found please contact Eduard Luque. + + + + + + + + + + + http://www.opengis.uab.es/cgi-bin/iberia/MiraMon.cgi?REQUEST=GetCapabilities&VERSION=1.3.0&SERVICE=WMS + + + + urn:ogc:serviceType:WebMapService:1.3.0:HTTP + + + LAYER=clima_anual_iberia&STYLE=Tmit + + + Servidor de Mapas del Atlas Climático Digital de la Península Ibérica (WMS) + + + download + + + Web Map Service (WMS) 1.3.0 + + + + + + + + http://www.ogc.uab.cat/cgi-bin/GeoViQUA/WMSQ/MiraMon.cgi?REQUEST=GetCapabilities&VERSION=1.3.0&SERVICE=WMS> + + + + urn:ogc:serviceType:WebMapService:1.3.0:HTTP:QualityProfile + + + LAYER=MeanAnnualTemperature + + + CREAF-MiraMon WMS-Q and WMTS-Q test demonstration server + + + download + + + Web Map Service (WMS) 1.3.0 - Quality profile + + + + + + + + http://www.opengis.uab.es/cgi-bin/iberia/MiraMon.cgi?REQUEST=GetCapabilities&VERSION=1.0&SERVICE=WCS + + + urn:ogc:serviceType:WebCoverageService:1.0:HTTP + + + + COVERAGE=clima_anual_iberia&BAND=Tmit + + + Servidor de Mapas del Atlas Climático Digital de la Península Ibérica (WCS) + + + download + + + Web Coverage Service (WCS) 1.0 + + + + + + + dvd + + + 1 + + + + + + + + + + + + + + + + mtri2an1ib.mmz + + + MMZ encoding of climatic data including uncertainty information at pixel level + + + MiraMon Compressed Map + + + mtri2an1ib_mean_temp,mtri2an1ib_mean_temp_residuals,mtri2an1ib_mean_temp_intermodel_variability + + + + + MiraMon Compressed Map (MMZ) + + + 1.1 + + + deflate + + + + + + + + + + + + + dataset + + + + + + + + 2004-07-02T00:00:00.0 + + + + + Cross-validation and calculation of Pearson Coefficient (R2) and Root Mean Square Error (RMSE) with 40% of the ground meteorological stations (global quality indicators) + + + + + + + directInternal + + + Random sampling into two lots + + + Subsets of 40% and 60% of the population + + + 100% of each lot is inspected + + + + + + + + Pearson Coefficient (R2) + + + + + + 0.9 + + + + + + + + + + Distribution of errors + + + + + + + 0 + 16 + + + + + + + + + + + Root Mean Square Error (RMSE) + + + + 0.8 + + + + + + + + + + + Interpolation of the residuals from the multiple regression using 100% of the ground meteorological stations. + + + + + directInternal + + + + + + + + grid + + + + + + + + + + + + + + + Standard deviation of the inter-model variability. + + + + + directInternal + + + Bootstrap sampling techniques are used to obtain 20 different models that are compared to obtain the inter-model variability. + + + ··$$·· + + + ··$$·· + + + + + + + + grid + + + + + + + + + + + + + + + + + + + + Empirical selection of the best proportion of the ground meteorological stations to be used to fit and to test the regression model (e.g. 60%-40%, 70%-30%,...) + + + + + + + + Random sampling (without constrains) over meteorological stations to assign each one of them to the fit (60%) and test (40%) sets. + + + + + + + + Enrichment of the test set of ground meteorological stations to include dataset values (predicted by linear regression) using binomial interpolation + + + + + + + + Pearson coefficient and Root Mean Squared Error computation using dataset and observed values for each ground meteorological stations on the test set + + + + + + + + + + + + + + + + + + Apply multiple regression techniques to the 100% of the meteorological stations. + + + + + + + + Regression residuals for each meteorological station are computed + + + + + + + Residual spatial interpolation is performed + + + + + + + + + + + + + + + + + + Split meteorological stations into train (70%) and test (30%) sets recursively (20 models) using bootstrap methods. + + + + + + + The 20 models obtained from the bootsrap sampling are mapped. + + + + + + + Standard deviation of the inter-model variability (using the 20 models) is computed. + + + + + + + + + + + There are two different origins depending on the part of the Iberian Peninsula. In the case of Spain, the original layer comes from the Army Map Service (SGE) 1:200000 topograhic series. The paper maps were scanned and georeferenced. The contour lines were digitized, converted into a topological structure and finally spatially interpolated using the ISOMDE procedure (implemented in the MiraMon GIS). In the case of Portugal, the 1km GTOPO30 world DEM was densifiyed and mosaiked with the contour line-based raster. + + + + + Meteorological stations from AEMET are filtered. First of all, the geometric position of the stations has been checked and modifiyed when need and possible. Secondly, stations with outlier values have been removed. Finally, stations with a temporal series length lower than 15 years have been removed. This theshold has been defined in order to obtain a compromise bewteen spatial coverage and temporal series lenght. + + + + + Meteorological stations from AEMET + + + + + Mean monthly climate records from the AEMET (temeprature and precipitation) + + + + + 2000 + + + creation + + + + + + + Unidad de Información Meteorológica. Instituto Nacional de Meteorología. + + + + + + + +34 915 819 810 + + + +34 915 819 811 + + + + + + + C/ Leonardo Prieto Castro, 8 (Ciudad Universitaria) + + + Madrid + + + 28071 + + + Spain + + + secinfomet@inm.es + + + infomet@inm.es + + + + + + + http://www.aemet.es/es/portada + + + + + + + author + + + + + tableHardcopy + + + + + + + + + + 1975 + 2000 + + + + + + + + + + Mean monthly climate records have been computed from raw AEMET data by using own routines. These routines fix problems with repeated records, inconsistencies in values and missing values to obtain an accurate monthly database that will be used as a basis for the spatial interpolations procedures. The total number of meteorological stations is 1068. + + + + + + + + + + + Indepent variables for the regression have been selected using prior expert knowledge. This set of variables have been feeded to statistical analysis to select the significant ones for the model. + + + + + ASTER Global Digital Elevation Model + + + + + ASTER Global Digital Elevation Model + + + + + 2009-06-29 + + + publication + + + + + + + + + The GDEM was created by stereo-correlating the 1.3 million scene ASTER VNIR, covering the surface of the Earth between latitudes 83N and 83S. The GDEM is produced with ~ 30 m spatial resolution, with a scenes of 1 x 1 degree in GeoTIFF format. Each GDEM file is accompanied by a file of quality assessment, which gives either the number of ASTER scenes used to calculate the value of a pixel (positive values) or whether external DEM data source used to fill the gaps of ASTER (negative values). The correspondence in this case is as follows: -1 in the case of SRTM3 V3 and -2 in the case of SRTM3 V2. + + + + + + + + + GIS based latitude + + + + + + + GIS based distance to Mediterranean sea (to express continentality) + + + + + + + GIS based distance to Cantabric sea (to express continentality) + + + + + + + GIS based distance to Atlantic sea (to express continentality) + + + + + + + DEM based solar radiation + + + + + + + + + Multiple lineal regression model is fitted and mapped. A mask is provided to identify intepolated and extrapolated areas (i.e. those whithin or outside the meteorological stations statistical range). + + + + + + + Regression residuals have been interpolated using inverse distance weighting. + + + + + + + Regression map and residual map (obtained on the two previous process steps) are combined to obtain the final dataset. + + + + + + + + + + + + + + + Some methodological constraints can be defined + + + First of all be careful with extrapolated areas (checking them in the provided binary mask). Moreover, be careful with areas with high uncertainty (checking them in the provided residuals map). + + + + + + + + + + + dataset + + + + + + + Area of Navarra with incorrectly modelled values + + + + + + 634145.9 4764080.8 634145.9 4775323.2 646710.9 4775323.2 646710.9 4764080.8 + + + + + + + + + + + + + A problem with the DEM on an subset of the Navarra area lead to an incorrect modelling of the temperature and to a very high residuals (due to a bad adjust of the model there) on this area. The problem is due to a bad attribute (a missing "0", i.e. the curve stated “10” instead of “100” m) on the isolines indicating heigh used to produce the DEM. + + + The area with incorrect values can be masked (marked with NoData). The bounding box with the incorrect values is (expressed in the reference system of the dataset): Min X: 634145.9, Min Y:4764080.8, Max X: 646710.9, Max X: 4775323.2. Next version of the Atlas will solve this problem. + + + + + + \ No newline at end of file diff --git a/server/src/test/resources/org/n52/geolabel/server/mapping/metadata.xml b/server/src/test/resources/testfiles/metadata/GLC2000.xml similarity index 100% rename from server/src/test/resources/org/n52/geolabel/server/mapping/metadata.xml rename to server/src/test/resources/testfiles/metadata/GLC2000.xml