it.infn.ct.indigo.futuregateway.server.FGServerManager.java Source code

Java tutorial

Introduction

Here is the source code for it.infn.ct.indigo.futuregateway.server.FGServerManager.java

Source

/**
 * *********************************************************************
 * Copyright (c) 2016: Istituto Nazionale di Fisica Nucleare (INFN) -
 * INDIGO-DataCloud
 *
 * See http://www.infn.it and and http://www.consorzio-cometa.it for details on
 * the copyright holders.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 **********************************************************************
 */
package it.infn.ct.indigo.futuregateway.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import com.liferay.expando.kernel.exception.DuplicateColumnNameException;
import com.liferay.expando.kernel.exception.DuplicateTableNameException;
import com.liferay.expando.kernel.model.ExpandoColumnConstants;
import com.liferay.expando.kernel.model.ExpandoTable;
import com.liferay.expando.kernel.service.ExpandoColumnLocalService;
import com.liferay.expando.kernel.service.ExpandoTableLocalService;
import com.liferay.expando.kernel.service.ExpandoValueLocalService;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.module.framework.ModuleServiceLifecycle;
import com.liferay.portal.kernel.service.CompanyLocalService;
import com.liferay.portal.kernel.servlet.HttpMethods;
import com.liferay.portal.security.sso.iam.IAM;

import it.infn.ct.indigo.futuregateway.constants.FutureGatewayAdminPortletKeys;

/**
 * Manager of the Future Gateway instance.
 * The manager is responsible to keep the information of the Future Gateway
 * instance to use in the portal and the basic interaction during the
 * administration.
 *
 * <i>Note: the class is responsible for the interaction server side,
 * other interactions will occure on the client side by the javascript
 * part of the portlet.</i>
 */
@Component(immediate = true, service = FGServerManager.class)
public class FGServerManager {

    /**
     * Sets the FG end point for the portal instance.
     *
     * @param companyId The id of the instance
     * @param url The URL of the FG
     * @throws PortalException If the value cannot be saved
     */
    public final void setFGUrl(final long companyId, final String url) throws PortalException {
        expandoValueService.addValue(companyId, FGServerManager.class.getName(), "FG", "fgUrl", 0, url);
    }

    /**
     * Retrieves the FG end point for the portal instance.
     *
     * @param companyId The id of the instance
     * @return The URL of the FG
     * @throws PortalException If the values cannot be accessed
     */
    public final String getFGUrl(final long companyId) throws PortalException {
        return expandoValueService.getData(companyId, FGServerManager.class.getName(), "FG", "fgUrl", 0, "");
    }

