geo-utility/src/main/java/org/gcube/spatial/data/geoutility/wms/WmsGetStyles.java

342 lines
10 KiB
Java

/**
*
*/
package org.gcube.spatial.data.geoutility.wms;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.gcube.spatial.data.geoutility.bean.WmsServiceBaseUri;
import org.gcube.spatial.data.geoutility.util.HttpRequestUtil;
import org.gcube.spatial.data.geoutility.util.NamespaceContextMap;
import org.gcube.spatial.data.geoutility.util.UrlEncoderUtil;
import org.gcube.spatial.data.geoutility.util.XpathParserUtil;
/**
* The Class WmsGetStyles.
*
* @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it
* Jan 22, 2016
*/
public class WmsGetStyles {
private int CONNECTION_TIMEOUT = 1000; //DEFAULT CONNECTION TIMEOUT
public static Logger logger = Logger.getLogger(WmsGetStyles.class);
protected HashMap<String, String> mappings;
protected NamespaceContextMap context;
private int responseCode;
private static final String GEOSERVER = "/geoserver";
/**
* Instantiates a new wms get styles.
*/
public WmsGetStyles() {
mappings = new HashMap<String, String>();
// mappings.put("xmlns", "http://www.opengis.net/sld");
mappings.put("sld", "http://www.opengis.net/sld");
mappings.put("ogc", "http://www.opengis.net/ogc");
mappings.put("gml", "http://www.opengis.net/gml");
mappings.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
context = new NamespaceContextMap(mappings);
}
/**
* Instantiates a new wms get styles.
*
* @param connectionTimeout the connection timeout sets a specified timeout value, in milliseconds, to be used when opening WMS GetStyles request.
*/
public WmsGetStyles(int connectionTimeout) {
this();
if(connectionTimeout>0)
CONNECTION_TIMEOUT = connectionTimeout;
}
/**
* Gets the styles from wms.
*
* @param urlConn the url conn
* @param layerName the layer name
* @return the styles from wms
*/
public List<String> getStylesFromWms(String urlConn, String layerName) {
List<String> styles = new ArrayList<String>();
String query = "";
try {
HashMap<String, String> parameters = new HashMap<String, String>();
parameters.put("request", "GetStyles");
parameters.put("layers", layerName);
parameters.put("service", "wms");
parameters.put("version", "1.1.1");
query = UrlEncoderUtil.encodeQuery(parameters);
WmsServiceBaseUri geosever = foundWmsServiceBaseUri(urlConn);
if(query==null || query.isEmpty())
return new ArrayList<String>();
logger.info("tentative get styles.. with query:" + query);
styles = openConnectionGetStyles(urlConn, query);
if(styles==null || styles.isEmpty()){
if(geosever.getScope()!=null && !geosever.getScope().isEmpty()){
logger.trace("trying to get styles with scope: "+geosever.getScope());
String newUrlConn = urlConn.replace("/"+geosever.getScope(), "");
logger.trace("new tentative get styles as base url without scope");
styles = openConnectionGetStyles(newUrlConn, query);
}
}
logger.info("WMS GetStyles returning: "+styles.toString());
return styles;
}catch (Exception e) {
logger.error("Error Exception getStylesFromWms from url:" + urlConn + ", query: "+query, e);
return styles;
}
}
/**
* Gets the styles.
*
* @param httpConnection the http connection
* @return a list of styles. The first element of list is default style if exists
* @throws IOException Signals that an I/O exception has occurred.
*/
private List<String> getStyles(HttpURLConnection httpConnection) throws IOException{
List<String> listStylesNames = new ArrayList<String>();
InputStream source = null;
int code = httpConnection.getResponseCode();
logger.trace("response code is " + code);
if (code == 200) {
source = httpConnection.getInputStream();
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
xPath.setNamespaceContext(context);
try{
String xmlGetStyles = IOUtils.toString(source);
String xpathExpression = "//sld:UserStyle[sld:IsDefault=1]/sld:Name"; //FIND DEFAULT STYLE NAME
List<String> defaultStylesList = XpathParserUtil.getTextFromXPathExpression(context, xmlGetStyles, xpathExpression);
LinkedHashMap<String, String> exclusiveStyles = new LinkedHashMap<String, String>();
//DEFAULT STYLE IS FOUND
if(defaultStylesList.size()>0 || !defaultStylesList.get(0).isEmpty()){
String defaultStyle = defaultStylesList.get(0);
exclusiveStyles.put(defaultStyle, defaultStyle);
}
xpathExpression = "//sld:UserStyle/sld:Name"; //FIND OTHER STYLES NAMES AND ADD INTO LIST
List<String> allStyles = XpathParserUtil.getTextFromXPathExpression(context, xmlGetStyles, xpathExpression);
for (String style : allStyles) {
exclusiveStyles.put(style, style);
}
listStylesNames.addAll(exclusiveStyles.keySet());
}catch (IOException e) {
logger.warn("IOException occurred when converting stream get styles");
}
} else {
return listStylesNames;
}
return listStylesNames;
}
/**
* Open connection get styles.
*
* @param urlConn the url conn
* @param query the query
* @return the list
*/
private List<String> openConnectionGetStyles(String urlConn, String query) {
URL url;
List<String> styles = new ArrayList<String>();
try {
url = new URL(urlConn + "?" + query);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(CONNECTION_TIMEOUT);
connection.setReadTimeout(CONNECTION_TIMEOUT + CONNECTION_TIMEOUT);
logger.trace("openConnectionGetStyles: " + url);
// Cast to a HttpURLConnection
if (connection instanceof HttpURLConnection) {
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
responseCode= httpConnection.getResponseCode();
if (responseCode == 200) {
styles = getStyles(httpConnection);
}else{
logger.warn("openConnectionGetStyles error, code = " + responseCode +", returning");
}
httpConnection.disconnect();
} else {
logger.error("error - not a http request!");
}
return styles;
} catch (SocketTimeoutException e) {
logger.error("Error SocketTimeoutException with url " + urlConn);
return styles;
} catch (MalformedURLException e) {
logger.error("Error MalformedURLException with url " + urlConn);
return styles;
} catch (IOException e) {
logger.error("Error IOException with url " + urlConn);
return styles;
} catch (Exception e) {
logger.error("Error Exception with url " + urlConn);
return styles;
}
}
/**
* Gets the geoserver base uri.
*
* @param uri the uri
* @return the input uri without the parameters, (the uri substring from start to index of '?' char (if exists)) if geoserver base url not found,
* geoserver url otherwise
*/
public WmsServiceBaseUri foundWmsServiceBaseUri(String uri){
WmsServiceBaseUri geoserverBaseUri = new WmsServiceBaseUri();
if(uri==null)
return geoserverBaseUri; //uri is empty
int end = uri.toLowerCase().lastIndexOf("?");
if(end==-1){
logger.trace("char ? not found in geoserver uri, return: "+uri);
return geoserverBaseUri; //uri is empty
}
String wmsServiceUri = uri.substring(0, uri.toLowerCase().lastIndexOf("?"));
int index = wmsServiceUri.lastIndexOf(GEOSERVER);
if(index>-1){ //FOUND the string GEOSERVER into URL
logger.trace("found geoserver string: "+GEOSERVER+" in "+wmsServiceUri);
//THERE IS SCOPE?
int lastSlash = wmsServiceUri.lastIndexOf("/");
int includeGeoserverString = index+GEOSERVER.length();
int endUrl = lastSlash>includeGeoserverString?lastSlash:includeGeoserverString;
logger.trace("indexs - lastSlash: ["+lastSlash+"], includeGeoserverString: ["+includeGeoserverString+"], endUrl: ["+endUrl+"]");
int startScope = includeGeoserverString+1<endUrl?includeGeoserverString+1:endUrl; //INCLUDE SLASH
String scope = wmsServiceUri.substring(startScope, endUrl);
logger.trace("geoserver url include scope: "+wmsServiceUri.substring(includeGeoserverString, endUrl));
geoserverBaseUri.setBaseUrl(wmsServiceUri.substring(0, endUrl));
geoserverBaseUri.setScope(scope);
return geoserverBaseUri;
}
else{
logger.trace("the string "+GEOSERVER+" not found in "+wmsServiceUri);
// GET LAST INDEX OF '/' AND CONCATENATE GEOSERVER
String urlConn = wmsServiceUri.substring(0, wmsServiceUri.lastIndexOf("/"))+GEOSERVER;
logger.trace("tentative concatenating string "+GEOSERVER+" at http url "+urlConn);
try {
if(HttpRequestUtil.urlExists(urlConn, false)){
logger.trace("url: "+urlConn+" - open a connection, return "+urlConn);
geoserverBaseUri.setBaseUrl(urlConn);
return geoserverBaseUri;
}
else
logger.trace("url: "+urlConn+" - not open a connection");
} catch (Exception e) {
logger.error("url connection is wrong at :"+urlConn);
}
String uriWithoutParameters = uri.substring(0, end);
logger.trace("url connection, returned: "+uriWithoutParameters);
geoserverBaseUri.setBaseUrl(uriWithoutParameters);
return geoserverBaseUri;
}
}
/**
* Gets the response code.
*
* @return the responseCode
*/
public int getResponseCode() {
return responseCode;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("WmsGetStyles [mappings=");
builder.append(mappings);
builder.append(", context=");
builder.append(context);
builder.append("]");
return builder.toString();
}
/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {
WmsGetStyles wmsStyles = new WmsGetStyles();
try {
List<String> list = wmsStyles.getStylesFromWms("http://www.fao.org/figis/geoserver/area/ows", "FAO_AREAS");
for (String string : list) {
System.out.println(string);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}