de.ii.xtraplatform.ogc.csw.client.CSWAdapter.java Source code

Java tutorial

Introduction

Here is the source code for de.ii.xtraplatform.ogc.csw.client.CSWAdapter.java

Source

/**
 * Copyright 2017 European Union, interactive instruments GmbH
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/**
 * bla
 */
package de.ii.xtraplatform.ogc.csw.client;

import com.google.common.collect.ImmutableMap;
import de.ii.xtraplatform.ogc.api.CSW;
import de.ii.xtraplatform.ogc.api.exceptions.ReadError;
import de.ii.xtraplatform.util.xml.XMLNamespaceNormalizer;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.BasicHttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author zahnen
 */
public class CSWAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CSWAdapter.class);
    private static final String DEFAULT_OPERATION = "default";

    private Map<String, Map<CSW.METHOD, URI>> urls;
    private CSW.VERSION version;
    private HttpClient httpClient;
    private HttpClient untrustedSslHttpClient;
    private XMLNamespaceNormalizer nsStore;
    private boolean ignoreTimeouts = false;
    private CSW.METHOD httpMethod;
    private boolean useBasicAuth = false;
    private String user;
    private String password;

    public CSWAdapter() {
        this.urls = new HashMap<>();
        this.nsStore = new XMLNamespaceNormalizer();
        this.httpMethod = CSW.METHOD.GET;
    }

    public CSWAdapter(String url) {
        this();
        try {
            // TODO: temporary basic auth hack
            // extract and remove credentials from url if existing
            //URI noAuthUri = this.extractBasicAuthCredentials(new URI(url));
            URI noAuthUri = parseAndCleanWfsUrl(url);
            Map<CSW.METHOD, URI> urls = new ImmutableMap.Builder<CSW.METHOD, URI>().put(CSW.METHOD.GET, noAuthUri)
                    .put(CSW.METHOD.POST, noAuthUri).build();

            this.urls.put(DEFAULT_OPERATION, urls);
        } catch (URISyntaxException ex) {
            //LOGGER.error(FrameworkMessages.INVALID_WFS_URL, url);
            throw new WebApplicationException();
        }
    }

    public void initialize(HttpClient httpClient, HttpClient untrustedSslhttpClient) {
        this.httpClient = httpClient;
        this.untrustedSslHttpClient = untrustedSslhttpClient;
    }

    public Map<String, Map<CSW.METHOD, URI>> getUrls() {
        return this.urls;
    }

    public void setUrls(Map<String, Map<CSW.METHOD, URI>> urls) {
        this.urls = urls;
    }

    public void addUrl(URI url, CSW.OPERATION op, CSW.METHOD method) {
        // TODO: remove toString
        if (!this.urls.containsKey(op.toString())) {
            Map<CSW.METHOD, URI> urls = new ImmutableMap.Builder<CSW.METHOD, URI>().put(method, url).build();
            this.urls.put(op.toString(), urls);
        }
    }

    public String getVersion() {
        return version != null ? version.toString() : null;
    }

    public void setVersion(String version) {
        CSW.VERSION v = CSW.VERSION.fromString(version);
        if (v != null) {
            if (this.version == null || v.isGreater(this.version)) {
                this.version = v;
                //LOGGER.debug(FrameworkMessages.VERSION_SET_TO, version);
            }
        }
    }

    public HttpEntity request(CSWOperation operation) {

        try {
            // TODO: POST or GET
            HttpResponse r;
            if (httpMethod == CSW.METHOD.POST)
                r = requestPOST(operation);
            else
                r = requestGET(operation);
            operation.setResponseHeaders(r.getAllHeaders());
            return r.getEntity();
        } catch (ParserConfigurationException e) {
            return null;
        }
    }

    private HttpResponse requestPOST(CSWOperation operation) throws ParserConfigurationException {

        URI url = findUrl(operation.getOperation(), CSW.METHOD.POST);

        HttpClient httpClient = url.getScheme().equals("https") ? this.untrustedSslHttpClient : this.httpClient;

        URIBuilder uri = new URIBuilder(url);

        String xml = operation.toXml(nsStore, version);

        LOGGER.debug("{}\n{}", uri, xml);

        HttpPost httpPost;
        HttpResponse response = null;

        try {
            httpPost = new HttpPost(uri.build());

            for (String key : operation.getRequestHeaders().keySet()) {
                httpPost.setHeader(key, operation.getRequestHeaders().get(key));
            }

            // TODO: temporary basic auth hack
            if (useBasicAuth) {
                String basic_auth = new String(Base64.encodeBase64((user + ":" + password).getBytes()));
                httpPost.addHeader("Authorization", "Basic " + basic_auth);
            }

            StringEntity xmlEntity = new StringEntity(xml, ContentType.create("text/plain", "UTF-8"));
            httpPost.setEntity(xmlEntity);

            response = httpClient.execute(httpPost, new BasicHttpContext());

            // check http status
            checkResponseStatus(response.getStatusLine().getStatusCode(), uri);

        } catch (SocketTimeoutException ex) {
            if (ignoreTimeouts) {
                //LOGGER.warn(FrameworkMessages.POST_REQUEST_TIMED_OUT_AFTER_MS_URL_REQUEST, HttpConnectionParams.getConnectionTimeout(httpClient.getParams()), uri.toString(), xml);
            }
            response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "");
            response.setEntity(new StringEntity("", ContentType.TEXT_XML));
        } catch (IOException ex) {
            //LOGGER.error(ERROR_IN_POST_REQUEST_TO_URL_REQUEST, uri.toString(), xml, ex);
            //LOGGER.debug("Error requesting URL: {}", uri.toString());

            try {
                if (!isDefaultUrl(uri.build(), CSW.METHOD.POST)) {

                    //LOGGER.info(FrameworkMessages.REMOVING_URL, uri.toString());
                    this.urls.remove(operation.getOperation().toString());

                    //LOGGER.info(FrameworkMessages.RETRY_WITH_DEFAULT_URL, this.urls.get("default"));
                    return requestPOST(operation);
                }
            } catch (URISyntaxException ex0) {
            }

            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL, uri.toString());
            throw new ReadError("Failed requesting URL: '{}'", uri);
        } catch (URISyntaxException ex) {
            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL, uri.toString());
            throw new ReadError("Failed requesting URL: '{}'", uri);
        } catch (ReadError ex) {
            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL, uri.toString());
            throw ex;
        }
        //LOGGER.debug(FrameworkMessages.WFS_REQUEST_SUBMITTED);
        return response;
    }

    public String getRequestUrl(CSWOperation operation) {
        try {
            URIBuilder uri = new URIBuilder(findUrl(operation.getOperation(), CSW.METHOD.GET));

            Map<String, String> params = operation.toKvp(nsStore, version);

            for (Map.Entry<String, String> param : params.entrySet()) {
                uri.addParameter(param.getKey(), param.getValue());
            }

            return uri.build().toString();
        } catch (URISyntaxException | ParserConfigurationException e) {
            return "";
        }
    }

    private HttpResponse requestGET(CSWOperation operation) throws ParserConfigurationException {
        URI url = findUrl(operation.getOperation(), CSW.METHOD.GET);

        HttpClient httpClient = url.getScheme().equals("https") ? this.untrustedSslHttpClient : this.httpClient;

        URIBuilder uri = new URIBuilder(url);

        Map<String, String> params = operation.toKvp(nsStore, version);

        for (Map.Entry<String, String> param : params.entrySet()) {
            uri.addParameter(param.getKey(), param.getValue());
        }
        //LOGGER.debug(FrameworkMessages.GET_REQUEST_OPERATION_URL, operation.toString(), uri.toString());

        boolean retried = false;
        HttpGet httpGet;
        HttpResponse response;

        try {

            // replace the + with %20
            String uristring = uri.build().toString();
            uristring = uristring.replaceAll("\\+", "%20");
            httpGet = new HttpGet(uristring);

            // TODO: temporary basic auth hack
            if (useBasicAuth) {
                String basic_auth = new String(Base64.encodeBase64((user + ":" + password).getBytes()));
                httpGet.addHeader("Authorization", "Basic " + basic_auth);
            }

            response = httpClient.execute(httpGet, new BasicHttpContext());

            // check http status
            checkResponseStatus(response.getStatusLine().getStatusCode(), uri);

        } catch (SocketTimeoutException ex) {
            if (ignoreTimeouts) {
                //LOGGER.warn(FrameworkMessages.GET_REQUEST_TIMED_OUT_AFTER_MS_URL_REQUEST, HttpConnectionParams.getConnectionTimeout(httpClient.getParams()), uri.toString());
            }
            response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "");
            response.setEntity(new StringEntity("", ContentType.TEXT_XML));
        } catch (IOException ex) {
            try {
                if (!isDefaultUrl(uri.build(), CSW.METHOD.GET)) {

                    //LOGGER.info(FrameworkMessages.REMOVING_URL, uri.toString());
                    this.urls.remove(operation.getOperation().toString());

                    //LOGGER.info(FrameworkMessages.RETRY_WITH_DEFAULT_URL, this.urls.get("default"));
                    return requestGET(operation);
                }
            } catch (URISyntaxException ex0) {
            }
            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL, uri.toString());
            throw new ReadError("Failed requesting URL: '{}'", uri);
        } catch (URISyntaxException ex) {
            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL, uri.toString());
            throw new ReadError("Failed requesting URL: '{}'", uri);
        }
        //LOGGER.debug(FrameworkMessages.WFS_REQUEST_SUBMITTED);
        return response;
    }

    private void checkResponseStatus(int status, URIBuilder uri) {
        if (status >= 400) {
            String reason = "No reason available";
            try {
                reason = status + " " + Response.Status.fromStatusCode(status).getReasonPhrase();
            } catch (Exception e) {
            }
            //LOGGER.error(FrameworkMessages.FAILED_REQUESTING_URL_REASON, uri.toString(), reason);
            ReadError re = new ReadError("Failed requesting URL: '{}'", uri);
            re.addDetail("Reason: " + reason);
            throw re;
        }
    }

    public XMLNamespaceNormalizer getNsStore() {
        return nsStore;
    }

    public void setNsStore(XMLNamespaceNormalizer nsStore) {
        this.nsStore = nsStore;
    }

    public void addNamespace(String namespaceURI) {
        nsStore.addNamespace(namespaceURI);
    }

    public void addNamespace(String prefix, String namespaceURI) {
        nsStore.addNamespace(prefix, namespaceURI);
    }

    public String retrieveNamespaceURI(String prefix) {
        return nsStore.getNamespaceURI(prefix);
    }

    public URI findUrl(CSW.OPERATION operation, CSW.METHOD method) {

        URI uri = this.urls.containsKey(operation.toString()) ? this.urls.get(operation.toString()).get(method)
                : this.urls.get("default").get(method);

        if (uri == null && method.equals(CSW.METHOD.GET)) {
            return this.urls.get("default").get(method);
        }

        return uri;
    }

    private boolean isDefaultUrl(URI uri, CSW.METHOD method) {
        URI defaultURI = this.urls.get("default").get(method);
        URI inputURI = uri;

        if (defaultURI.getHost().startsWith(inputURI.getHost())) {
            return true;
        }
        return false;
    }

    public void setIgnoreTimeouts(boolean ignoreTimeouts) {
        this.ignoreTimeouts = ignoreTimeouts;
    }

    public String getHttpMethod() {
        return httpMethod.toString();
    }

    public void setHttpMethod(String httpMethod) {
        this.httpMethod = CSW.METHOD.fromString(httpMethod);
    }

    public static URI parseAndCleanWfsUrl(String url) throws URISyntaxException {
        URI inUri = new URI(url.trim());
        URIBuilder outUri = new URIBuilder(inUri).removeQuery();

        if (inUri.getQuery() != null && !inUri.getQuery().isEmpty()) {
            for (String inParam : inUri.getQuery().split("&")) {
                String[] param = inParam.split("=");
                if (!CSW.hasKVPKey(param[0].toUpperCase())) {
                    outUri.addParameter(param[0], param[1]);
                }
            }
        }

        return outUri.build();
    }
}