/*
* 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.provider.coveragesgroup.util;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.UnconvertibleObjectException;
import org.apache.sis.util.logging.Logging;
import org.constellation.ServiceDef;
import org.constellation.business.IStyleBusiness;
import org.constellation.provider.Data;
import org.constellation.provider.DataProvider;
import org.constellation.provider.DataProviders;
import org.constellation.provider.FeatureData;
import org.constellation.util.DataReference;
import org.geotoolkit.client.Client;
import org.geotoolkit.coverage.io.CoverageStoreException;
import org.geotoolkit.coverage.io.GridCoverageReader;
import org.geotoolkit.coverage.io.GridCoverageWriter;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.FeatureStore;
import org.geotoolkit.data.FeatureStoreRuntimeException;
import org.geotoolkit.data.memory.WrapFeatureCollection;
import org.geotoolkit.data.query.Query;
import org.geotoolkit.data.query.QueryBuilder;
import org.geotoolkit.data.session.Session;
import org.geotoolkit.data.wfs.WebFeatureClient;
import org.geotoolkit.feature.Feature;
import org.geotoolkit.map.CoverageMapLayer;
import org.geotoolkit.map.EmptyMapLayer;
import org.geotoolkit.map.FeatureMapLayer;
import org.geotoolkit.map.MapBuilder;
import org.geotoolkit.map.MapContext;
import org.geotoolkit.map.MapItem;
import org.geotoolkit.security.BasicAuthenticationSecurity;
import org.geotoolkit.security.ClientSecurity;
import org.geotoolkit.style.DefaultStyleFactory;
import org.geotoolkit.style.MutableStyle;
import org.geotoolkit.version.VersionControl;
import org.geotoolkit.version.VersioningException;
import org.geotoolkit.wms.WebMapClient;
import org.geotoolkit.wms.xml.WMSVersion;
import org.geotoolkit.wmts.WebMapTileClient;
import org.geotoolkit.wmts.xml.WMTSVersion;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import java.awt.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.constellation.configuration.TargetNotFoundException;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.storage.coverage.AbstractCoverageReference;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.storage.coverage.CoverageStore;
import org.geotoolkit.storage.coverage.CoverageStoreFinder;
import org.opengis.util.GenericName;
/**
* Allow to convert a {@linkplain org.constellation.provider.coveragesgroup.xml.MapContext mapContext} from the
* providers xml binding to a {@linkplain MapContext map context} from the map module.
*
* @author Cédric Briançon (Geomatys)
* @author Quentin Boileau (Geomatys)
*/
public final class ConvertersJaxbToGeotk {
private static final Logger LOGGER = Logging.getLogger("org.constellation.provider.coveragesgroup.util");
public static final String ORIGINAL_CONFIG = "original_config";
public static MapItem convertsMapLayer(final org.constellation.provider.coveragesgroup.xml.MapLayer mapLayer, final String login, final String password, final IStyleBusiness sb) {
ArgumentChecks.ensureNonNull("mapLayer", mapLayer);
ArgumentChecks.ensureNonNull("dataReference", mapLayer.getDataReference());
final String dataReference = mapLayer.getDataReference().getValue();
final DataReference ref = new DataReference(dataReference);
Object obj;
try {
obj = convertsDataReferenceToCoverageReference(ref, login, password);
} catch (UnconvertibleObjectException e) {
obj = null;
}
//try in features
if (obj == null) {
try {
obj = convertsDataReferenceToFeatureCollection(ref);
} catch (UnconvertibleObjectException e) {
obj = null;
LOGGER.log(Level.WARNING, "No data found for the given DataReference {0}.",ref.getReference());
}
}
MutableStyle style = null;
if (mapLayer.getStyleReference() != null) {
final String styleReference = mapLayer.getStyleReference().getValue();
style = convertsDataReferenceToMutableStyle(styleReference, sb);
}
final double opacity = (mapLayer.getOpacity() != null && mapLayer.getOpacity() <= 1 && mapLayer.getOpacity() >= 0) ? mapLayer.getOpacity() : 1;
if (obj instanceof FeatureCollection) {
final FeatureMapLayer layer = MapBuilder.createFeatureLayer((FeatureCollection) obj, style);
layer.setOpacity(opacity);
return layer;
} else if (obj instanceof CoverageReference) {
final CoverageMapLayer layer = MapBuilder.createCoverageLayer((CoverageReference) obj, style);
layer.setOpacity(opacity);
return layer;
}
final EmptyMapLayer emptyLayer = MapBuilder.createEmptyMapLayer();
emptyLayer.setName(dataReference);
emptyLayer.setOpacity(opacity);
return emptyLayer;
}
public static MapItem convertsMapItem(final org.constellation.provider.coveragesgroup.xml.MapItem mapItem, final String login, final String password, final IStyleBusiness sb) {
final MapItem mi = MapBuilder.createItem();
for (org.constellation.provider.coveragesgroup.xml.MapItem currentMapItem : mapItem.getMapItems()) {
if (currentMapItem instanceof org.constellation.provider.coveragesgroup.xml.MapLayer) {
final MapItem layer = convertsMapLayer((org.constellation.provider.coveragesgroup.xml.MapLayer)currentMapItem, login, password, sb);
if (layer != null) {
layer.setUserProperty(ORIGINAL_CONFIG, currentMapItem);
mi.items().add(layer);
}
} else {
mi.items().add(convertsMapItem(currentMapItem, login, password, sb));
}
}
return mi;
}
public static MapContext convertsMapContext(final org.constellation.provider.coveragesgroup.xml.MapContext mapContext, final String login, final String password, final IStyleBusiness sb) {
final MapContext mc = MapBuilder.createContext();
mc.setName(mapContext.getName());
mc.items().add(convertsMapItem(mapContext.getMapItem(), login, password, sb));
return mc;
}
/**
* Get MutableStyle from DataReference or a StyleReference.
* @param styleRefStr
* @return MutableStyle from DataReference if found, or default MutableStyle.
*/
private static MutableStyle convertsDataReferenceToMutableStyle(final String styleRefStr, final IStyleBusiness sb) {
String providerID = null;
String styleName = null;
MutableStyle style = null;
try {
DataReference dataReference = new DataReference(styleRefStr);
providerID = dataReference.getProviderOrServiceId();
styleName = dataReference.getLayerId().tip().toString();
} catch (IllegalArgumentException ex) {
//style reference is a simple StyleReference which contain only the name of the style.
styleName = styleRefStr;
}
try {
style = sb.getStyle(providerID, styleName);
} catch (TargetNotFoundException ex) {
LOGGER.log(Level.WARNING, "map Item style not found {" + providerID + "}" + styleName, ex);
}
return style != null ? style : new DefaultStyleFactory().style();
}
public static CoverageReference convertsDataReferenceToCoverageReference(final DataReference source, final String login, final String password) throws UnconvertibleObjectException {
final String dataType = source.getDataType();
final Date dataVersion = source.getDataVersion();
if (dataType.equals(DataReference.PROVIDER_STYLE_TYPE)) {
throw new UnconvertibleObjectException("Style provider not supported.");
}
CoverageReference coverageReference = null;
final GenericName layerName = source.getLayerId();
/*
* Search in Provider layers
*/
if (dataType.equals(DataReference.PROVIDER_LAYER_TYPE)) {
final String providerID = source.getProviderOrServiceId();
boolean providerFound = false;
boolean providerLayerFound = false;
//find provider
final Collection<DataProvider> providers = DataProviders.getInstance().getProviders();
for (DataProvider provider : providers) {
if (provider.getId().equals(providerID)) {
providerFound = true;
//open store with provider config
ParameterValueGroup config = provider.getSource();
config = config.groups("choice").get(0);
ParameterValueGroup factoryconfig = null;
for(GeneralParameterValue val : config.values()){
if(val instanceof ParameterValueGroup){
factoryconfig = (ParameterValueGroup) val;
break;
}
}
try {
final CoverageStore store = CoverageStoreFinder.open(factoryconfig);
if (store != null && store.handleVersioning()) {
final VersionControl control = store.getVersioning(layerName);
if (control.isVersioned() && dataVersion != null) {
coverageReference = store.getCoverageReference(layerName, control.getVersion(dataVersion));
}
}
if (store != null && coverageReference == null) {
coverageReference = store.getCoverageReference(layerName);
}
} catch (VersioningException e) {
throw new UnconvertibleObjectException(e.getMessage(), e);
} catch (DataStoreException e) {
throw new UnconvertibleObjectException(e.getMessage(), e);
}
if (coverageReference != null) {
providerLayerFound = true;
break;
}
}
}
if (!providerFound) {
throw new UnconvertibleObjectException("Provider id "+providerID+" not found.");
}
if (!providerLayerFound) {
throw new UnconvertibleObjectException("Layer name "+layerName+" not found.");
}
/*
* Search in Services
*/
} else if (dataType.equals(DataReference.SERVICE_TYPE)) {
final String serviceURL = source.getServiceURL();
final String serviceSpec = source.getServiceSpec();
if (serviceSpec.equalsIgnoreCase("WMS") || serviceSpec.equalsIgnoreCase("WMTS")) {
if (serviceURL != null) {
try {
final ClientSecurity security;
if (login != null && password != null) {
security = new BasicAuthenticationSecurity(login, password);
} else {
security = null;
}
final Client server;
if(serviceSpec.equalsIgnoreCase("WMS")){
server = new WebMapClient(new URL(serviceURL), security, WMSVersion.v130);
}else{
server = new WebMapTileClient(new URL(serviceURL), security, WMTSVersion.v100);
}
if (server instanceof CoverageStore) {
final CoverageStore coverageStore = (CoverageStore) server;
if (coverageStore != null && coverageStore.handleVersioning()) {
final VersionControl control = coverageStore.getVersioning(layerName);
if (control.isVersioned() && dataVersion != null) {
coverageReference = coverageStore.getCoverageReference(layerName, control.getVersion(dataVersion));
}
}
if (coverageStore != null && coverageReference == null) {
coverageReference = coverageStore.getCoverageReference(layerName);
}
} else {
throw new UnconvertibleObjectException("Server is not a coverageStore.");
}
} catch (VersioningException e) {
throw new UnconvertibleObjectException(e.getMessage(), e);
} catch (DataStoreException ex) {
throw new UnconvertibleObjectException(ex);
} catch (MalformedURLException ex) {
throw new UnconvertibleObjectException(ex);
}
} else {
throw new UnconvertibleObjectException("Service URL unknow.");
}
} else {
throw new UnconvertibleObjectException("Service specification should be a WMS or WMTS service.");
}
}
if (coverageReference == null) {
throw new UnconvertibleObjectException("Data no found for : "+source.getReference());
}
return new CoverageReferenceWrapper(source.getReference(), coverageReference);
}
public static FeatureCollection convertsDataReferenceToFeatureCollection(final DataReference source) throws UnconvertibleObjectException {
final String dataType = source.getDataType();
final Date dataVersion = source.getDataVersion();
if (dataType.equals(DataReference.PROVIDER_STYLE_TYPE)) {
throw new UnconvertibleObjectException("Style provider not supported.");
}
FeatureCollection featureColl = null;
final GenericName layerName = source.getLayerId();
// build query
final QueryBuilder builder = new QueryBuilder();
builder.setTypeName(layerName);
if (dataVersion != null) {
builder.setVersionDate(dataVersion);
}
final Query query = builder.buildQuery();
/*
* Search in Provider layers
*/
if (dataType.equals(DataReference.PROVIDER_LAYER_TYPE)) {
final String providerID = source.getProviderOrServiceId();
boolean providerFound = false;
boolean providerLayerFound = false;
//find provider
final Collection<DataProvider> providers = DataProviders.getInstance().getProviders();
for (DataProvider provider : providers) {
if (provider.getId().equals(providerID)) {
providerFound = true;
final Data layerDetails = provider.get(layerName);
if (layerDetails != null && layerDetails instanceof FeatureData) {
final FeatureData fLayerDetail = (FeatureData) layerDetails;
final FeatureStore store = fLayerDetail.getStore();
if (store != null) {
final Session session = store.createSession(true);
featureColl = session.getFeatureCollection(query);
providerLayerFound = true;
break;
}
}
}
}
if (!providerFound) {
throw new UnconvertibleObjectException("Provider id "+providerID+" not found.");
}
if (!providerLayerFound) {
throw new UnconvertibleObjectException("Layer name "+layerName+" not found.");
}
/*
* Search in Services
*/
} else if (dataType.equals(DataReference.SERVICE_TYPE)) {
final String serviceURL = source.getServiceURL();
final String serviceSpec = source.getServiceSpec();
final String serviceId = source.getProviderOrServiceId();
if (serviceSpec.equalsIgnoreCase("WFS")) {
if (serviceURL != null) {
try {
final Client server = new WebFeatureClient(new URL(serviceURL), ServiceDef.WFS_1_1_0.version.toString());
if (server instanceof FeatureStore) {
final FeatureStore datastore = (FeatureStore) server;
final Session session = datastore.createSession(true);
featureColl = session.getFeatureCollection(query);
} else {
throw new UnconvertibleObjectException("Server is not a datastore.");
}
} catch (MalformedURLException ex) {
throw new UnconvertibleObjectException(ex);
}
} else {
throw new UnconvertibleObjectException("Service URL unknow.");
}
} else {
throw new UnconvertibleObjectException("Service specification should be a WFS service.");
}
}
if (featureColl == null) {
throw new UnconvertibleObjectException("Data no found for : "+source.getReference());
}
return new ReferenceCollectionWrapper(featureColl, source.getReference());
}
/**
* Private internal class that wrap a FeatureCollection into another with a specified identifier.
*/
private static class ReferenceCollectionWrapper extends WrapFeatureCollection {
private String referenceId;
public ReferenceCollectionWrapper(final FeatureCollection originalFC, final String collectionId) {
super(originalFC);
this.referenceId = collectionId;
}
@Override
public String getID() {
return referenceId;
}
@Override
protected Feature modify(Feature original) throws FeatureStoreRuntimeException {
return original;
}
}
/**
* Class that wrap a CoverageReference into another with a specified identifier.
*
* @author Quentin Boileau (Geomatys)
*/
private static class CoverageReferenceWrapper extends AbstractCoverageReference {
private final CoverageReference reference;
private final String name;
public CoverageReferenceWrapper(final String name, final CoverageReference ref) {
super(ref.getStore(), NamesExt.create(name));
this.name = name;
this.reference = ref;
}
@Override
public GridCoverageReader acquireReader() throws CoverageStoreException {
return reference.acquireReader();
}
@Override
public GridCoverageWriter acquireWriter() throws CoverageStoreException {
return reference.acquireWriter();
}
@Override
public boolean isWritable() throws DataStoreException {
return reference.isWritable();
}
@Override
public Image getLegend() throws DataStoreException {
return reference.getLegend();
}
@Override
public int getImageIndex() {
return reference.getImageIndex();
}
}
}