/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.wmc;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.storage.coverage.CoverageStore;
import org.geotoolkit.data.FeatureStore;
import org.geotoolkit.data.FeatureCollection;
import org.geotoolkit.data.query.QueryBuilder;
import org.geotoolkit.data.session.Session;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.util.NamesExt;
import org.apache.sis.geometry.Envelope2D;
import org.geotoolkit.map.CoverageMapLayer;
import org.geotoolkit.map.MapBuilder;
import org.geotoolkit.map.MapContext;
import org.geotoolkit.map.MapLayer;
import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.storage.DataStoreException;
import org.geotoolkit.style.DefaultDescription;
import org.geotoolkit.style.MutableStyle;
import org.geotoolkit.style.RandomStyleBuilder;
import org.geotoolkit.style.StyleConstants;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.iso.SimpleInternationalString;
import org.geotoolkit.wmc.xml.v110.*;
import org.apache.sis.xml.MarshallerPool;
import org.opengis.util.GenericName;
import org.opengis.geometry.Envelope;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.style.Description;
import org.opengis.util.FactoryException;
import javax.xml.bind.JAXBContext;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.storage.DataStore;
import org.geotoolkit.storage.DataStoreFactory;
import org.geotoolkit.storage.DataStores;
import org.apache.sis.referencing.crs.AbstractCRS;
import org.apache.sis.referencing.cs.AxesConvention;
/**
*
* @author Alexis Manin (Geomatys)
*/
public class WMCUtilities {
public static String getServiceId(String source) {
String id = null;
if (source.toLowerCase().contains("wms")) {
id = "wms";
}
if (source.toLowerCase().contains("wmts")) {
id = "wmts";
}
if (source.toLowerCase().contains("wfs")) {
id = "wfs";
}
return id;
}
/**
* Get a {@linkplain MarshallerPool marshaller pool} for the WMC binding.
*
* @return The {@linkplain MarshallerPool marshaller pool}.
* @throws JAXBException
*/
public static MarshallerPool getMarshallerPool() throws JAXBException {
return new MarshallerPool(JAXBContext.newInstance(
"org.geotoolkit.ogc.xml.exception:" +
"org.geotoolkit.wmc.xml.v110:" +
"org.geotoolkit.ogc.xml.v100"), null);
}
/**
* This method will get WMC informations to create a new valid
* {@link MapContext}.
*
* @param source : An {@link InputSream}, the WMC as an xml.
* @return A map context containing informations given by a wmc document.
* @throws JAXBException if the xml cannot be read.
*/
public static MapContext getMapContext(InputStream source) throws JAXBException {
final MarshallerPool pool = getMarshallerPool();
final Unmarshaller um = pool.acquireUnmarshaller();
Object o = um.unmarshal(source);
if (o instanceof JAXBElement) {
o = ((JAXBElement) o).getValue();
}
//Get needed markups
ViewContextType root = (ViewContextType) o;
final MapContext context = getMapContext(root);
pool.recycle(um);
return context;
}
/**
* Create a Geotk {@link MapContext} embeding layers described by given wmc.
*
* @param root The {@link ViewContextType}, root markup of the wmc.
* @return a {@link MapContext} containing layers extracted from wmc.
*/
public static MapContext getMapContext(ViewContextType root) {
ArgumentChecks.ensureNonNull("ViewContextType", root);
CoordinateReferenceSystem srs = CommonCRS.WGS84.normalizedGeographic();
final MapContext context = MapBuilder.createContext();
//Get needed markups
GeneralType general = root.getGeneral();
LayerListType layers = root.getLayerList();
if (general != null) {
//Retrieve enveloppe for the map context.
BoundingBoxType bbox = general.getBoundingBox();
try {
srs = AbstractCRS.castOrCopy(CRS.forCode(bbox.getSRS())).forConvention(AxesConvention.RIGHT_HANDED);
} catch (FactoryException ex) {
Logging.getLogger("org.geotoolkit.wmc").log(Level.SEVERE, null, ex);
}
final double width = bbox.getMaxx().subtract(bbox.getMinx()).doubleValue();
final double height = bbox.getMaxy().subtract(bbox.getMiny()).doubleValue();
Envelope aoi = new Envelope2D(srs, bbox.getMinx().doubleValue(), bbox.getMiny().doubleValue(), width, height);
SimpleInternationalString title = new SimpleInternationalString(general.getTitle());
SimpleInternationalString description = new SimpleInternationalString((general.getAbstract() == null) ? "No description" : general.getAbstract());
Description desc = new DefaultDescription(title, description);
context.setDescription(desc);
context.setAreaOfInterest(aoi);
}
//set context general values
context.setName(root.getId());
context.setCoordinateReferenceSystem(srs);
//fill context with layers
for (final LayerType layerType : layers.getLayer()) {
//build server from parameters.
final ServerType serverType = layerType.getServer();
final DataStore server;
final String serviceId = getServiceId(serverType.getService().value());
final GenericName layerName = NamesExt.valueOf(layerType.getName());
try {
final URL serviceURL = new URL(serverType.getOnlineResource().getHref());
final DataStoreFactory factory = DataStores.getFactoryById(serviceId);
final Map<String, Serializable> parameters = new HashMap<String, Serializable>();
parameters.put("identifier", serviceId);
parameters.put("version", serverType.getVersion());
parameters.put("url", serviceURL);
server = factory.open(parameters);
} catch (Exception ex) {
Logging.getLogger("org.geotoolkit.wmc").log(Level.SEVERE, null, ex);
continue;
}
if (server instanceof CoverageStore) {
final CoverageStore cs = (CoverageStore) server;
try {
for (GenericName n : cs.getNames()) {
if (n.tip().toString().equalsIgnoreCase(layerName.tip().toString())) {
final CoverageReference ref = cs.getCoverageReference(n);
final CoverageMapLayer mapLayer = MapBuilder.createCoverageLayer(ref,
GO2Utilities.STYLE_FACTORY.style(StyleConstants.DEFAULT_RASTER_SYMBOLIZER));
context.layers().add(mapLayer);
}
}
} catch (DataStoreException ex) {
Logging.getLogger("org.geotoolkit.wmc").log(Level.SEVERE, null, ex);
continue;
}
} else if (server instanceof FeatureStore) {
final FeatureStore wfs = (FeatureStore) server;
final Session storeSession = wfs.createSession(true);
final FeatureCollection collection = storeSession.getFeatureCollection(QueryBuilder.all(layerName));
final MutableStyle style = RandomStyleBuilder.createRandomVectorStyle(collection.getFeatureType());
final MapLayer layer = MapBuilder.createFeatureLayer(collection, style);
context.layers().add(layer);
}
}
return context;
}
}