org.fao.geonet.api.records.editing.InspireValidatorUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.fao.geonet.api.records.editing.InspireValidatorUtils.java

Source

/*
 * Copyright (C) 2001-2016 Food and Agriculture Organization of the
 * United Nations (FAO-UN), United Nations World Food Programme (WFP)
 * and United Nations Environment Programme (UNEP)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
 * Rome - Italy. email: geonetwork@osgeo.org
 */

package org.fao.geonet.api.records.editing;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.fao.geonet.exceptions.ServiceNotFoundEx;
import org.fao.geonet.utils.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javassist.NotFoundException;

// A static style interface for methods in Inspire Service.
// Based on ETF Web API v.2 BETA
public class InspireValidatorUtils {

    /** The Constant USER_AGENT. */
    private final static String USER_AGENT = "Mozilla/5.0";

    /** The Constant ACCEPT. */
    private final static String ACCEPT = "application/json";

    /** The Constant CheckStatus_URL. */
    private final static String CheckStatus_URL = "/v2/status";

    /** The Constant ExecutableTestSuites_URL. */
    private final static String ExecutableTestSuites_URL = "/v2/ExecutableTestSuites";

    /** The Constant TestObjects_URL. */
    private final static String TestObjects_URL = "/v2/TestObjects";

    /** The Constant TestRuns_URL. */
    private final static String TestRuns_URL = "/v2/TestRuns";

    /** The Constant TESTS_TO_RUN. */
    private final static String[] TESTS_TO_RUN = {
            "Conformance class: INSPIRE Profile based on EN ISO 19115 and EN ISO 19119",
            "Conformance class: XML encoding of ISO 19115/19119 metadata" };

    /**
     * Check service status.
     *
     * @param endPoint the end point
     * @param client the client (optional) (optional)
     * @return true, if successful
     */
    public static boolean checkServiceStatus(String endPoint, CloseableHttpClient client) {

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }
        HttpGet request = new HttpGet(endPoint + CheckStatus_URL);

        // add request header
        request.addHeader("User-Agent", USER_AGENT);
        request.addHeader("Accept", ACCEPT);
        HttpResponse response;

        try {
            response = client.execute(request);
        } catch (Exception e) {
            Log.warning(Log.SERVICE, "Error calling INSPIRE service: " + endPoint, e);
            return false;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }

