it.greenvulcano.gvesb.api.controller.GvConfigurationControllerRest.java Source code

Java tutorial

Introduction

Here is the source code for it.greenvulcano.gvesb.api.controller.GvConfigurationControllerRest.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2016 GreenVulcano ESB Open Source Project.
 * All rights reserved.
 *
 * This file is part of GreenVulcano ESB.
 *
 * GreenVulcano ESB 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 3 of the License, or
 * (at your option) any later version.
 *
 * GreenVulcano ESB 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with GreenVulcano ESB. If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package it.greenvulcano.gvesb.api.controller;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.Multipart;
import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.fasterxml.jackson.core.JsonProcessingException;

import it.greenvulcano.configuration.XMLConfig;
import it.greenvulcano.configuration.XMLConfigException;
import it.greenvulcano.gvesb.GVConfigurationManager;
import it.greenvulcano.gvesb.GVConfigurationManager.Authority;
import it.greenvulcano.gvesb.api.dto.ServiceDTO;
import it.greenvulcano.util.xml.XMLUtils;

@CrossOriginResourceSharing(allowAllOrigins = true, allowCredentials = true, exposeHeaders = { "Content-Type",
        "Content-Range", "X-Auth-Status" })
public class GvConfigurationControllerRest extends BaseControllerRest {
    private final static Logger LOG = LoggerFactory.getLogger(GvConfigurationControllerRest.class);

    private final DocumentBuilder documentBuilder;
    private GVConfigurationManager gvConfigurationManager;