    /**
     * Add a new resource into the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The id of the resource to add. If provided the
     *                   resource will be overwritten
     * @param resource The resource information in JSON format
     * @param token The token of the user performing the action
     * @return The Id of the new resource
     * @throws PortalException Cannot retrieve the server endpoint
     * @throws IOException Connect communicate with the server
     */
    public final String addResource(final long companyId, final String collection, final String resourceId,
            final String resource, final String token) throws PortalException, IOException {
        log.debug("Updating/adding the resource in " + collection + ": " + resource);
        HttpURLConnection connection;
        boolean resourceExist = false;

        if (resourceId != null && !resourceId.isEmpty()) {
            resourceExist = true;
            connection = getFGConnection(companyId, collection, resourceId, token, HttpMethods.PUT,
                    FutureGatewayAdminPortletKeys.FUTURE_GATEWAY_CONTENT_TYPE);
        } else {
            connection = getFGConnection(companyId, collection, null, token, HttpMethods.POST,
                    FutureGatewayAdminPortletKeys.FUTURE_GATEWAY_CONTENT_TYPE);
        }
        OutputStream os = connection.getOutputStream();
        os.write(resource.getBytes());
        os.flush();
        if (resourceExist && connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
            return resourceId;
        }
        if (!resourceExist && connection.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
            throw new IOException("Impossible to add the resource. " + "Server response with code: "
                    + connection.getResponseCode());
        }
        StringBuilder result = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            String readLine;
            while ((readLine = br.readLine()) != null) {
                result.append(readLine);
            }
        }
        connection.disconnect();
        JSONObject jRes = JSONFactoryUtil.createJSONObject(result.toString());
        return jRes.getString(FGServerConstants.ATTRIBUTE_ID);
    }

    /**
     * Add a new resource into the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resource The resource information in JSON format
     * @param userId The id of the user performing the action
     * @return The Id of the new resource
     * @throws Exception The resource cannot be added
     */
    public String addResource(final long companyId, final String collection, final String resource,
            final long userId) throws Exception {
        return addResource(companyId, collection, null, resource, iam.getUserToken(userId));
    }

    /**
     * Add a new resource into the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The id of the resource to add. If provided the
     *                   resource will be overwritten
     * @param resource The resource information in JSON format
     * @param userId The id of the user performing the action
     * @return The Id of the new resource
     * @throws Exception The resource cannot be added
     */
    public String addResource(final long companyId, final String collection, final String resourceId,
            final String resource, final long userId) throws Exception {
        return addResource(companyId, collection, resourceId, resource, iam.getUserToken(userId));
    }

    /**
     * Add files into a resource on FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The resource requiring the files
     * @param files The files to add to the resource
     * @param token The token of the user performing the action
     * @throws PortalException Cannot retrieve the server endpoint
     * @throws IOException Connect communicate with the server
     */
    public final void submitFilesResource(final long companyId, final String collection, final String resourceId,
            final Map<String, InputStream> files, final String token) throws PortalException, IOException {
        String boundary = Long.toHexString(System.currentTimeMillis());
        String crlf = "\r\n";
        log.info("Adding new files to " + collection + "/" + resourceId);

        HttpURLConnection connection = getFGConnection(companyId, collection, resourceId + "/input", token,
                HttpMethods.POST, "multipart/form-data; boundary=" + boundary);
        try (OutputStream output = connection.getOutputStream();
                PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8),
                        true);) {
            for (String fName : files.keySet()) {
                writer.append("--" + boundary).append(crlf);
                writer.append("Content-Disposition: form-data; " + "name=\"file[]\"; filename=\"" + fName + "\"")
                        .append(crlf);
                writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(fName)).append(crlf);
                writer.append("Content-Transfer-Encoding: binary").append(crlf);
                writer.append(crlf).flush();
                IOUtils.copy(files.get(fName), output);
                writer.append(crlf).flush();
                files.get(fName).close();
            }
            writer.append("--" + boundary + "--").append(crlf).flush();
        }
        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            throw new IOException("Impossible to post files to the resource " + collection + "/" + resourceId
                    + ". Server response with code: " + connection.getResponseCode());
        }
    }

    /**
     * Add files into a resource on FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The resource requiring the files
     * @param files The files to add to the resource
     * @param userId The id of the user performing the action
     * @throws Exception Impossible to retrieve the user token
     */
    public void submitFilesResource(final long companyId, final String collection, final String resourceId,
            final Map<String, InputStream> files, final long userId) throws Exception {
        submitFilesResource(companyId, collection, resourceId, files, iam.getUserToken(userId));
    }

    /**
     * Retrieves a collection from the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param token The authorisation token for the user
     * @return The full raw collection in json format
     * @throws PortalException Cannot retrieve the server endpoint
     * @throws IOException Connect communicate with the server
     */
    public String getCollection(final long companyId, final String collection, final String token)
            throws PortalException, IOException {
        HttpURLConnection connection = getFGConnection(companyId, collection, null, token, HttpMethods.GET,
                FutureGatewayAdminPortletKeys.FUTURE_GATEWAY_CONTENT_TYPE);
        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            connection.disconnect();
            log.debug("FG server response code not correct: " + connection.getResponseCode());
            throw new IOException("Server response with code: " + connection.getResponseCode());
        }
        BufferedReader collIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String inputLine;
        StringBuilder collections = new StringBuilder();
        while ((inputLine = collIn.readLine()) != null) {
            collections.append(inputLine);
        }
        collIn.close();
        log.debug("This is the collection: " + collections.toString());
        return collections.toString();
    }

    /**
     * Retrieves a resource from the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The id of the resource to retrieve
     * @param userId The id of the user performing the action
     * @return The full raw collection in json format
     * @throws Exception Impossible to retrieve the user token
     */
    public String getResource(final long companyId, final String collection, final String resourceId,
            final long userId) throws Exception {
        return getResource(companyId, collection, resourceId, iam.getUserToken(userId));
    }

    /**
     * Retrieves a resource from the FG service.
     *
     * @param companyId The id of the instance
     * @param collection The name of the collection to post the new resource
     * @param resourceId The id of the resource to retrieve
     * @param token The authorisation token for the user
     * @return The full raw collection in json format
     * @throws PortalException Cannot retrieve the server endpoint
     * @throws IOException Connect communicate with the server
     */
    public String getResource(final long companyId, final String collection, final String resourceId,
            final String token) throws PortalException, IOException {
        HttpURLConnection connection = getFGConnection(companyId, collection, resourceId, token, HttpMethods.GET,
                FutureGatewayAdminPortletKeys.FUTURE_GATEWAY_CONTENT_TYPE);
        if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            connection.disconnect();
            log.debug("FG server response code not correct: " + connection.getResponseCode());
            throw new IOException("Server response with code: " + connection.getResponseCode());
        }
        BufferedReader resIn = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String inputLine;
        StringBuilder resource = new StringBuilder();
        while ((inputLine = resIn.readLine()) != null) {
            resource.append(inputLine);
        }
        resIn.close();
        log.debug("This is the collection: " + resource.toString());
        return resource.toString();
    }

    /**
     * Retrieves the available infrastructures from the FG service.
     *
     * @param companyId The id of the instance
     * @param userId The id of the user performing the request
     * @return A map of enabled infrastructures. The map contains id and name
     * @throws Exception Cannot communicate with the server
     */
    public Map<String, String> getInfrastructures(final long companyId, final long userId) throws Exception {
        Map<String, String> mapInfras = new HashMap<>();
        String rawCollection = getCollection(companyId, FGServerConstants.INFRASTRUCTURE_COLLECTION,
                iam.getUserToken(userId));
        log.debug("Infrastructure json: " + rawCollection);
        JSONObject jsonInfras = JSONFactoryUtil.createJSONObject(rawCollection);
        JSONArray jAInfras = jsonInfras.getJSONArray(FGServerConstants.INFRASTRUCTURE_COLLECTION);
        log.debug("Available " + jAInfras.length() + " infrastructures");
        for (int i = 0; i < jAInfras.length(); i++) {
            JSONObject jOInfra = jAInfras.getJSONObject(i);
            log.debug("Infrastructure " + jOInfra.getString(FGServerConstants.ATTRIBUTE_ID) + " enabled option is "
                    + jOInfra.getBoolean(FGServerConstants.ATTRIBUTE_ENABLED));
            if (jOInfra.getBoolean(FGServerConstants.ATTRIBUTE_ENABLED)) {
                mapInfras.put(jOInfra.getString(FGServerConstants.ATTRIBUTE_ID),
                        jOInfra.getString(FGServerConstants.ATTRIBUTE_NAME));
            }
        }
        return mapInfras;
    }

    /**
     * Retrive the connection to the server.
     *
     * @param companyId The companyId
     * @param collection The collection
     * @param resourceId The resource
     * @param token The Token
     * @param method The request method
     * @param contentType The content type
     * @return The active connection.
     * @throws PortalException Cannot retrieve the information
     * @throws IOException Cannot open the connection
     */
    public HttpURLConnection getFGConnection(final long companyId, final String collection, final String resourceId,
            final String token, final String method, final String contentType) throws PortalException, IOException {
        String finalPath = collection;
        if (resourceId != null) {
            finalPath = finalPath + "/" + resourceId;
        }
        URL url = new URL(getFGUrl(companyId) + "/" + finalPath);
        log.debug("Get the collection from " + url.toString());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setRequestMethod(method);
        connection.setRequestProperty("Authorization", "Bearer " + token);
        connection.setRequestProperty("Content-Type", contentType);
        return connection;
    }

    /**
     * Actions to do when the component is activated.
     * The only activity is to create the tables in the DB to save
     * the configurations for the FG
     */
    @Activate
    protected final void activate() {
        List<Company> companys = companyService.getCompanies();

        for (Company company : companys) {
            try {
                setupExpando(company.getCompanyId());
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    log.warn("Unable to setup FutureGateway service for" + " company " + company.getCompanyId()
                            + ": " + e.getMessage());
                }
            }
        }
    }

    /**
     * Sets the company service.
     * Used to retrieve the list of instances during the activation
     *
     * @param companyLocalService The local company service
     */
    @Reference(unbind = "-")
    protected final void setCompanyLocalService(final CompanyLocalService companyLocalService) {
        companyService = companyLocalService;
    }

    /**
     * Sets the ExpandoColumn service.
     * Used to add columns in the expando table related to the FG
     *
     * @param expandoColumnLocalService The local expando column service
     */
    @Reference(unbind = "-")
    protected final void setExpandoColumnLocalService(final ExpandoColumnLocalService expandoColumnLocalService) {
        expandoColumnService = expandoColumnLocalService;
    }

    /**
     * Sets the ExpandoTable service.
     * Used to create an expando table for the FG
     *
     * @param expandoTableLocalService The local expando table service
     */
    @Reference(unbind = "-")
    protected final void setExpandoTableLocalService(final ExpandoTableLocalService expandoTableLocalService) {
        expandoTableService = expandoTableLocalService;
    }

    /**
     * Sets the ExpandoValue service.
     * Used to save and retrive values from the expando table
     *
     * @param expandoValueLocalService The local expando value service
     */
    @Reference(unbind = "-")
    protected final void setExpandoValueLocalService(final ExpandoValueLocalService expandoValueLocalService) {
        expandoValueService = expandoValueLocalService;
    }

    /**
     * Sets the ModuleServiceLifecycle.
     * <b>Not used</b>
     * @param moduleServiceLifecycle The module service lifecycle
     */
    @Reference(target = ModuleServiceLifecycle.PORTAL_INITIALIZED, unbind = "-")
    protected final void setModuleServiceLifecycle(final ModuleServiceLifecycle moduleServiceLifecycle) {
    }

    /**
     * Creates the expando table for the FG.
     *
     * @param companyId The id of the instance owning the table
     * @throws Exception If the table cannot be created
     */
    private void setupExpando(final long companyId) throws Exception {
        ExpandoTable table = null;
        try {
            table = expandoTableService.addTable(companyId, FGServerManager.class.getName(), "FG");
        } catch (DuplicateTableNameException dtne) {
            table = expandoTableService.getTable(companyId, FGServerManager.class.getName(), "FG");
        }

        try {
            expandoColumnService.addColumn(table.getTableId(), "fgUrl", ExpandoColumnConstants.STRING);
        } catch (DuplicateColumnNameException dcne) {
        }
    }

    /**
     * Sets the iam component.
     *
     * @param iamComp The iam component
     */
    @Reference(unbind = "-")
    protected final void setIam(final IAM iamComp) {
        this.iam = iamComp;
    }

    /**
     * The logger.
     */
    private final Log log = LogFactoryUtil.getLog(FGServerManager.class);

    /**
     * The Company service.
     */
    private CompanyLocalService companyService;

    /**
     * The ExpandoColumn service.
     */
    private ExpandoColumnLocalService expandoColumnService;

    /**
     * The ExpandoTable service.
     */
    private ExpandoTableLocalService expandoTableService;

    /**
     * The ExpandoValue service.
     */
    private ExpandoValueLocalService expandoValueService;

    /**
     * The IAM service.
     */
    private IAM iam;
}