/** * Copyright (C) 2012-2017 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * License version 2 and the aforementioned licenses. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. */ package org.n52.sos.ds.hibernate.util.procedure; import java.util.ArrayList; import java.util.Locale; import java.util.Map; import org.hibernate.Session; import org.n52.sos.convert.Converter; import org.n52.sos.convert.ConverterException; import org.n52.sos.convert.ConverterRepository; import org.n52.sos.ds.hibernate.dao.HibernateSqlQueryConstants; import org.n52.sos.ds.hibernate.entities.DescriptionXmlEntity; import org.n52.sos.ds.hibernate.entities.HibernateRelations.HasProcedureDescriptionFormat; import org.n52.sos.ds.hibernate.entities.Procedure; import org.n52.sos.ds.hibernate.entities.ValidProcedureTime; import org.n52.sos.ds.hibernate.util.procedure.create.DescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.create.FileDescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.create.GeneratedDescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.create.LinkedDescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.create.ValidProcedureTimeDescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.create.XmlStringDescriptionCreationStrategy; import org.n52.sos.ds.hibernate.util.procedure.enrich.ProcedureDescriptionEnrichments; import org.n52.sos.ds.hibernate.util.procedure.generator.HibernateProcedureDescriptionGeneratorRepository; import org.n52.sos.exception.ows.InvalidParameterValueException; import org.n52.sos.exception.ows.NoApplicableCodeException; import org.n52.sos.ogc.gml.time.TimePeriod; import org.n52.sos.ogc.ows.OwsExceptionReport; import org.n52.sos.ogc.sensorML.AbstractProcess; import org.n52.sos.ogc.sensorML.SensorML; import org.n52.sos.ogc.sos.SosConstants; import org.n52.sos.ogc.sos.SosProcedureDescription; import org.n52.sos.util.http.HTTPStatus; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.collect.Lists; /** * @author <a href="mailto:e.h.juerrens@52north.org">Eike * HinderkJürrens</a> * @author <a href="mailto:c.hollmann@52north.org">Carsten Hollmann</a> * @author <a href="mailto:c.autermann@52north.org">Christian Autermann</a> * @author <a href="mailto:shane@axiomalaska.com">Shane StClair</a> * * @since 4.0.0 * * TODO - apply description enrichment to all types of procedures * (creates, file, or database) - use setting switches for code flow */ public class HibernateProcedureConverter implements HibernateSqlQueryConstants { /** * Create procedure description from file, single XML text or generate * * @param procedure * Hibernate procedure entity * @param requestedDescriptionFormat * Requested procedure descriptionFormat * @param requestedServiceVersion * Requested SOS version * @param session * Hibernate session * * @return created SosProcedureDescription * * @throws OwsExceptionReport * If an error occurs */ public SosProcedureDescription createSosProcedureDescription(Procedure procedure, String requestedDescriptionFormat, String requestedServiceVersion, Session session) throws OwsExceptionReport { // child hierarchy procedures haven't been queried yet, pass null return createSosProcedureDescription(procedure, requestedDescriptionFormat, requestedServiceVersion, null, session); } /** * Create procedure description from file, single XML text or generate * * @param procedure * Hibernate procedure entity * @param requestedDescriptionFormat * Requested procedure descriptionFormat * @param requestedServiceVersion * Requested SOS version * @param loadedProcedures * Loaded procedure hierarchy (passed to recursive requests to * avoid multiple queries) * @param session * Hibernate session * * @return created SosProcedureDescription * * @throws OwsExceptionReport * If an error occurs */ public SosProcedureDescription createSosProcedureDescription(Procedure procedure, String requestedDescriptionFormat, String requestedServiceVersion, Map<String, Procedure> loadedProcedures, Locale i18n, Session session) throws OwsExceptionReport { if (procedure == null) { throw new NoApplicableCodeException().causedBy( new IllegalArgumentException("Parameter 'procedure' should not be null!")).setStatus( HTTPStatus.INTERNAL_SERVER_ERROR); } checkOutputFormatWithDescriptionFormat(procedure.getIdentifier(), procedure, requestedDescriptionFormat, getFormat(procedure)); SosProcedureDescription desc = create(procedure, requestedDescriptionFormat, null, i18n, session).orNull(); if (desc != null) { addHumanReadableName(desc, procedure); enrich(desc, procedure, requestedServiceVersion, requestedDescriptionFormat, null, loadedProcedures, i18n, session); if (!requestedDescriptionFormat.equals(desc.getDescriptionFormat())) { desc = convert(desc.getDescriptionFormat(), requestedDescriptionFormat, desc); desc.setDescriptionFormat(requestedDescriptionFormat); } } return desc; } /** * Create procedure description from XML text stored in ValidProcedureTime * table * * @param procedure * Hibernate procedure entity * @param vpt * Hibernate ValidProcedureTime entity * @param version * Requested SOS version * @param session * Hibernate session * * @return created SosProcedureDescription * * @throws OwsExceptionReport * If an error occurs */ public SosProcedureDescription createSosProcedureDescriptionFromValidProcedureTime(Procedure procedure, String requestedDescriptionFormat, ValidProcedureTime vpt, String version, Locale i18n, Session session) throws OwsExceptionReport { if (vpt != null) { checkOutputFormatWithDescriptionFormat(procedure.getIdentifier(), vpt, requestedDescriptionFormat, getFormat(vpt)); } else { checkOutputFormatWithDescriptionFormat(procedure.getIdentifier(), procedure, requestedDescriptionFormat, getFormat(procedure)); } Optional<SosProcedureDescription> description = create(procedure, requestedDescriptionFormat, vpt, i18n, session); if (description.isPresent()) { addHumanReadableName(description.get(), procedure); enrich(description.get(), procedure, version, requestedDescriptionFormat, getValidTime(vpt), null, i18n, session); if (!requestedDescriptionFormat.equals(description.get().getDescriptionFormat())) { SosProcedureDescription converted = convert(description.get().getDescriptionFormat(), requestedDescriptionFormat, description.get()); converted.setDescriptionFormat(requestedDescriptionFormat); return converted; } } return description.orNull(); } public SosProcedureDescription createSosProcedureDescription(Procedure procedure, String requestedDescriptionFormat, String requestedServiceVersion, Locale i18n, Session session) throws OwsExceptionReport { return createSosProcedureDescription(procedure, requestedDescriptionFormat, requestedServiceVersion, null, i18n, session); } private void addHumanReadableName(SosProcedureDescription desc, Procedure procedure) { if (!desc.isSetHumanReadableIdentifier() && procedure.isSetName()) { desc.setHumanReadableIdentifier(procedure.getName()); } } protected TimePeriod getValidTime(ValidProcedureTime validProcedureTime) { return new TimePeriod(validProcedureTime.getStartTime(), validProcedureTime.getEndTime()); } private String getFormat(HasProcedureDescriptionFormat hpdf) { return hpdf.getProcedureDescriptionFormat().getProcedureDescriptionFormat(); } /** * Checks the requested procedureDescriptionFormat with the datasource * procedureDescriptionFormat. * @param identifier * * @param procedure * the procedure * @param requestedFormat * requested procedureDescriptionFormat * @param descriptionFormat * Data source procedureDescriptionFormat * * @throws OwsExceptionReport * If procedureDescriptionFormats are invalid */ @VisibleForTesting boolean checkOutputFormatWithDescriptionFormat(String identifier, DescriptionXmlEntity procedure, String requestedFormat, String descriptionFormat) throws OwsExceptionReport { if (procedure.isSetDescriptionXml()) { if (requestedFormat.equalsIgnoreCase(descriptionFormat) || existConverter(descriptionFormat, requestedFormat)) { return true; } } else { if (existsGenerator(requestedFormat)) { return true; } } throw new InvalidParameterValueException() .at(SosConstants.DescribeSensorParams.procedure) .withMessage("The value of the output format is wrong and has to be %s for procedure %s", descriptionFormat, identifier).setStatus(HTTPStatus.BAD_REQUEST); } private boolean existConverter(String from, String to) { return ConverterRepository.getInstance().hasConverter(from, to); } private boolean existsGenerator(String descriptionFormat) { return HibernateProcedureDescriptionGeneratorRepository.getInstance() .hasHibernateProcedureDescriptionGeneratorFactory(descriptionFormat); } private Optional<SosProcedureDescription> create(Procedure procedure, String descriptionFormat, ValidProcedureTime vpt, Locale i18n, Session session) throws OwsExceptionReport { Optional<DescriptionCreationStrategy> strategy = getCreationStrategy(procedure, vpt); if (strategy.isPresent()) { return Optional.fromNullable(strategy.get().create(procedure, descriptionFormat, i18n, session)); } else { return Optional.absent(); } } private Optional<DescriptionCreationStrategy> getCreationStrategy(Procedure p, ValidProcedureTime vpt) { for (DescriptionCreationStrategy strategy : getCreationStrategies(vpt)) { if (strategy.apply(p)) { return Optional.of(strategy); } } return Optional.absent(); } protected ArrayList<DescriptionCreationStrategy> getCreationStrategies(ValidProcedureTime vpt) { return Lists.newArrayList(new ValidProcedureTimeDescriptionCreationStrategy(vpt), new LinkedDescriptionCreationStrategy(), new XmlStringDescriptionCreationStrategy(), new FileDescriptionCreationStrategy(), new GeneratedDescriptionCreationStrategy()); } /** * Enrich the procedure description. * * @param desc * the description * @param procedure * the procedure * @param version * the version * @param format * the format * @param cache * the procedure cache * @param language * the language * @param session * the session * * @see HibernateProcedureEnrichment * @throws OwsExceptionReport * if the enrichment fails */ private void enrich(SosProcedureDescription desc, Procedure procedure, String version, String format, TimePeriod validTime, Map<String, Procedure> cache, Locale language, Session session) throws OwsExceptionReport { ProcedureDescriptionEnrichments enrichments = ProcedureDescriptionEnrichments.create().setIdentifier(procedure.getIdentifier()).setVersion(version) .setDescription(desc).setProcedureDescriptionFormat(format).setSession(session) .setValidTime(validTime).setProcedureCache(cache).setConverter(this).setLanguage(language); if (desc instanceof SensorML && ((SensorML) desc).isWrapper()) { enrichments.setDescription(desc).createValidTimeEnrichment().enrich(); for (AbstractProcess abstractProcess : ((SensorML) desc).getMembers()) { enrichments.setDescription(abstractProcess).enrichAll(); } } else { enrichments.enrichAll(); } } /** * Convert the description to another procedure description format. * * @param fromFormat * the source format * @param toFormat * the target format * @param description * the procedure description. * * @return the converted description * * @throws OwsExceptionReport * if conversion fails */ private SosProcedureDescription convert(String fromFormat, String toFormat, SosProcedureDescription description) throws OwsExceptionReport { try { Converter<SosProcedureDescription, Object> converter = ConverterRepository.getInstance().getConverter(fromFormat, toFormat); if (converter != null) { return converter.convert(description); } throw new ConverterException(String.format("No converter available to convert from '%s' to '%s'", fromFormat, toFormat)); } catch (ConverterException ce) { throw new NoApplicableCodeException().causedBy(ce).withMessage( "Error while processing data for DescribeSensor document!"); } } }