        if (response.getStatusLine().getStatusCode() == 200) {
            return true;
        } else {
            Log.warning(Log.SERVICE, "INSPIRE service not available: " + endPoint + CheckStatus_URL);
            return false;
        }
    }

    /**
     * Upload metadata file.
     *
     * @param endPoint the end point
     * @param xml the xml
     * @param client the client (optional)
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws JSONException the JSON exception
     */
    private static String uploadMetadataFile(String endPoint, InputStream xml, CloseableHttpClient client)
            throws IOException, JSONException {

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }

        try {

            HttpPost request = new HttpPost(endPoint + TestObjects_URL + "?action=upload");

            request.addHeader("User-Agent", USER_AGENT);
            request.addHeader("Accept", ACCEPT);

            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("fileupload", xml, ContentType.TEXT_XML, "file.xml");
            HttpEntity entity = builder.build();

            request.setEntity(entity);

            HttpResponse response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {

                ResponseHandler<String> handler = new BasicResponseHandler();
                String body = handler.handleResponse(response);
                JSONObject jsonRoot = new JSONObject(body);
                return jsonRoot.getJSONObject("testObject").getString("id");
            } else {
                Log.warning(Log.SERVICE, "WARNING: INSPIRE service HTTP response: "
                        + response.getStatusLine().getStatusCode() + " for " + TestObjects_URL);
                return null;
            }
        } catch (Exception e) {
            Log.error(Log.SERVICE, "Error calling INSPIRE service: " + endPoint, e);
            return null;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }
    }

    /**
     * Gets the tests.
     *
     * @param endPoint the end point
     * @param client the client (optional)
     * @return the tests
     */
    private static List<String> getTests(String endPoint, CloseableHttpClient client) {

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }

        try {

            HttpGet request = new HttpGet(endPoint + ExecutableTestSuites_URL);

            request.addHeader("User-Agent", USER_AGENT);
            request.addHeader("Accept", ACCEPT);
            HttpResponse response;

            response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {

                List<String> testList = new ArrayList<>();

                ResponseHandler<String> handler = new BasicResponseHandler();
                String body = handler.handleResponse(response);

                JSONObject jsonRoot = new JSONObject(body);

                JSONObject etfItemCollection = jsonRoot.getJSONObject("EtfItemCollection");
                JSONObject executableTestSuites = etfItemCollection.getJSONObject("executableTestSuites");
                JSONArray executableTestSuiteArray = executableTestSuites.getJSONArray("ExecutableTestSuite");

                for (int i = 0; i < executableTestSuiteArray.length(); i++) {
                    JSONObject test = executableTestSuiteArray.getJSONObject(i);

                    boolean ok = false;

                    for (String testToRun : TESTS_TO_RUN) {
                        ok = ok || testToRun.equals(test.getString("label"));
                    }

                    if (ok) {
                        testList.add(test.getString("id"));
                    }
                }

                return testList;
            } else {
                Log.warning(Log.SERVICE, "WARNING: INSPIRE service HTTP response: "
                        + response.getStatusLine().getStatusCode() + " for " + ExecutableTestSuites_URL);
                return null;
            }
        } catch (Exception e) {
            Log.error(Log.SERVICE, "Exception in INSPIRE service: " + endPoint, e);
            return null;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }
    }

    /**
     * Test run.
     *
     * @param endPoint the end point
     * @param fileId the file id
     * @param testList the test list
     * @param client the client (optional)
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws JSONException the JSON exception
     */
    private static String testRun(String endPoint, String fileId, List<String> testList, String testTitle,
            CloseableHttpClient client) throws IOException, JSONException {

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }

        try {
            HttpPost request = new HttpPost(endPoint + TestRuns_URL);

            JSONObject json = new JSONObject();
            JSONArray tests = new JSONArray();
            JSONObject argumets = new JSONObject();
            JSONObject testObject = new JSONObject();

            json.put("label", "TEST " + testTitle + " - " + System.currentTimeMillis());
            json.put("executableTestSuiteIds", tests);
            json.put("argumets", argumets);
            json.put("testObject", testObject);

            for (String test : testList) {
                tests.put(test);
            }

            argumets.put("files_to_test", ".*");
            argumets.put("tests_to_execute", ".*");

            testObject.put("id", fileId);

            StringEntity entity = new StringEntity(json.toString());
            request.setEntity(entity);

            request.setHeader("Content-type", ACCEPT);
            request.addHeader("User-Agent", USER_AGENT);
            request.addHeader("Accept", ACCEPT);
            HttpResponse response;

            response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == 201) {

                ResponseHandler<String> handler = new BasicResponseHandler();
                String body = handler.handleResponse(response);

                JSONObject jsonRoot = new JSONObject(body);
                String testId = jsonRoot.getJSONObject("EtfItemCollection").getJSONObject("testRuns")
                        .getJSONObject("TestRun").getString("id");

                return testId;
            } else {
                Log.warning(Log.SERVICE, "WARNING: INSPIRE service HTTP response: "
                        + response.getStatusLine().getStatusCode() + " for " + TestRuns_URL);
                return null;
            }

        } catch (Exception e) {
            Log.error(Log.SERVICE, "Exception in INSPIRE service: " + endPoint, e);
            return null;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }
    }

    /**
     * Checks if is ready.
     *
     * @param endPoint the end point
     * @param testId the test id
     * @param client the client (optional)
     * @return true, if is ready
     * @throws Exception
     */
    public static boolean isReady(String endPoint, String testId, CloseableHttpClient client) throws Exception {

        if (testId == null) {
            return false;
        }

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }

        try {

            HttpGet request = new HttpGet(endPoint + TestRuns_URL + "/" + testId + "/progress");

            request.addHeader("User-Agent", USER_AGENT);
            request.addHeader("Accept", ACCEPT);
            HttpResponse response;

            response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {

                ResponseHandler<String> handler = new BasicResponseHandler();
                String body = handler.handleResponse(response);

                JSONObject jsonRoot = new JSONObject(body);

                // Completed when estimated number of Test Steps is equal to completed Test Steps
                // Somehow this condition is necessary but not sufficient
                // so another check on real value of test is evaluated
                return jsonRoot.getInt("val") == jsonRoot.getInt("max")
                        & InspireValidatorUtils.isPassed(endPoint, testId, client) != null;

            } else if (response.getStatusLine().getStatusCode() == 404) {

                throw new NotFoundException("Test not found");

            } else {
                Log.warning(Log.SERVICE, "WARNING: INSPIRE service HTTP response: "
                        + response.getStatusLine().getStatusCode() + " for " + TestRuns_URL + "?view=progress");
            }
        } catch (NotFoundException e) {
            throw e;
        } catch (Exception e) {
            Log.error(Log.SERVICE, "Exception in INSPIRE service: " + endPoint, e);
            throw e;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }

        return false;
    }

    /**
     * Checks if is passed.
     *
     * @param endPoint the end point
     * @param testId the test id
     * @param client the client (optional)
     * @return the string
     * @throws Exception
     */
    public static String isPassed(String endPoint, String testId, CloseableHttpClient client) throws Exception {

        if (testId == null) {
            throw new Exception("");
        }

        boolean close = false;
        if (client == null) {
            client = HttpClients.createDefault();
            close = true;
        }

        try {

            HttpGet request = new HttpGet(endPoint + TestRuns_URL + "/" + testId);

            request.addHeader("User-Agent", USER_AGENT);
            request.addHeader("Accept", ACCEPT);
            HttpResponse response;

            response = client.execute(request);

            if (response.getStatusLine().getStatusCode() == 200) {

                ResponseHandler<String> handler = new BasicResponseHandler();
                String body = handler.handleResponse(response);

                JSONObject jsonRoot = new JSONObject(body);

                try {
                    return jsonRoot.getJSONObject("EtfItemCollection").getJSONObject("testRuns")
                            .getJSONObject("TestRun").getString("status");
                } catch (JSONException e) {
                    return null;
                }

            } else if (response.getStatusLine().getStatusCode() == 404) {

                throw new NotFoundException("Test not found");

            } else {
                Log.warning(Log.SERVICE, "WARNING: INSPIRE service HTTP response: "
                        + response.getStatusLine().getStatusCode() + " for " + TestRuns_URL + "?view=progress");
            }
        } catch (Exception e) {
            Log.error(Log.SERVICE, "Exception in INSPIRE service: " + endPoint, e);
            throw e;
        } finally {
            if (close) {
                try {
                    client.close();
                } catch (IOException e) {
                    Log.error(Log.SERVICE, "Error closing CloseableHttpClient: " + endPoint, e);
                }
            }
        }

        return null;
    }

    /**
     * Gets the report url.
     *
     * @param endPoint the end point
     * @param testId the test id
     * @return the report url
     */
    public static String getReportUrl(String endPoint, String testId) {

        return endPoint + TestRuns_URL + "/" + testId + ".html";
    }

    /**
     * Gets the report url in JSON format.
     *
     * @param endPoint the end point
     * @param testId the test id
     * @return the report url
     */
    public static String getReportUrlJSON(String endPoint, String testId) {

        return endPoint + TestRuns_URL + "/" + testId + ".json";
    }

    /**
     * Submit file.
     *
     * @param record the record
     * @return the string
     * @throws IOException Signals that an I/O exception has occurred.
     * @throws JSONException the JSON exception
     */
    public static String submitFile(String serviceEndpoint, InputStream record, String testTitle)
            throws IOException, JSONException {

        CloseableHttpClient client = HttpClients.createDefault();

        try {
            if (InspireValidatorUtils.checkServiceStatus(serviceEndpoint, client)) {
                // Get the tests to execute
                List<String> tests = InspireValidatorUtils.getTests(serviceEndpoint, client);
                // Upload file to test
                String testFileId = InspireValidatorUtils.uploadMetadataFile(serviceEndpoint, record, client);

                if (testFileId == null) {
                    Log.error(Log.SERVICE, "File not valid.", new Exception());
                    return null;
                }

                if (tests == null || tests.size() == 0) {
                    Log.error(Log.SERVICE,
                            "Default test sequence not supported. Check org.fao.geonet.api.records.editing.InspireValidatorUtils.TESTS_TO_RUN.",
                            new Exception());
                    return null;
                }
                // Return test id from Inspire service
                return InspireValidatorUtils.testRun(serviceEndpoint, testFileId, tests, testTitle, client);

            } else {
                ServiceNotFoundEx ex = new ServiceNotFoundEx(serviceEndpoint);
                Log.error(Log.SERVICE, "Service unavailable.", ex);
                throw ex;
            }
        } finally {
            client.close();
        }
    }

}