/* * Constellation - An open source and standard compliant SDI * http://www.constellation-sdi.org * * Copyright 2014 Geomatys. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.constellation.ws; import org.constellation.ServiceDef.Specification; import org.constellation.business.ILayerBusiness; import org.constellation.business.IStyleBusiness; import org.constellation.configuration.ConfigurationException; import org.constellation.configuration.Language; import org.constellation.configuration.Languages; import org.constellation.configuration.Layer; import org.constellation.configuration.LayerContext; import org.constellation.configuration.TargetNotFoundException; import org.constellation.map.featureinfo.FeatureInfoUtilities; import org.constellation.provider.Data; import org.constellation.provider.DataProviders; import org.constellation.util.DataReference; import org.constellation.ws.security.SimplePDP; import org.geotoolkit.factory.FactoryNotFoundException; import org.geotoolkit.style.MutableStyle; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.xml.namespace.QName; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.logging.Level; import org.geotoolkit.util.NamesExt; import static org.geotoolkit.ows.xml.OWSExceptionCode.LAYER_NOT_DEFINED; import static org.geotoolkit.ows.xml.OWSExceptionCode.NO_APPLICABLE_CODE; import static org.geotoolkit.ows.xml.OWSExceptionCode.STYLE_NOT_DEFINED; import org.opengis.util.GenericName; /** * A super class for all the web service worker dealing with layers (WMS, WCS, WMTS, WFS, ...) * * @author Guilhem Legal (Geomatys) */ public abstract class LayerWorker extends AbstractWorker { @Inject private ILayerBusiness layerBusiness; @Inject protected IStyleBusiness styleBusiness; private LayerContext layerContext; protected final List<String> supportedLanguages = new ArrayList<>(); protected final String defaultLanguage; public LayerWorker(final String id, final Specification specification) { super(id, specification); isStarted = true; String defaultLanguageCandidate = null; try { final Object obj = serviceBusiness.getConfiguration(specification.name().toLowerCase(), id); if (obj instanceof LayerContext) { layerContext = (LayerContext) obj; final String sec = layerContext.getSecurity(); // Instantiaties the PDP only if a rule has been discovered. if (sec != null && !sec.isEmpty()) { pdp = new SimplePDP(sec); } final Languages languages = layerContext.getSupportedLanguages(); if (languages != null) { for (Language language : languages.getLanguages()) { supportedLanguages.add(language.getLanguageCode()); if (language.getDefault()) { defaultLanguageCandidate = language.getLanguageCode(); } } } // look for shiro accessibility final String sa = getProperty("shiroAccessible"); if (sa != null && !sa.isEmpty()) { shiroAccessible = Boolean.parseBoolean(sa); } // look for capabilities cache flag final String cc = getProperty("cacheCapabilities"); if (cc != null && !cc.isEmpty()) { cacheCapabilities = Boolean.parseBoolean(cc); } //Check FeatureInfo configuration (if exist) FeatureInfoUtilities.checkConfiguration(layerContext); applySupportedVersion(); } else { startError = "The layer context File does not contain a layerContext object"; isStarted = false; LOGGER.log(Level.WARNING, startError); } } catch (FactoryNotFoundException ex) { startError = ex.getMessage(); isStarted = false; LOGGER.log(Level.WARNING, startError, ex); } catch (ClassNotFoundException | ConfigurationException ex) { startError = "Custom FeatureInfo configuration error : " + ex.getMessage(); isStarted = false; LOGGER.log(Level.WARNING, startError, ex); } catch (CstlServiceException ex) { startError = "Error applying supported versions : " + ex.getMessage(); isStarted = false; LOGGER.log(Level.WARNING, startError, ex); } defaultLanguage = defaultLanguageCandidate; //listen to changes on the providers to clear the getcapabilities cache DataProviders.getInstance().addPropertyListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { refreshUpdateSequence(); clearCapabilitiesCache(); } }); } @PostConstruct public void init(){ } protected List<Layer> getConfigurationLayers(final String login, final List<GenericName> layerNames) { final List<Layer> layerConfigs = new ArrayList<>(); for (GenericName layerName : layerNames) { Layer l = getConfigurationLayer(layerName, login); layerConfigs.add(l); } return layerConfigs; } protected Layer getConfigurationLayer(final GenericName layerName, final String login) { if (layerName != null && layerName.tip().toString()!= null) { final QName qname = new QName(NamesExt.getNamespace(layerName), layerName.tip().toString()); return getConfigurationLayer(qname, login); } return null; } protected Layer getConfigurationLayer(final QName layerName, final String login) { try { return layerBusiness.getLayer(this.specification.name(), getId(), layerName.getLocalPart(), layerName.getNamespaceURI(), login); } catch (ConfigurationException e) { LOGGER.log(Level.FINE, "No layer is exactly named as queried. Search using alias will start now", e); } if (layerName != null) { final List<Layer> layers = getConfigurationLayers(login); for (Layer layer : layers) { if (layer.getName().equals(layerName) || (layer.getAlias() != null && layer.getAlias().equals(layerName.getLocalPart()))) { return layer; } } // we do a second round with missing namespace search for (Layer layer : layers) { if (layer.getName().getLocalPart().equals(layerName.getLocalPart())) { return layer; } } } return null; } protected List<QName> getConfigurationLayerNames(final String login) { final List<QName> result = new ArrayList<>(); final List<Layer> layers = getConfigurationLayers(login); for (Layer layer : layers) { result.add(layer.getName()); } return result; } /** * @param login * * @return map of additional informations for each layer declared in the * layer context. */ public List<Layer> getConfigurationLayers(final String login) { try { return layerBusiness.getLayers(this.specification.name().toLowerCase(), getId(), login); } catch (ConfigurationException ex) { LOGGER.log(Level.WARNING, "Error while getting layers", ex); } return new ArrayList<>(); } /** * Return all layers details in LayerProviders from there names. * @param login * @param layerNames * @return a list of LayerDetails * @throws CstlServiceException */ protected List<Data> getLayerReferences(final String login, final Collection<GenericName> layerNames) throws CstlServiceException { final List<Data> layerRefs = new ArrayList<>(); for (GenericName layerName : layerNames) { layerRefs.add(getLayerReference(login, layerName)); } return layerRefs; } protected Data getLayerReference(final Layer layer) throws CstlServiceException { return DataProviders.getInstance().get(NamesExt.create(layer.getName()), layer.getProviderID(), null); } protected Data getLayerReference(final String login, final QName layerName) throws CstlServiceException { return getLayerReference(login, NamesExt.create(layerName)); } /** * Search layer real name and return the LayerDetails from LayerProvider. * @param login * @param layerName * @return a LayerDetails * @throws CstlServiceException */ protected Data getLayerReference(final String login, final GenericName layerName) throws CstlServiceException { final Data layerRef; final DataProviders namedProxy = DataProviders.getInstance(); final NameInProvider fullName = layersContainsKey(login, layerName); if (fullName != null) { if (fullName.dataVersion != null) { layerRef = namedProxy.get(fullName.name, fullName.providerID, fullName.dataVersion); } else { layerRef = namedProxy.get(fullName.name, fullName.providerID); } if (layerRef == null) { throw new CstlServiceException("Unable to find the Layer named:{"+NamesExt.getNamespace(layerName) + '}' + layerName.tip().toString()+ " in the provider proxy", NO_APPLICABLE_CODE); } } else { throw new CstlServiceException("Unknown Layer name:" + layerName, LAYER_NOT_DEFINED); } return layerRef; } /** * We can't use directly layers.containsKey because it may miss the namespace or the alias. * @param login * @param name */ protected NameInProvider layersContainsKey(final String login, final GenericName name) { if (name == null) { return null; } final Layer directLayer = getConfigurationLayer(name, login); if (directLayer == null) { final List<QName> layerNames = getConfigurationLayerNames(login); if (layerNames == null) { return null; } //search with only localpart for (QName layerName : layerNames) { if (layerName.getLocalPart().equals(name.tip().toString())) { final Layer layerConfig = getConfigurationLayer(layerName, login); Date version = null; if (layerConfig.getVersion() != null) { version = new Date(layerConfig.getVersion()); } return new NameInProvider(layerName, layerConfig.getProviderID(), version); } } //search in alias if any for (QName l : layerNames) { final Layer layer = getConfigurationLayer(l, login); if (layer.getAlias() != null && !layer.getAlias().isEmpty()) { final String alias = layer.getAlias(); if (alias.equals(name.tip().toString())) { Date version = null; if (layer.getVersion() != null) { version = new Date(layer.getVersion()); } return new NameInProvider(l, layer.getProviderID(), version); } } } return null; } Date version = null; if (directLayer.getVersion() != null) { version = new Date(directLayer.getVersion()); } return new NameInProvider(directLayer.getName(), directLayer.getProviderID(), version); } protected MutableStyle getStyle(final DataReference styleReference) throws CstlServiceException { MutableStyle style; if (styleReference != null) { try { style = styleBusiness.getStyle(styleReference.getProviderId(), styleReference.getLayerId().tip().toString()); } catch (TargetNotFoundException e) { throw new CstlServiceException("Style provided: " + styleReference.getReference() + " not found.", STYLE_NOT_DEFINED); } } else { //no defined styles, use the favorite one, let the layer get it himself. style = null; } // final MutableStyle style; // if (styleName != null) { // //try to grab the style if provided // //a style has been given for this layer, try to use it // style = StyleProviders.getInstance().get(styleName.getLayerId().getLocalPart(), styleName.getProviderId()); // if (style == null) { // throw new CstlServiceException("Style provided: " + styleName.getReference() + " not found.", STYLE_NOT_DEFINED); // } // } else { // //no defined styles, use the favorite one, let the layer get it himself. // style = null; // } return style; } protected Layer getMainLayer() { if (layerContext == null) { return null; } return layerContext.getMainLayer(); } /** * {@inheritDoc} */ @Override public boolean isAuthorized(final String ip, final String referer) { return pdp.isAuthorized(ip, referer); } /** * {@inheritDoc} */ @Override public boolean isSecured() { return (pdp != null); } @Override protected final String getProperty(final String key) { if (layerContext != null && layerContext.getCustomParameters() != null) { return layerContext.getCustomParameters().get(key); } return null; } @Override public LayerContext getConfiguration() { return layerContext; } /** * Parse a Name from a string. * @param layerName * @return */ protected GenericName parseCoverageName(final String layerName) { final GenericName namedLayerName; if (layerName != null && layerName.lastIndexOf(':') != -1) { final String namespace = layerName.substring(0, layerName.lastIndexOf(':')); final String localPart = layerName.substring(layerName.lastIndexOf(':') + 1); namedLayerName = NamesExt.create(namespace, localPart); } else { namedLayerName = NamesExt.create(layerName); } return namedLayerName; } public static class NameInProvider { public GenericName name; public String providerID; public Date dataVersion; public NameInProvider(final GenericName name, final String providerID) { this(name, providerID, null); } public NameInProvider(final QName name, final String providerID) { this(NamesExt.create(name), providerID, null); } public NameInProvider(final QName name, final String providerID, final Date dataVersion) { this(NamesExt.create(name), providerID, dataVersion); } public NameInProvider(final GenericName name, final String providerID, final Date dataVersion) { this.name = name; this.providerID = providerID; this.dataVersion= dataVersion; } } }