/* * 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.admin; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import javax.imageio.spi.ServiceRegistry; import javax.inject.Inject; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; import com.google.common.base.Optional; import org.constellation.business.IDataBusiness; import org.constellation.business.ILayerBusiness; import org.constellation.configuration.ConfigurationException; import org.constellation.configuration.DataBrief; import org.constellation.configuration.DataSourceType; import org.constellation.configuration.LayerContext; import org.constellation.configuration.LayerSummary; import org.constellation.configuration.TargetNotFoundException; import org.constellation.dto.AddLayer; import org.constellation.database.api.ConstellationPersistenceException; import org.constellation.database.api.jooq.tables.pojos.CstlUser; import org.constellation.database.api.jooq.tables.pojos.Data; import org.constellation.database.api.jooq.tables.pojos.Layer; import org.constellation.database.api.jooq.tables.pojos.Provider; import org.constellation.database.api.jooq.tables.pojos.Service; import org.constellation.database.api.jooq.tables.pojos.Style; import org.constellation.database.api.repository.DataRepository; import org.constellation.database.api.repository.LayerRepository; import org.constellation.database.api.repository.ProviderRepository; import org.constellation.database.api.repository.ServiceRepository; import org.constellation.database.api.repository.StyleRepository; import org.constellation.database.api.repository.UserRepository; import org.constellation.generic.database.GenericDatabaseMarshallerPool; import org.constellation.ws.MapFactory; import org.constellation.ws.LayerSecurityFilter; import org.constellation.provider.DataProvider; import org.constellation.provider.DataProviders; import org.constellation.provider.configuration.ProviderParameters; import org.constellation.util.DataReference; import org.geotoolkit.factory.FactoryNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; /** * * @author Guilhem Legal (Geomatys) */ @Component("cstlLayerBusiness") @Primary public class LayerBusiness implements ILayerBusiness { @Inject private UserRepository userRepository; @Autowired private StyleRepository styleRepository; @Autowired private LayerRepository layerRepository; @Autowired private DataRepository dataRepository; @Autowired private ProviderRepository providerRepository; @Autowired private ServiceRepository serviceRepository; @Autowired private org.constellation.security.SecurityManager securityManager; @Inject private IDataBusiness dataBusiness; @Override @Transactional public void add(final AddLayer addLayerData) throws ConfigurationException { final String name = addLayerData.getLayerId(); // Prevents adding empty layer namespace, put null instead final String namespace = (addLayerData.getLayerNamespace() != null && addLayerData.getLayerNamespace().isEmpty()) ? null : addLayerData.getLayerNamespace(); final String providerId = addLayerData.getProviderId(); final String alias = addLayerData.getLayerAlias(); final String serviceId = addLayerData.getServiceId(); final String serviceType = addLayerData.getServiceType(); add(name, namespace, providerId, alias, serviceId, serviceType, null); } @Override @Transactional public void add(final String name, String namespace, final String providerId, final String alias, final String serviceId, final String serviceType, final org.constellation.configuration.Layer config) throws ConfigurationException { final Service service = serviceRepository.findByIdentifierAndType(serviceId, serviceType.toLowerCase()); if (service !=null) { if (namespace != null && namespace.isEmpty()) { // Prevents adding empty layer namespace, put null instead namespace = null; } // look for layer namespace if (namespace == null) { final DataProvider provider = DataProviders.getInstance().getProvider(providerId); if (provider != null) { namespace = ProviderParameters.getNamespace(provider); } } final Data data = dataRepository.findDataFromProvider(namespace, name, providerId); if(data == null) { throw new TargetNotFoundException("Unable to find data for namespace:" + namespace+" name:"+name+" provider:"+providerId); } boolean update = true; Layer layer = layerRepository.findByServiceIdAndLayerName(service.getId(), name, namespace); if (layer == null) { update = false; layer = new Layer(); } layer.setName(name); layer.setNamespace(namespace); layer.setAlias(alias); layer.setService(service.getId()); layer.setData(data.getId()); layer.setDate(System.currentTimeMillis()); Optional<CstlUser> user = userRepository.findOne(securityManager.getCurrentUserLogin()); if(user.isPresent()) { layer.setOwner(user.get().getId()); } final String configXml = getStringFromLayerConfig(config); layer.setConfig(configXml); int layerID; if (!update) { layerID = layerRepository.save(layer).getId(); } else { layerRepository.update(layer); layerID = layer.getId(); } for (int styleID : styleRepository.getStyleIdsForData(data.getId())) { styleRepository.linkStyleToLayer(styleID, layerID); } //style //update service ISO metadata // if (service.getMetadata() != null) { // try { // final DefaultMetadata servMeta = MetadataIOUtils.unmarshallMetadata(service.getMetadata()); // CstlMetadatas.addServiceMetadataLayer(servMeta, name); // final String srm = MetadataIOUtils.marshallMetadataToString(servMeta); // serviceRepository.updateIsoMetadata(service, servMeta.getFileIdentifier(), srm); // } catch (JAXBException e) { // throw new ConstellationPersistenceException(e); // } // } } else { throw new TargetNotFoundException("Unable to find a service:" + serviceId); } } @Override @Transactional public void updateLayerTitle(LayerSummary layer) throws ConfigurationException { layerRepository.updateLayerTitle(layer); } @Override @Transactional public void remove(final String spec, final String serviceId, final String name, final String namespace) throws ConfigurationException { final Service service = serviceRepository.findByIdentifierAndType(serviceId, spec.toLowerCase()); if (service != null) { final Layer layer = layerRepository.findByServiceIdAndLayerName(service.getId(), name, namespace); if (layer != null) { layerRepository.delete(layer.getId()); } else { throw new TargetNotFoundException("Unable to find a layer: {" + namespace + "}" + name); } } else { throw new TargetNotFoundException("Unable to find a service:" + serviceId); } } @Override @Transactional public void removeForService(final String spec, final String serviceId) throws ConfigurationException { final Service service = serviceRepository.findByIdentifierAndType(serviceId, spec.toLowerCase()); if (service != null) { final List<Layer> layers = layerRepository.findByServiceId(service.getId()); for (Layer layer : layers) { layerRepository.delete(layer.getId()); } } else { throw new TargetNotFoundException("Unable to find a service:" + serviceId); } } @Override @Transactional public void removeAll() { final List<Layer> layers = layerRepository.findAll(); for (Layer layer : layers) { layerRepository.delete(layer.getId()); } } /** * Returns list of {@link Layer} for given style id. * * @param styleId the given style id. * @return the list of {@link Data}. */ @Override public List<Layer> findByStyleId(final Integer styleId) { return layerRepository.getLayersByLinkedStyle(styleId); } /** * {@inheritDoc} */ @Override public List<LayerSummary> getLayerRefFromStyleId(final Integer styleId) { final List<LayerSummary> sumLayers = new ArrayList<>(); final List<Layer> layers = layerRepository.getLayersRefsByLinkedStyle(styleId); for(final Layer lay : layers) { final LayerSummary layerSummary = new LayerSummary(); layerSummary.setId(lay.getId()); layerSummary.setName(lay.getName()); sumLayers.add(layerSummary); } return sumLayers; } /** * {@inheritDoc} */ @Override public List<LayerSummary> getLayerSummaryFromStyleId(final Integer styleId) { final List<LayerSummary> sumLayers = new ArrayList<>(); final List<Layer> layers = findByStyleId(styleId); for(final Layer lay : layers){ final QName fullName = new QName(lay.getNamespace(), lay.getName()); final Data data = dataRepository.findById(lay.getData()); final DataBrief db = dataBusiness.getDataBrief(fullName, data.getProvider()); final LayerSummary layerSummary = new LayerSummary(); layerSummary.setId(lay.getId()); layerSummary.setName(data.getName()); layerSummary.setNamespace(data.getNamespace()); layerSummary.setAlias(lay.getAlias()); layerSummary.setTitle(lay.getTitle()); layerSummary.setType(db.getType()); layerSummary.setSubtype(db.getSubtype()); layerSummary.setDate(new Date(lay.getDate())); layerSummary.setOwner(db.getOwner()); layerSummary.setProvider(db.getProvider()); sumLayers.add(layerSummary); } return sumLayers; } @Override public List<org.constellation.configuration.Layer> getLayers(final String serviceType, final String serviceName, final String login) throws ConfigurationException { final List<org.constellation.configuration.Layer> response = new ArrayList<>(); final Service service = serviceRepository.findByIdentifierAndType(serviceName, serviceType.toLowerCase()); if (service != null) { final LayerContext context = readMapConfiguration(service.getConfig()); final MapFactory mapfactory = getMapFactory(context.getImplementation()); final LayerSecurityFilter securityFilter = mapfactory.getSecurityFilter(); final List<Layer> layers = layerRepository.findByServiceId(service.getId()); for (Layer layer : layers) { org.constellation.configuration.Layer config = toLayerConfig(login, securityFilter, layer); if (config != null) { response.add(config); } } } else { throw new TargetNotFoundException("Unable to find a service:" + serviceName); } return response; } /** * Get a single layer from service spec and identifier and layer name and namespace. * * @param spec service type * @param identifier service identifier * @param name layer name * @param namespace layer namespace * @param login login for security check * @return org.constellation.configuration.Layer * @throws ConfigurationException */ @Override public org.constellation.configuration.Layer getLayer(final String spec, final String identifier, final String name, final String namespace, final String login) throws ConfigurationException { final Service service = serviceRepository.findByIdentifierAndType(identifier, spec.toLowerCase()); if (service != null) { final LayerContext context = readMapConfiguration(service.getConfig()); final MapFactory mapfactory = getMapFactory(context.getImplementation()); final LayerSecurityFilter securityFilter = mapfactory.getSecurityFilter(); Layer layer = (namespace != null && !namespace.isEmpty())? layerRepository.findByServiceIdAndLayerName(service.getId(), name, namespace) : layerRepository.findByServiceIdAndLayerName(service.getId(), name); org.constellation.configuration.Layer layerConfig = toLayerConfig(login, securityFilter, layer); if (layerConfig != null) { return layerConfig; } else { throw new ConfigurationException("Not allowed to see this layer."); } } else { throw new TargetNotFoundException("Unable to find a service:" + identifier); } } /** * * @param login * @param securityFilter * @param layer * @return * @throws ConfigurationException */ private org.constellation.configuration.Layer toLayerConfig(String login, LayerSecurityFilter securityFilter, Layer layer) throws ConfigurationException { if (layer == null) return null; final Data data = dataRepository.findById(layer.getData()); final Provider provider = providerRepository.findOne(data.getProvider()); final QName name = new QName(layer.getNamespace(), layer.getName()); final List<Style> styles = styleRepository.findByLayer(layer); org.constellation.configuration.Layer layerConfig = readLayerConfiguration(layer.getConfig()); if (securityFilter.allowed(login, name)) { if (layerConfig == null) { layerConfig = new org.constellation.configuration.Layer(name); } layerConfig.setId(layer.getId()); // override with table values (TODO remove) layerConfig.setAlias(layer.getAlias()); layerConfig.setTitle(layer.getTitle()); layerConfig.setDate(new Date(layer.getDate())); layerConfig.setOwner(layer.getOwner()); layerConfig.setProviderID(provider.getIdentifier()); layerConfig.setProviderType(provider.getType()); // TODO layerDto.setAbstrac(); // TODO layerDto.setAttribution(null); // TODO layerDto.setAuthorityURL(null); // TODO layerDto.setCrs(null); // TODO layerDto.setDataURL(null); // TODO layerDto.setDimensions(null); // TODO layerDto.setFilter(null); // TODO layerDto.setGetFeatureInfoCfgs(null); // TODO layerDto.setKeywords(); // TODO layerDto.setMetadataURL(null); // TODO layerDto.setOpaque(Boolean.TRUE); for (Style style : styles) { final Provider styleProvider = providerRepository.findOne(style.getProvider()); DataReference styleProviderReference = DataReference.createProviderDataReference(DataReference.PROVIDER_STYLE_TYPE, styleProvider.getIdentifier(), style.getName()); layerConfig.getStyles().add(styleProviderReference); } // TODO layerDto.setTitle(null); // TODO layerDto.setVersion(); return layerConfig; } return null; } private LayerContext readMapConfiguration(final String xml) throws ConfigurationException { try { if (xml != null) { final Unmarshaller u = GenericDatabaseMarshallerPool.getInstance().acquireUnmarshaller(); final Object config = u.unmarshal(new StringReader(xml)); GenericDatabaseMarshallerPool.getInstance().recycle(u); return (LayerContext) config; } return null; } catch (JAXBException ex) { throw new ConfigurationException(ex); } } private org.constellation.configuration.Layer readLayerConfiguration(final String xml) throws ConfigurationException { try { if (xml != null) { final Unmarshaller u = GenericDatabaseMarshallerPool.getInstance().acquireUnmarshaller(); final Object config = u.unmarshal(new StringReader(xml)); GenericDatabaseMarshallerPool.getInstance().recycle(u); return (org.constellation.configuration.Layer) config; } return null; } catch (JAXBException ex) { throw new ConfigurationException(ex); } } /** * Select the good CSW factory in the available ones in function of the dataSource type. * * @param type * @return */ private MapFactory getMapFactory(final DataSourceType type) { final Iterator<MapFactory> ite = ServiceRegistry.lookupProviders(MapFactory.class); while (ite.hasNext()) { MapFactory currentFactory = ite.next(); if (currentFactory.factoryMatchType(type)) { return currentFactory; } } throw new FactoryNotFoundException("No Map factory has been found for type:" + type); } private String getStringFromLayerConfig(final org.constellation.configuration.Layer obj) { String config = null; if (obj != null) { try { final StringWriter sw = new StringWriter(); final Marshaller m = GenericDatabaseMarshallerPool.getInstance().acquireMarshaller(); m.marshal(obj, sw); GenericDatabaseMarshallerPool.getInstance().recycle(m); config = sw.toString(); } catch (JAXBException e) { throw new ConstellationPersistenceException(e); } } return config; } }