    public GvConfigurationControllerRest() throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setValidating(true);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/namespaces", false);
        documentBuilderFactory.setFeature("http://xml.org/sax/features/validation", false);
        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
        documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        documentBuilder = documentBuilderFactory.newDocumentBuilder();
    }

    public void setConfigurationManager(GVConfigurationManager gvConfigurationManager) {
        this.gvConfigurationManager = gvConfigurationManager;
    }

    @GET
    @Path("/configuration/")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getConfigurationHistory() {

        JSONArray history = new JSONArray();

        try {
            Properties descriptions = getConfDescriptionProperties();

            gvConfigurationManager.getHistory().stream().filter(fn -> !fn.getName().equals("history.properties"))
                    .map(f -> {
                        JSONObject configEntry = new JSONObject();
                        String id = f.getName().split("\\.(?=[^\\.]+$)")[0];
                        configEntry.put("id", id);
                        configEntry.put("time", f.lastModified());
                        configEntry.put("description", descriptions.getProperty(id));

                        return configEntry;
                    }).forEach(history::put);
        } catch (IOException e) {
            LOG.error("Failed to retrieve configuration history", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build());

        }

        return Response.ok(history.toString()).build();
    }

    @POST
    @Path("/configuration/{configId}/{description}")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void installConfiguration(@PathParam("configId") String id, @PathParam("description") String description,
            @Multipart(value = "gvconfiguration") Attachment config) {

        try {
            Properties descriptions = getConfDescriptionProperties();

            File currentConfig = new File(XMLConfig.getBaseConfigPath());
            if (id.equals(currentConfig.getName()) && !id.endsWith("-debug")) {
                throw new WebApplicationException(Response.status(Response.Status.CONFLICT).build());
            }

            MediaType contentType = Optional.ofNullable(config.getContentType())
                    .orElse(MediaType.APPLICATION_OCTET_STREAM_TYPE);

            switch (contentType.getSubtype()) {

            case "zip":
            case "x-zip-compressed":

                try (InputStream inputData = config.getDataHandler().getInputStream()) {

                    gvConfigurationManager.install(id, IOUtils.toByteArray(inputData));
                    descriptions.setProperty(id, description);
                    saveConfDescriptionProperties(descriptions);

                } catch (IllegalStateException e) {
                    LOG.error("Failed to install configuraton, operation already in progress", e);
                    throw new WebApplicationException(
                            Response.status(Response.Status.SERVICE_UNAVAILABLE).entity(e.getMessage()).build());

                } catch (Exception e) {
                    LOG.error("Failed to install configuraton, something bad appened", e);
                    throw new WebApplicationException(
                            Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build());

                }

                break;

            default:
                throw new WebApplicationException(Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).build());

            }
        } catch (FileNotFoundException e) {
            //TODO: perhaps it is better to allow uploading even if the descriptions data are not found
            LOG.error("Failed to upload configuraton, something bad appened", e);
        } catch (IOException e) {
            //TODO: perhaps it is better to allow uploading even if the descriptions data are not found
            LOG.error("Failed to upload configuraton, something bad appened", e);
        }

    }

    @DELETE
    @Path("/configuration/{configId}")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void deleteConfiguration(@PathParam("configId") String id) {
        try {
            Properties descriptions = getConfDescriptionProperties();

            gvConfigurationManager.delete(id);
            descriptions.remove(id);
            saveConfDescriptionProperties(descriptions);

        } catch (Exception e) {
            //TODO: perhaps it is better to allow deleting even if the descriptions data are not found
            LOG.error("Failed to delete configuraton, something bad appened", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build());

        }
    }

    @GET
    @Path("/configuration/{configId}/GVCore.xml")
    @Produces(MediaType.APPLICATION_XML)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getArchivedConfig(@PathParam("configId") String id) {

        try {
            byte[] gvcore = gvConfigurationManager.extract(id, "GVCore.xml");
            return Response.ok(gvcore).build();
        } catch (Exception e) {
            if (e.getCause() instanceof FileNotFoundException) {
                throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                        .entity("<error><![CDATA[File not found: " + id + "/GVCore.xml]]></error>").build());
            }

            LOG.error("File to retrieve GVCore.xml in " + id, e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE)
                    .entity("<error><![CDATA[" + e.getMessage() + "]]></error>").build());
        }

    }

    @GET
    @Path("/configuration/{configId}/properties")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getArchivedConfigProperties(@PathParam("configId") String id) {
        Response response = null;

        try {
            byte[] gvcore = gvConfigurationManager.extract(id, "GVCore.xml");
            if (gvcore != null && gvcore.length > 0) {

                JSONArray properties = new JSONArray();

                String xml = new String(gvcore, "UTF-8");

                String pattern = "xmlp\\{\\{([-a-zA-Z0-9._]+)\\}\\}";
                Pattern p = Pattern.compile(pattern);
                Matcher m = p.matcher(xml);

                while (m.find()) {
                    properties.put(m.group(1));
                }
                response = Response.ok(properties.toString()).build();
            }
        } catch (Exception e) {
            LOG.error("Error reading services configuration", e);
            response = Response.status(Response.Status.NOT_FOUND).build();
        }

        return response;
    }

    @GET
    @Path("/configuration/{configId}")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getArchivedConfigServices(@PathParam("configId") String id) {

        try {
            byte[] gvcore = gvConfigurationManager.extract(id, "GVCore.xml");

            if (gvcore != null && gvcore.length > 0) {

                Document gvcoreDocument = documentBuilder.parse(new ByteArrayInputStream(gvcore));

                NodeList serviceNodes = XMLConfig.getNodeList(gvcoreDocument, "//Service");

                Map<String, ServiceDTO> services = IntStream.range(0, serviceNodes.getLength())
                        .mapToObj(serviceNodes::item).map(ServiceDTO::buildServiceFromConfig)
                        .filter(Optional::isPresent).map(Optional::get)
                        .collect(Collectors.toMap(ServiceDTO::getIdService, Function.identity()));

                LOG.debug("Services found " + serviceNodes.getLength());
                return Response.ok(toJson(services)).build();

            }

            return Response.status(Response.Status.NOT_FOUND).build();

        } catch (XMLConfigException | JsonProcessingException xmlConfigException) {
            LOG.error("Error reading services configuration", xmlConfigException);
            throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(toJson(xmlConfigException)).build());
        } catch (Exception e) {
            LOG.error("Error reading services configuration", e);
            return Response.status(Response.Status.NOT_FOUND).build();

        }

    }

    @GET
    @Path("/configuration/{configId}/{serviceId}")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getArchivedConfigServices(@PathParam("configId") String id,
            @PathParam("serviceId") String service) {

        try {
            byte[] gvcore = gvConfigurationManager.extract(id, "GVCore.xml");
            if (gvcore != null && gvcore.length > 0) {

                Document gvcoreDocument = documentBuilder.parse(new ByteArrayInputStream(gvcore));

                Node serviceNode = Optional
                        .ofNullable(XMLConfig.getNode(gvcoreDocument, "//Service[@id-service='" + service + "']"))
                        .orElseThrow(NoSuchElementException::new);

                ServiceDTO svc = ServiceDTO.buildServiceFromConfig(serviceNode)
                        .orElseThrow(NoSuchElementException::new);

                return Response.ok(toJson(svc)).build();
            }

            return Response.status(Response.Status.NOT_FOUND).build();

        } catch (NoSuchElementException noSuchElementException) {
            throw new WebApplicationException(
                    Response.status(Response.Status.NOT_FOUND).entity("Service not found").build());

        } catch (XMLConfigException | JsonProcessingException xmlConfigException) {
            LOG.error("Error reading services configuration", xmlConfigException);
            throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(toJson(xmlConfigException)).build());
        } catch (Exception e) {
            LOG.error("Error reading services configuration", e);
            return Response.status(Response.Status.NOT_FOUND).build();

        }

    }

    @GET
    @Path("/configuration/{configId}/{serviceId}/{operationId}")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getArchivedConfigFlows(@PathParam("configId") String id, @PathParam("serviceId") String service,
            @PathParam("operationId") String operation) {

        try {
            byte[] gvcore = gvConfigurationManager.extract(id, "GVCore.xml");
            if (gvcore != null && gvcore.length > 0) {

                Document gvcoreDocument = documentBuilder.parse(new ByteArrayInputStream(gvcore));

                Node operationNode = Optional
                        .ofNullable(XMLConfig.getNode(gvcoreDocument,
                                "//Service[@id-service='" + service + "']/Operation[@name='" + operation + "']"))
                        .orElseThrow(NoSuchElementException::new);

                byte[] operationNodeData = XMLUtils.serializeDOMToByteArray_S(operationNode);

                String response = XML.toJSONObject(new String(operationNodeData), true).toString();

                return Response.ok(response).build();
            }

            return Response.status(Response.Status.NOT_FOUND).build();

        } catch (NoSuchElementException noSuchElementException) {
            throw new WebApplicationException(
                    Response.status(Response.Status.NOT_FOUND).entity("Service not found").build());

        } catch (XMLConfigException | JsonProcessingException xmlConfigException) {
            LOG.error("Error reading services configuration", xmlConfigException);
            throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(toJson(xmlConfigException)).build());
        } catch (Exception e) {
            return Response.status(Response.Status.NOT_FOUND).build();

        }

    }

    @GET
    @Path("/deploy")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER, Authority.GUEST })
    public Response getConfigurationInfo() {
        File currentConfig = new File(XMLConfig.getBaseConfigPath());

        if (currentConfig.exists()) {

            JSONObject configInfo = new JSONObject();
            configInfo.put("id", currentConfig.getName());
            configInfo.put("path", currentConfig.getParent());
            configInfo.put("time", currentConfig.lastModified());

            return Response.ok(configInfo.toString()).build();
        } else {
            return Response.status(Status.NOT_FOUND).build();
        }

    }

    @PUT
    @Path("/deploy")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void reloadConfiguraiton() {
        try {
            gvConfigurationManager.reload();
        } catch (XMLConfigException e) {
            LOG.error("Export failed", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build());
        }
    }

    @GET
    @Path("/deploy/export")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response exportConfiguration() {
        try {
            String currentConfig = gvConfigurationManager.getCurrentConfigurationName();
            return Response.ok(gvConfigurationManager.export(currentConfig))
                    .header("Content-Disposition", "attachment; filename=" + currentConfig + ".zip").build();

        } catch (IOException e) {
            LOG.error("Export failed", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build());
        }

    }

    @GET
    @Path("/deploy/export/{configId}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response exportConfiguration(@PathParam("configId") String id) {
        try {
            //String selectedConfig = id;
            return Response.ok(gvConfigurationManager.export(id))
                    .header("Content-Disposition", "attachment; filename=" + id + ".zip").build();

        } catch (IOException e) {
            LOG.error("Export failed", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build());
        }

    }

    @POST
    @Path("/deploy/{configId}")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void deploy(@PathParam("configId") String id) {

        try {
            gvConfigurationManager.deploy(id);
            gvConfigurationManager.reload();

        } catch (IllegalStateException e) {
            LOG.error("Deploy failed, a deploy is already in progress", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.SERVICE_UNAVAILABLE).entity(e.getMessage()).build());

        } catch (Exception e) {
            LOG.error("Deploy failed, something bad appened", e);
            throw new WebApplicationException(
                    Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build());

        }
    }

    @GET
    @Path("/deploy/xml")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getConfigurationFileList() {
        JSONArray files = new JSONArray(XMLConfig.getLoadedFiles());
        return Response.ok(files.toString()).build();
    }

    @GET
    @Path("/deploy/xml/{name}")
    @Produces(MediaType.APPLICATION_XML)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Document getConfigurationFile(@PathParam("name") String name) {

        Document document = null;

        try {
            document = XMLConfig.getDocument(name);
        } catch (XMLConfigException e) {
            if (e.getCause() instanceof FileNotFoundException) {
                throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                        .entity("<error><![CDATA[File not found: " + name + "]]></error>").build());
            }

            LOG.error("Failed to retrieve configuration file " + name, e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE)
                    .entity("<error><![CDATA[" + e.getMessage() + "]]></error>").build());
        }

        if (Objects.isNull(document))
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND)
                    .entity("<error><![CDATA[File not found: " + name + "]]></error>").build());

        return document;

    }

    @GET
    @Path("/property")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getConfigProperties() {

        Response response = null;

        try {
            Properties configProperties = gvConfigurationManager.getXMLConfigProperties();

            JSONObject configJson = new JSONObject();
            configProperties.keySet().stream().map(Object::toString)
                    .forEach(k -> configJson.put(k, configProperties.getProperty(k)));

            response = Response.ok(configJson.toString()).build();

        } catch (FileNotFoundException e) {
            response = Response.status(Response.Status.NOT_FOUND).build();
        } catch (Exception e) {
            LOG.error("Failed to retrieve XMLConfigProperties ", e);
            response = Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
        }

        return response;

    }

    @GET
    @Path("/property/{key}")
    @Produces(MediaType.TEXT_PLAIN)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public String getConfigProperty(@PathParam("key") String key) {

        try {
            Properties configProperties = gvConfigurationManager.getXMLConfigProperties();

            return Optional.ofNullable(configProperties.getProperty(key)).orElseThrow(
                    () -> new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()));

        } catch (FileNotFoundException e) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());

        } catch (IOException e) {
            LOG.error("Failed to retrieve XMLConfigProperties ", e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE).build());
        }

    }

    @POST
    @Path("/property")
    @Consumes(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void createProperties(String properties) {
        try {
            JSONObject configJson = new JSONObject(properties);
            Properties configProperties = new Properties();

            configJson.keySet().stream().filter(k -> !configJson.isNull(k))
                    .forEach(k -> configProperties.put(k, configJson.get(k).toString()));

            gvConfigurationManager.saveXMLConfigProperties(configProperties);

        } catch (JSONException e) {
            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build());

        } catch (Exception e) {
            LOG.error("Failed to update XMLConfigProperties ", e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE).build());
        }
    }

    @PUT
    @Path("/property")
    @Consumes(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void updateProperties(String properties) {
        try {
            JSONObject configJson = new JSONObject(properties);

            Properties configProperties = new Properties();
            configProperties.putAll(gvConfigurationManager.getXMLConfigProperties());

            configJson.keySet().stream().filter(k -> !configJson.isNull(k))
                    .forEach(k -> configProperties.put(k, configJson.get(k).toString()));

            gvConfigurationManager.saveXMLConfigProperties(configProperties);

        } catch (JSONException e) {
            throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST).build());
        } catch (Exception e) {
            LOG.error("Failed to update XMLConfigProperties ", e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE).build());
        }
    }

    @PUT
    @Path("/property/{key}")
    @Consumes(MediaType.TEXT_PLAIN)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void setProperty(@PathParam("key") String key, String value) {

        try {

            Properties configProperties;
            try {
                configProperties = gvConfigurationManager.getXMLConfigProperties();
            } catch (FileNotFoundException e) {
                configProperties = new Properties();
            }

            configProperties.put(key, value);

            gvConfigurationManager.saveXMLConfigProperties(configProperties);
        } catch (Exception e) {
            LOG.error("Failed to update XMLConfigProperties ", e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE).build());
        }
    }

    @DELETE
    @Path("/property/{key}")
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public void deleteProperty(@PathParam("key") String key) {

        try {

            Properties configProperties = gvConfigurationManager.getXMLConfigProperties();
            configProperties.remove(key);

            gvConfigurationManager.saveXMLConfigProperties(configProperties);

        } catch (FileNotFoundException e) {
            throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
        } catch (Exception e) {
            LOG.error("Failed to update XMLConfigProperties ", e);
            throw new WebApplicationException(Response.status(Response.Status.SERVICE_UNAVAILABLE).build());
        }
    }

    @GET
    @Path("/systemproperty")
    @Produces(MediaType.APPLICATION_JSON)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public Response getSystemProperties() {

        Response response = null;

        Properties systemProperties = System.getProperties();

        JSONObject configJson = new JSONObject();
        systemProperties.keySet().stream().map(Object::toString)
                .forEach(k -> configJson.put(k, systemProperties.getProperty(k)));

        response = Response.ok(configJson.toString()).build();

        return response;

    }

    @GET
    @Path("/systemproperty/{key}")
    @Produces(MediaType.TEXT_PLAIN)
    @RolesAllowed({ Authority.ADMINISTRATOR, Authority.MANAGER })
    public String getSystemProperty(@PathParam("key") String key) {

        Properties systemProperties = System.getProperties();

        return Optional.ofNullable(systemProperties.getProperty(key))
                .orElseThrow(() -> new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()));

    }

}