org.ow2.proactive_grid_cloud_portal.rm.server.RMServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ow2.proactive_grid_cloud_portal.rm.server.RMServiceImpl.java

Source

/*
 * ################################################################
 *
 * ProActive Parallel Suite(TM): The Java(TM) library for
 *    Parallel, Distributed, Multi-Core Computing for
 *    Enterprise Grids & Clouds
 *
 * Copyright (C) 1997-2015 INRIA/University of
 *                 Nice-Sophia Antipolis/ActiveEon
 * Contact: proactive@ow2.org or contact@activeeon.com
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; version 3 of
 * the License.
 *
 * This library 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
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * If needed, contact us to obtain a release under GPL Version 2 or 3
 * or a different license than the AGPL.
 *
 *  Initial developer(s):               The ProActive Team
 *                        http://proactive.inria.fr/team_members.htm
 *  Contributor(s):
 *
 * ################################################################
 * $$PROACTIVE_INITIAL_DEV$$
 */
package org.ow2.proactive_grid_cloud_portal.rm.server;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.ow2.proactive_grid_cloud_portal.common.server.ConfigReader;
import org.ow2.proactive_grid_cloud_portal.common.server.ConfigUtils;
import org.ow2.proactive_grid_cloud_portal.common.server.HttpUtils;
import org.ow2.proactive_grid_cloud_portal.common.server.Service;
import org.ow2.proactive_grid_cloud_portal.common.shared.RestServerException;
import org.ow2.proactive_grid_cloud_portal.common.shared.ServiceException;
import org.ow2.proactive_grid_cloud_portal.rm.client.RMService;
import org.ow2.proactive_grid_cloud_portal.rm.shared.RMConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static org.ow2.proactive_grid_cloud_portal.common.server.HttpUtils.convertToString;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class RMServiceImpl extends Service implements RMService {

    private static final Logger LOGGER = LoggerFactory.getLogger(RMServiceImpl.class);

    /**
     * Number of threads created for the threadPool shared by RestEasy client proxies.
     */
    private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 8;

    /**
     * Thread pool shared by RestEasy client proxies.
     */
    private ExecutorService threadPool;

    private DefaultHttpClient httpClient;

    @Override
    public void init() {
        loadProperties();

        httpClient = HttpUtils.createDefaultExecutor();
        threadPool = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#getProperties()
     */
    public Map<String, String> getProperties() {
        return RMConfig.get().getProperties();
    }

    /**
     * Loads properties defined in the configuration file and in JVM arguments.
     */
    private void loadProperties() {
        RMConfig.get()
                .load(ConfigReader.readPropertiesFromFile(getServletContext().getRealPath(RMConfig.CONFIG_PATH)));
        ConfigUtils.loadSystemProperties(RMConfig.get());
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#logout(java.lang.String)
     */
    public void logout(String sessionId) throws ServiceException {
        RestClient restClientProxy = getRestClientProxy();

        try {
            restClientProxy.logout(sessionId);
        } catch (WebApplicationException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /*
     * (non-Javadoc)
     * @see Service#login(java.lang.String, java.lang.String, java.io.File, java.lang.String)
     */
    public String login(String login, String pass, File cred, String ssh)
            throws RestServerException, ServiceException {
        HttpPost httpPost = new HttpPost(RMConfig.get().getRestUrl() + "/rm/login");

        try {
            MultipartEntity entity;
            if (cred == null) {
                entity = createLoginPasswordSSHKeyMultipart(login, pass, ssh);
            } else {
                entity = new MultipartEntity();
                entity.addPart("credential", new FileBody(cred, "application/octet-stream"));
            }
            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);
            String responseAsString = convertToString(response.getEntity().getContent());
            switch (response.getStatusLine().getStatusCode()) {
            case 200:
                break;
            default:
                if (responseAsString.trim().length() == 0) {
                    responseAsString = "{ \"httpErrorCode\": " + response.getStatusLine().getStatusCode() + ","
                            + "\"errorMessage\": \"" + response.getStatusLine().getReasonPhrase() + "\" }";
                }
                throw new RestServerException(response.getStatusLine().getStatusCode(), responseAsString);
            }
            return responseAsString;
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        } finally {
            httpPost.releaseConnection();
            if (cred != null) {
                cred.delete();
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#getState(java.lang.String)
     */
    public String getState(final String sessionId) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.state(sessionId);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#getMonitoring(java.lang.String)
     */
    public String getMonitoring(final String sessionId) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.monitoring(sessionId);
            }
        });
    }

    /**
     * Create a Credentials file with the provided authentication parameters
     *
     * @param login username
     * @param pass  password
     * @param ssh   private ssh key
     * @return the the Credentials file as a base64 String
     * @throws ServiceException
     */
    public String createCredentials(String login, String pass, String ssh)
            throws RestServerException, ServiceException {
        HttpPost httpPost = new HttpPost(RMConfig.get().getRestUrl() + "/scheduler/createcredential");

        try {
            MultipartEntity entity = createLoginPasswordSSHKeyMultipart(login, pass, ssh);

            httpPost.setEntity(entity);

            HttpResponse response = httpClient.execute(httpPost);
            String responseAsString = convertToString(response.getEntity().getContent());

            switch (response.getStatusLine().getStatusCode()) {
            case 200:
                return responseAsString;
            default:
                throw new RestServerException(response.getStatusLine().getStatusCode(), responseAsString);
            }
        } catch (Exception e) {
            LOGGER.warn("Failed to create credentials", e);
            throw new ServiceException(e.getMessage());
        } finally {
            httpPost.releaseConnection();
        }
    }

    private MultipartEntity createLoginPasswordSSHKeyMultipart(String login, String pass, String ssh)
            throws UnsupportedEncodingException {
        MultipartEntity entity = new MultipartEntity();
        entity.addPart("username", new StringBody(login));
        entity.addPart("password", new StringBody(pass));
        if (ssh != null && !ssh.isEmpty()) {
            entity.addPart("sshKey", new ByteArrayBody(ssh.getBytes(), MediaType.APPLICATION_OCTET_STREAM, null));
        }
        return entity;
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#createNodeSource(java.lang.String, java.lang.String, java.lang.String, java.lang.String[], java.lang.String[], java.lang.String, java.lang.String[], java.lang.String[])
     */
    public String createNodeSource(final String sessionId, final String nodeSourceName,
            final String infrastructureType, final String[] infrastructureParameters,
            final String[] infrastructureFileParameters, final String policyType, final String[] policyParameters,
            final String[] policyFileParameters) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.createnodeSource(sessionId, nodeSourceName, infrastructureType,
                        infrastructureParameters, infrastructureFileParameters, policyType, policyParameters,
                        policyFileParameters);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#getInfrastructures(java.lang.String)
     */
    public String getInfrastructures(final String sessionId) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.infrastructures(sessionId);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#getPolicies(java.lang.String)
     */
    public String getPolicies(final String sessionId) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.policies(sessionId);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#lockNodes(java.lang.String, java.util.Set)
     */
    public String lockNodes(final String sessionId, Set<String> urls) throws RestServerException, ServiceException {
        return executeFunction(new BiFunction<RestClient, Set<String>, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient, Set<String> strings) {
                return restClient.lockNodes(sessionId, strings);
            }
        }, urls, "lock");
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#unlockNodes(java.lang.String, java.util.Set)
     */
    public String unlockNodes(final String sessionId, Set<String> urls)
            throws RestServerException, ServiceException {
        return executeFunction(new BiFunction<RestClient, Set<String>, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient, Set<String> strings) {
                return restClient.unlockNodes(sessionId, strings);
            }
        }, urls, "unlock");
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#removeNode(java.lang.String, java.lang.String)
     */
    public String removeNode(final String sessionId, final String url, final boolean force)
            throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.removeNode(sessionId, url, force);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#removeNodesource(java.lang.String, java.lang.String)
     */
    public String removeNodesource(final String sessionId, final String name, final boolean preempt)
            throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.removeNodesource(sessionId, name, preempt);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see org.ow2.proactive_grid_cloud_portal.rm.client.RMService#releaseNode(java.lang.String, java.lang.String)
     */
    public String releaseNode(final String sessionId, final String url)
            throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.releaseNode(sessionId, url);
            }
        });
    }

    /*
     * (non-Javadoc)
     * @see Service#getVersion()
     */
    public String getVersion() throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getVersion();
            }
        });
    }

    @Override
    public String getMBeanInfo(final String sessionId, String name, final List<String> attrs)
            throws RestServerException, ServiceException {
        try {
            final ObjectName obj = new ObjectName(name);

            return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
                @Override
                public InputStream apply(RestClient restClient) {
                    return restClient.getMBeanInfo(sessionId, obj, attrs);
                }
            });
        } catch (MalformedObjectNameException e) {
            throw new ServiceException("Malformed MBean name", e);
        }
    }

    @Override
    public String getNodeMBeanInfo(final String sessionId, final String nodeJmxUrl, final String objectName,
            final List<String> attrs) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getNodeMBeanInfo(sessionId, nodeJmxUrl, objectName, attrs);
            }
        });
    }

    @Override
    public String getNodeMBeanHistory(final String sessionId, final String nodeJmxUrl, final String objectName,
            final List<String> attrs, final String timeRange) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getNodeMBeanHistory(sessionId, nodeJmxUrl, objectName, attrs, timeRange);
            }
        });
    }

    @Override
    public String getNodeMBeansInfo(final String sessionId, final String nodeJmxUrl, final String objectNames,
            final List<String> attrs) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getNodeMBeansInfo(sessionId, nodeJmxUrl, objectNames, attrs);
            }
        });
    }

    @Override
    public String getNodeMBeansHistory(final String sessionId, final String nodeJmxUrl, final String objectNames,
            final List<String> attrs, final String timeRange) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getNodeMBeansHistory(sessionId, nodeJmxUrl, objectNames, attrs, timeRange);
            }
        });
    }

    @Override
    public String getStatHistory(final String sessionId, final String range)
            throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.getStatHistory(sessionId, range);
            }
        });
    }

    @Override
    public String executeNodeScript(final String sessionId, final String script, final String engine,
            final String nodeUrl) throws RestServerException, ServiceException {
        return executeFunctionReturnStreamAsString(new Function<RestClient, InputStream>() {
            @Override
            public InputStream apply(RestClient restClient) {
                return restClient.executeNodeScript(sessionId, nodeUrl, script, engine);
            }
        });
    }

    private RestClient getRestClientProxy() {
        ResteasyClient client = new ResteasyClientBuilder().asyncExecutor(threadPool).build();
        ResteasyWebTarget target = client.target(RMConfig.get().getRestUrl());

        return target.proxy(RestClient.class);
    }

    private String executeFunction(BiFunction<RestClient, Set<String>, InputStream> action, Set<String> urls,
            String actionName) throws ServiceException, RestServerException {

        RestClient restClientProxy = getRestClientProxy();

        int failures = 0;
        int success = 0;

        for (String url : urls) {
            InputStream inputStream = null;

            try {
                inputStream = action.apply(restClientProxy, Collections.singleton(url));
                success++;
            } catch (WebApplicationException e) {
                failures++;
            } finally {
                IOUtils.closeQuietly(inputStream);
            }
        }

        if (failures > 0) {
            throw new RestServerException("Failed to " + actionName + " all requested nodes: " + success
                    + " succeeded, " + failures + " failed.");
        }

        return "";
    }

    private String executeFunctionReturnStreamAsString(Function<RestClient, InputStream> function)
            throws ServiceException, RestServerException {
        RestClient restClientProxy = getRestClientProxy();

        InputStream inputStream = null;

        try {
            inputStream = function.apply(restClientProxy);

            try {
                return convertToString(inputStream);
            } catch (IOException e) {
                throw new ServiceException(e.getMessage());
            }
        } catch (WebApplicationException e) {
            return rethrowRestServerException(e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    private String rethrowRestServerException(WebApplicationException e) throws RestServerException {
        throw new RestServerException(e.getResponse().getStatus(), e.getMessage());
    }

    private interface BiFunction<T, U, R> {

        R apply(T t, U u);

    }

    private interface Function<T, R> {

        R apply(T t);

    }

}