/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2010, 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;
* version 2.1 of the License.
*
* 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.wmts;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotoolkit.client.AbstractCoverageClient;
import org.geotoolkit.client.AbstractClientFactory;
import org.geotoolkit.storage.coverage.CoverageReference;
import org.geotoolkit.storage.coverage.CoverageType;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.parameter.Parameters;
import org.geotoolkit.security.ClientSecurity;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.client.Client;
import org.geotoolkit.storage.DataNode;
import org.geotoolkit.storage.DataStores;
import org.geotoolkit.storage.DefaultDataNode;
import org.geotoolkit.wmts.v100.GetCapabilities100;
import org.geotoolkit.wmts.v100.GetTile100;
import org.geotoolkit.wmts.xml.WMTSBindingUtilities;
import org.geotoolkit.wmts.xml.WMTSVersion;
import org.geotoolkit.wmts.xml.v100.Capabilities;
import org.geotoolkit.wmts.xml.v100.LayerType;
import org.opengis.util.GenericName;
import org.opengis.parameter.ParameterValueGroup;
/**
* Generates WMTS requests objects on a WMTS server.
*
* @author Guilhem Legal (Geomatys)
* @module
*/
public class WebMapTileClient extends AbstractCoverageClient implements Client{
private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.wmts");
private Capabilities capabilities;
private DataNode rootNode = null;
/**
* Defines the timeout in milliseconds for the GetCapabilities request.
* default is 10 seconds.
*/
private static final long TIMEOUT_GETCAPS = 10000L;
/**
* The request header map for this server
* that contains a set of key-value for HTTP header fields (user-agent, referer, accept-language...)
*/
private final Map<String,String> requestHeaderMap = new HashMap<>();
/**
* Builds a web map server with the given server url and version.
*
* @param serverURL The server base url.
* @param version A string representation of the service version.
* @throws IllegalArgumentException if the version specified is not applyable.
*/
public WebMapTileClient(final URL serverURL, final String version) {
this(serverURL, WMTSVersion.getVersion(version));
}
/**
* Builds a web map server with the given server url, a security and version.
*
* @param serverURL The server base url.
* @param security The server security.
* @param version The service version.
* @throws IllegalArgumentException if the version specified is not applyable.
*/
public WebMapTileClient(final URL serverURL, final ClientSecurity security, final WMTSVersion version) {
this(serverURL, security, version, null, false);
}
/**
* Builds a web map server with the given server url and version.
*
* @param serverURL The server base url.
* @param version The service version.
*/
public WebMapTileClient(final URL serverURL, final WMTSVersion version) {
this(serverURL, version, null);
}
/**
* Builds a web map server with the given server url, version and getCapabilities response.
*
* @param serverURL The server base url.
* @param version A string representation of the service version.
* @param capabilities A getCapabilities response.
* @throws IllegalArgumentException if the version specified is not applyable.
*/
public WebMapTileClient(final URL serverURL, final String version, final Capabilities capabilities) {
this(serverURL, WMTSVersion.getVersion(version), capabilities);
}
/**
* Builds a web map server with the given server url, version and getCapabilities response.
*
* @param serverURL The server base url.
* @param version A string representation of the service version.
* @param capabilities A getCapabilities response.
*/
public WebMapTileClient(final URL serverURL, final WMTSVersion version, final Capabilities capabilities) {
this(serverURL,null,version,capabilities,false);
}
/**
* Builds a web map server with the given server url, version and getCapabilities response.
*
* @param serverURL The server base url.
* @param security The server security.
* @param version A string representation of the service version.
* @param capabilities A getCapabilities response.
*/
public WebMapTileClient(final URL serverURL, final ClientSecurity security,
final WMTSVersion version, final Capabilities capabilities, boolean cacheImage) {
super(create(WMTSClientFactory.PARAMETERS, serverURL, security));
Parameters.getOrCreate(WMTSClientFactory.VERSION, parameters).setValue(version.getCode());
Parameters.getOrCreate(WMTSClientFactory.IMAGE_CACHE, parameters).setValue(cacheImage);
this.capabilities = capabilities;
}
public WebMapTileClient(ParameterValueGroup param){
super(param);
}
@Override
public WMTSClientFactory getFactory() {
return (WMTSClientFactory)DataStores.getFactoryById(WMTSClientFactory.NAME);
}
/**
* Returns the {@linkplain Capabilities capabilities} response for this request.
*
* @return {@linkplain Capabilities capabilities} response but never {@code null}.
* @see {@link #getCapabilities(long)}
*/
public Capabilities getCapabilities() {
return getCapabilities(TIMEOUT_GETCAPS);
}
/**
* Returns the {@linkplain Capabilities capabilities} response for this
* request.
*
* @param timeout Timeout in milliseconds
*/
public Capabilities getCapabilities(final long timeout) {
if (capabilities != null) {
return capabilities;
}
//Thread to prevent infinite request on a server
final Thread thread = new Thread() {
@Override
public void run() {
final GetCapabilitiesRequest getCaps = createGetCapabilities();
//Filling the request header map from the map of the layer's server
final Map<String, String> headerMap = getRequestHeaderMap();
getCaps.getHeaderMap().putAll(headerMap);
try {
capabilities = WMTSBindingUtilities.unmarshall(getCaps.getResponseStream(), getVersion());
} catch (Exception ex) {
capabilities = null;
try {
LOGGER.log(Level.WARNING, "Wrong URL, the server doesn't answer : " +
createGetCapabilities().getURL().toString(), ex);
} catch (MalformedURLException ex1) {
LOGGER.log(Level.WARNING, "Malformed URL, the server doesn't answer. ", ex1);
}
}
}
};
thread.start();
final long start = System.currentTimeMillis();
try {
thread.join(timeout);
} catch (InterruptedException ex) {
LOGGER.log(Level.WARNING, "The thread to obtain GetCapabilities doesn't answer.", ex);
}
if ((System.currentTimeMillis() - start) > timeout) {
LOGGER.log(Level.WARNING, "TimeOut error, the server takes too much time to answer. ");
}
return capabilities;
}
/**
* Returns the request version.
*/
public WMTSVersion getVersion() {
return WMTSVersion.getVersion(Parameters.value(WMTSClientFactory.VERSION, parameters));
}
public boolean getImageCache(){
return (Boolean)Parameters.getOrCreate(AbstractClientFactory.IMAGE_CACHE, parameters).getValue();
}
/**
* Returns the request object, in the version chosen.
*
* @throws IllegalArgumentException if the version requested is not supported.
*/
public GetTileRequest createGetTile() {
switch (getVersion()) {
case v100:
return new GetTile100(serverURL.toString(),getClientSecurity());
default:
throw new IllegalArgumentException("Version was not defined");
}
}
/**
* Returns the request object, in the version chosen.
*
* @throws IllegalArgumentException if the version requested is not supported.
*/
public GetCapabilitiesRequest createGetCapabilities() {
switch (getVersion()) {
case v100:
return new GetCapabilities100(serverURL.toString(),getClientSecurity());
default:
throw new IllegalArgumentException("Version was not defined");
}
}
/**
* Returns the request header map for this server.
* @return {@code Map}
*/
public Map<String,String> getRequestHeaderMap() {
return requestHeaderMap;
}
@Override
public synchronized DataNode getRootNode() throws DataStoreException {
if(rootNode == null){
rootNode = new DefaultDataNode();
final Capabilities capa = getCapabilities();
if(capa == null){
throw new DataStoreException("Could not get Capabilities.");
}
final List<LayerType> layers = capa.getContents().getLayers();
for(LayerType lt : layers){
final String name = lt.getIdentifier().getValue();
final GenericName nn = NamesExt.create(name);
final CoverageReference ref = new WMTSCoverageReference(this,nn,getImageCache());
rootNode.getChildren().add(ref);
}
}
return rootNode;
}
@Override
public void close() {
}
@Override
public CoverageReference create(GenericName name) throws DataStoreException {
throw new DataStoreException("Can not create new coverage.");
}
@Override
public void delete(GenericName name) throws DataStoreException {
throw new DataStoreException("Can not create new coverage.");
}
@Override
public CoverageType getType() {
return CoverageType.PYRAMID;
}
}