org.occiware.mart.server.servlet.utils.Utils.java Source code

Java tutorial

Introduction

Here is the source code for org.occiware.mart.server.servlet.utils.Utils.java

Source

/**
 * Copyright (c) 2015-2017 Inria
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.
 * <p>
 * Contributors:
 * - Christophe Gourdin <christophe.gourdin@inria.fr>
 */
package org.occiware.mart.server.servlet.utils;

import org.apache.commons.io.IOUtils;
import org.occiware.clouddesigner.occi.*;
import org.occiware.mart.server.servlet.model.ConfigurationManager;
import org.occiware.mart.server.servlet.model.exceptions.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * Utility class for rest queries.
 *
 * @author cgourdin
 */
public class Utils {

    private static final String REGEX_CONTROL_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}";
    private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
    private static int uniqueInt = 1;

    /**
     * Client OCCI user agent version control.
     *
     * @param headers
     * @return null if no response, not null if failed response.
     */
    public static Response checkClientOCCIVersion(HttpHeaders headers) {
        boolean result = true;
        List<String> vals = getFromValueFromHeaders(headers, Constants.HEADER_USER_AGENT);
        for (String val : vals) {
            if (val.contains("OCCI/") || val.contains("occi/")) {
                // Check if version is compliant with supported occi version 1.2 currently.
                if (!val.contains(Constants.OCCI_SERVER_VERSION)) {
                    // Check if client version is > 1.2.
                    int index = val.indexOf("OCCI/") + 5;
                    String versionStr = val.substring(index);
                    if (!versionStr.isEmpty()) {

                        // Check version number.
                        try {
                            Float version = Float.valueOf(versionStr);
                            if (version > Constants.OCCI_SERVER_VERSION_NUMBER) {
                                result = false;
                            }
                        } catch (NumberFormatException ex) {
                            // Version is unparseable.
                        }

                    }

                }
            }
        }
        if (!result) {
            System.out.println("Version is not compliant, max: OCCI v1.2");
            return Response.status(Response.Status.NOT_IMPLEMENTED)
                    .entity("The requested version is not implemented.").build();
        }
        return null;
    }

    /**
     * Check if text/uri-list is used.
     *
     * @param headers
     * @return true if this content-type is an uri-list otherwise false.
     */
    public static boolean isUriListContentTypeUsed(HttpHeaders headers) {
        boolean result = false;
        // Find media type produce as Content-Type: text/uri-list.
        List<String> vals = Utils.getFromValueFromHeaders(headers, Constants.HEADER_CONTENT_TYPE);

        for (String val : vals) {
            if (val.toLowerCase().equals(Constants.MEDIA_TYPE_TEXT_URI_LIST)) {
                result = true;
            }
        }
        return result;
    }

    /**
     * Return the Content-type from http header.
     *
     * @param headers
     * @return
     */
    public static String findContentTypeFromHeader(HttpHeaders headers) {
        List<String> vals = Utils.getFromValueFromHeaders(headers, Constants.HEADER_CONTENT_TYPE);
        String contentType = null;
        for (String val : vals) {
            if (val != null && !val.isEmpty()) {
                contentType = val;
                break;
            }
        }
        return contentType;
    }

    /**
     * Return the accept media type from header.
     *
     * @param headers
     * @return
     */
    public static String findAcceptTypeFromHeader(HttpHeaders headers) {
        List<String> vals = Utils.getFromValueFromHeaders(headers, Constants.HEADER_ACCEPT);
        String contentType = null;
        for (String val : vals) {
            if (val != null && !val.isEmpty()) {
                contentType = val;
                break;
            }
        }
        return contentType;
    }

    /**
     * Get a list of values for a header key.
     *
     * @param headers
     * @param key
     * @return
     */
    public static List<String> getFromValueFromHeaders(HttpHeaders headers, String key) {
        MultivaluedMap<String, String> headersVal = headers.getRequestHeaders();
        List<String> vals = headersVal.get(key);
        if (vals == null) {
            vals = new ArrayList<>();
        }
        return vals;
    }

    public static String createUUID() {
        return UUID.randomUUID().toString();

    }

    /**
     * Simple copy a stream with a buffer of 1024 bytes into an outputstream.
     *
     * @param in
     * @param os
     * @return a String representation of copied bytes, null if outputstream is
     * not a ByteArrayOutputStream.
     * @throws IOException
     */
    public static String copyStream(InputStream in, OutputStream os) throws IOException {
        byte[] buf = new byte[1024];
        int len;
        while ((len = in.read(buf)) > 0) {
            os.write(buf, 0, len);
        }
        os.flush();
        if (os instanceof ByteArrayOutputStream) {
            return new String(((ByteArrayOutputStream) os).toByteArray(), "UTF-8");
        }
        return null;
    }

    /**
     * Close quietly an inputstream without exception thrown.
     *
     * @param in
     */
    public static void closeQuietly(InputStream in) {
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                /* ignore */
            }
        }
    }

    public static void closeQuietly(BufferedReader br) {
        if (br != null) {
            try {
                br.close();
            } catch (IOException e) {
                /* ignore */
            }
        }
    }

    public static void closeQuietly(Reader r) {
        if (r != null) {
            try {
                r.close();
            } catch (IOException e) {
                /* ignore */
            }
        }
    }

    /**
     * Close quietly an outputstream without exception thrown.
     *
     * @param os
     */
    public static void closeQuietly(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                /* ignore */
            }
        }
    }

    /**
     * Serialize an object to make an MD5 hash after call getMd5Digest Method.
     *
     * @param obj
     * @return
     * @throws IOException
     */
    private static byte[] serialize(Object obj) throws IOException {
        byte[] byteArray = null;
        ByteArrayOutputStream baos;
        ObjectOutputStream out = null;
        try {
            // These objects are closed in the finally.
            baos = new ByteArrayOutputStream();
            out = new ObjectOutputStream(baos);
            out.writeObject(obj);
            byteArray = baos.toByteArray();
        } finally {
            if (out != null) {
                out.close();
            }
        }
        return byteArray;
    }

    /**
     * Create a MD5 hash.
     *
     * @param bytes (array of bytes).
     * @return
     */
    private static String getMd5Digest(byte[] bytes) {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            return "1";
            // throw new RuntimeException("MD5 cryptographic algorithm is not
            // available.", e);
        }
        byte[] messageDigest = md.digest(bytes);
        BigInteger number = new BigInteger(1, messageDigest);
        // prepend a zero to get a "proper" MD5 hash value
        return "0" + number.toString(16);
    }

    /**
     * Create an eTag (Serial number, serialize an object) for dbus interaction.
     *
     * @param obj
     * @return an eTag number.
     */
    public static Long createEtagNumber(Object obj) {
        String eTag;
        try {
            eTag = getMd5Digest(serialize(obj));
        } catch (IOException ioe) {
            LOGGER.warn("IOException thrown : {0}", ioe.getMessage());
            eTag = "1";
        }

        StringBuilder sb = new StringBuilder();
        for (char c : eTag.toCharArray()) {
            sb.append((int) c);
        }
        return new Long(sb.toString());
    }

    /**
     * Serialize a string (entity id for example with an owner)
     *
     * @param id
     * @param owner
     * @param version (version number, will increment with each update on this
     *                object).
     * @return
     */
    public static Long createEtagNumber(final String id, final String owner, final int version) {
        String eTag;
        if (id == null) {
            eTag = "1";
        } else {
            try {
                eTag = getMd5Digest(serialize(id + owner + version));
            } catch (IOException ioe) {
                LOGGER.warn("IOException thrown : {0}", ioe.getMessage());
                eTag = "1";
            }
        }
        StringBuilder sb = new StringBuilder();

        for (char c : eTag.toCharArray()) {
            sb.append((int) c);
        }
        String result = sb.toString().substring(0, 7);

        return new Long(result);
    }

    /**
     * Check if an UUID is provided on a String or attribute occi.core.id.
     *
     * @param id,  an uuid or a path like foo/bar/myuuid
     * @param attr
     * @return true if provided or false if not provided
     */
    public static boolean isEntityUUIDProvided(final String id, final Map<String, String> attr) {
        String[] uuids = id.split("/");
        boolean match = false;

        for (String uuid : uuids) {
            if (uuid.matches(REGEX_CONTROL_UUID)) {
                match = true;
                break;
            }
        }
        String occiCoreId = attr.get("occi.core.id");
        if (!match && occiCoreId != null && !occiCoreId.isEmpty()) {
            String[] spls = { "/", ":" };
            for (String spl : spls) {
                uuids = occiCoreId.split(spl);
                for (String uuid : uuids) {
                    if (uuid.matches(REGEX_CONTROL_UUID)) {
                        match = true;
                        break;
                    }
                }
                if (match) {
                    break;
                }
            }

        }

        return match;
    }

    /**
     * Search for UUID on a entityId String before attribute occi.core.id.
     *
     * @param path
     * @param attr
     * @return the UUID provided may return null if uuid not found.
     */
    public static String getUUIDFromPath(final String path, final Map<String, String> attr) {
        String[] uuids = path.split("/");
        String uuidToReturn = null;

        for (String uuid : uuids) {
            if (uuid.matches(REGEX_CONTROL_UUID)) {
                uuidToReturn = uuid;
                break;
            }
        }
        if (uuidToReturn != null) {
            return uuidToReturn;
        }

        // Check with occi.core.id attribute.
        String occiCoreId = attr.get(Constants.OCCI_CORE_ID);
        if (occiCoreId == null) {
            return null;
        }
        occiCoreId = occiCoreId.replace(Constants.URN_UUID_PREFIX, "");
        if (!occiCoreId.isEmpty()) {
            String[] spls = { "/", ":" };
            for (String spl : spls) {
                uuids = occiCoreId.split(spl);
                for (String uuid : uuids) {
                    if (uuid.matches(REGEX_CONTROL_UUID)) {
                        return uuid;
                    }
                }
            }
        }

        return uuidToReturn;
    }

    /**
     * Check if the uuid is a valid one.
     * @param uuid
     * @return true if the uuid provided is valid false elsewhere.
     */
    public static boolean isUUIDValid(final String uuid) {
        if (uuid == null || uuid.trim().isEmpty()) {
            return false;
        }
        return uuid.matches(REGEX_CONTROL_UUID);
    }

    /**
     * Helper for converting action attributes parameters in array.
     *
     * @param actionAttributes
     * @return parameters for an action null if none.
     */
    public static String[] getActionParametersArray(Map<String, String> actionAttributes) {
        String[] actionParameters = null;
        if (actionAttributes != null && !actionAttributes.isEmpty()) {
            actionParameters = new String[actionAttributes.size()];
            String value;
            int index = 0;
            for (Map.Entry<String, String> entry : actionAttributes.entrySet()) {
                value = entry.getValue();
                actionParameters[index] = value;
                index++;
            }
        }

        return actionParameters;
    }

    /**
     * Print on logger an entity.
     *
     * @param entity
     */
    public static void printEntity(Entity entity) {

        StringBuilder builder = new StringBuilder("");
        if (entity instanceof Resource) {
            builder.append("Entity is a resource. \n");
        }
        if (entity instanceof Link) {
            builder.append("Entity is a link.\n");
        }
        builder.append("id : ").append(entity.getId()).append(" \n");
        builder.append("kind : ").append(entity.getKind().getScheme()).append(entity.getKind().getTerm())
                .append(" \n ");
        if (!entity.getMixins().isEmpty()) {
            builder.append("mixins : ").append(entity.getMixins().toString()).append(" \n ");
        } else {
            builder.append("entity has no mixins" + " \n ");
        }
        builder.append("Entity attributes : " + " \n ");
        if (entity.getAttributes().isEmpty()) {
            builder.append("no attributes found." + " \n ");
        }
        for (AttributeState attribute : entity.getAttributes()) {
            builder.append("--> name : ").append(attribute.getName()).append(" \n ");
            builder.append("-- value : ").append(attribute.getValue()).append(" \n ");
        }
        if (entity.getKind().getActions().isEmpty()) {
            builder.append("entity has no action \n ");
        } else {
            builder.append("entity has actions available : \n ");
            for (Action action : entity.getKind().getActions()) {
                builder.append(action.getTitle()).append("--> ").append(action.getScheme()).append(action.getTerm())
                        .append(" \n ");
            }
        }
        LOGGER.info(builder.toString());

    }

    /**
     * Check if the path contains a category referenced on extensions used by
     * configuration.
     *
     * @param path
     * @param user
     * @return a category term if found on configuration, if not found return
     * null.
     */
    public static String getCategoryFilter(final String path, final String user) {
        List<Kind> kinds = ConfigurationManager.getAllConfigurationKind(user);
        List<Mixin> mixins = ConfigurationManager.getAllConfigurationMixins(user);
        String term;

        for (Kind kind : kinds) {
            for (Action action : kind.getActions()) {
                term = action.getTerm();
                if (path.contains(term) || path.contains(term.toLowerCase())) {
                    return term;

                }
            }

            term = kind.getTerm();
            if (path.contains(term) || path.contains(term.toLowerCase())) {
                return term;
            }

        }
        for (Mixin mixin : mixins) {
            term = mixin.getTerm();
            if (path.contains(term) || path.contains(term.toLowerCase())) {
                return term;
            }
        }

        return null;
    }

    /**
     * Check if the path equals a category referenced on extensions used by
     * configuration. Remove leading slash and ending slash before proceed.
     *
     * @param path
     * @param user
     * @return a category term if found on configuration, if not found return
     * null.
     */
    public static String getCategoryFilterSchemeTerm(final String path, final String user) {
        List<Kind> kinds = ConfigurationManager.getAllConfigurationKind(user);
        List<Mixin> mixins = ConfigurationManager.getAllConfigurationMixins(user);
        String term;
        String scheme;
        String id;

        if (path == null) {
            return null;
        }

        String pathTerm = path;
        if (pathTerm.startsWith("/")) {
            pathTerm = pathTerm.substring(1);
        }
        if (pathTerm.endsWith("/")) {
            pathTerm = pathTerm.substring(0, pathTerm.length() - 1);
        }

        for (Kind kind : kinds) {
            for (Action action : kind.getActions()) {
                term = action.getTerm();
                scheme = action.getScheme();
                id = scheme + term;
                if (pathTerm.equals(term) || pathTerm.equals(term.toLowerCase())) {
                    return id;

                }
            }

            term = kind.getTerm();
            scheme = kind.getScheme();
            id = scheme + term;
            if (pathTerm.equals(term) || path.equals(term.toLowerCase())) {
                return id;
            }

        }
        for (Mixin mixin : mixins) {

            term = mixin.getTerm();
            scheme = mixin.getScheme();
            id = scheme + term;
            if (pathTerm.equals(term) || pathTerm.equals(term.toLowerCase())) {
                return id;
            }
        }

        return null;
    }

    /**
     * Return true if categoryFilter is a scheme + term.
     *
     * @param categoryFilter
     * @param user
     * @return
     */
    public static boolean checkIfCategorySchemeTerm(String categoryFilter, String user) {

        List<Kind> kinds = ConfigurationManager.getAllConfigurationKind(user);
        List<Mixin> mixins = ConfigurationManager.getAllConfigurationMixins(user);
        String term;
        String scheme;
        String id;
        for (Kind kind : kinds) {
            // Check actions.
            for (Action action : kind.getActions()) {
                term = action.getTerm();
                scheme = action.getScheme();
                id = scheme + term;
                if (categoryFilter.equalsIgnoreCase(id)) {
                    return true;

                }
            }

            term = kind.getTerm();
            scheme = kind.getScheme();
            id = scheme + term;
            if (categoryFilter.equalsIgnoreCase(id)) {
                return true;
            }

        }
        for (Mixin mixin : mixins) {

            term = mixin.getTerm();
            scheme = mixin.getScheme();
            id = scheme + term;
            if (categoryFilter.equalsIgnoreCase(id)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param mixins
     * @param kind
     * @return true if all mixins applied.
     */
    public static boolean checkIfMixinAppliedToKind(List<Mixin> mixins, Kind kind) {
        boolean result = true;
        if (mixins.isEmpty()) {
            return true;
        }
        for (Mixin mixin : mixins) {
            if (!mixin.getApplies().contains(kind)) {
                // one or more mixin doesnt apply to this kind.
                result = false;
            }
        }
        return result;
    }

    /**
     * Load a list of mixin from used extensions models.
     *
     * @param mixins
     * @return
     * @throws ConfigurationException
     */
    public static List<Mixin> loadMixinFromSchemeTerm(List<String> mixins) throws ConfigurationException {
        List<Mixin> mixinModel = new LinkedList<>();

        Mixin mixinTmp;
        for (String mixinId : mixins) {
            mixinTmp = ConfigurationManager.findMixinOnExtension(ConfigurationManager.DEFAULT_OWNER, mixinId);
            if (mixinTmp == null) {
                mixinTmp = ConfigurationManager.findUserMixinOnConfiguration(mixinId,
                        ConfigurationManager.DEFAULT_OWNER);
                if (mixinTmp == null) {
                    throw new ConfigurationException("Mixin : " + mixinId + " not found on used extensions models");
                }
            } else {
                mixinModel.add(mixinTmp);
            }
        }
        return mixinModel;
    }

    public static synchronized int getUniqueInt() {
        return uniqueInt++;
    }

    /**
     * Entity request is defined by a known path relative to an entity. This
     * method search for an entity or entities for the path. if entities found
     * for the same path, this is a collection request and not an entity request
     * => return false..
     *
     * @param path
     * @param attrs
     * @return true if the path is an entity request path, false elsewhere.
     */
    public static boolean isEntityRequest(String path, Map<String, String> attrs) {
        if (isEntityUUIDProvided(path, attrs)) {
            return true;
        }

        // this path has no uuid provided, must search on all entities path.
        List<String> entitiesUuid = getEntityUUIDsFromPath(path);

        // This is a collection request or no entities on paths. Other entities are declared on the same path.
        return entitiesUuid.size() == 1;

    }

    /**
     * Get all entities registered on the same path.
     *
     * @param path
     * @return a List of String uuids
     */
    public static List<String> getEntityUUIDsFromPath(final String path) {
        List<String> entitiesUUID = new ArrayList<>();
        if (path == null || path.isEmpty()) {
            return entitiesUUID;
        }
        String pathCompare = path;
        if (!path.equals("/") && path.endsWith("/")) {
            // Delete ending slash.
            pathCompare = path.substring(0, path.length() - 1);
        }
        // Remove leading "/".
        if (path.startsWith("/")) {
            pathCompare = path.substring(1);
        }

        Map<String, String> entitiesPath = ConfigurationManager.getEntitiesRelativePath();
        String uuid;
        String pathTmp;
        for (Map.Entry<String, String> entry : entitiesPath.entrySet()) {
            uuid = entry.getKey();
            pathTmp = entry.getValue();

            if (!pathTmp.equals("/") && pathTmp.endsWith("/")) {
                pathTmp = pathTmp.substring(0, pathTmp.length() - 1);
            }
            // Remove leading "/".
            if (pathTmp.startsWith("/")) {
                pathTmp = pathTmp.substring(1);
            }

            if (pathCompare.equals(pathTmp)) {
                entitiesUUID.add(uuid);
            } else if ((pathCompare.startsWith(pathTmp) || pathTmp.startsWith(pathCompare)) && !pathTmp.isEmpty()) {
                entitiesUUID.add(uuid);
            }
        }
        return entitiesUUID;
    }

    /**
     * Check if path is on a mixin tag (mixin without attributes and applied and
     * depends).
     *
     * @param path
     * @param owner
     * @return false if the path and request is not on mixin tag.
     */
    public static boolean isMixinTagRequest(final String path, final String owner) {
        boolean result;
        Mixin mixin = ConfigurationManager.getUserMixinFromLocation(path, owner);
        result = mixin != null;
        return result;
    }

    /**
     * Is that path is on a category ? like compute/
     *
     * @param path
     * @return
     */
    public static boolean isCollectionOnCategory(String path) {
        String categoryId = Utils.getCategoryFilterSchemeTerm(path, ConfigurationManager.DEFAULT_OWNER);

        return categoryId != null;

    }

    /**
     * Parse a string to a number without knowning its type output.
     *
     * @param str
     * @param instanceClassType can be null.
     * @return a non null number object.
     */
    public static Number parseNumber(String str, String instanceClassType) {
        Number number;
        if (instanceClassType == null) {

            try {
                number = Float.parseFloat(str);

            } catch (NumberFormatException e) {
                try {
                    number = Double.parseDouble(str);
                } catch (NumberFormatException e1) {
                    try {
                        number = Integer.parseInt(str);
                    } catch (NumberFormatException e2) {
                        try {
                            number = Long.parseLong(str);
                        } catch (NumberFormatException e3) {
                            throw e3;
                        }
                    }
                }
            }
        } else {
            switch (instanceClassType) {
            // We know here the instanceClass.

            case "int":
            case "Integer":
                // Convert to integer.
                try {
                    number = Integer.parseInt(str);
                } catch (NumberFormatException ex) {
                    throw ex;
                }
                break;
            case "float":
            case "Float":
                try {
                    number = Float.parseFloat(str);
                } catch (NumberFormatException ex) {
                    throw ex;
                }
                break;
            case "BigDecimal":
            case "double":
            case "Double":
                try {
                    number = Double.parseDouble(str);
                } catch (NumberFormatException ex) {
                    throw ex;
                }

                break;
            case "Long":
            case "long":
                try {
                    number = Long.parseLong(str);
                } catch (NumberFormatException ex) {
                    throw ex;
                }
                break;
            default:
                throw new NumberFormatException("Unknown format.");
            }

        }

        return number;
    }

    /**
     * Convert an input stream to a String object.
     *
     * @param jsonInput
     * @return
     * @throws IOException
     */
    public static String convertInputStreamToString(InputStream jsonInput) throws IOException {
        String contentStr;
        StringBuilder content = new StringBuilder();
        try {
            List<String> lines = IOUtils.readLines(jsonInput, "UTF8");
            for (String line : lines) {
                content.append(line);
            }
            //            if (content.toString().isEmpty()) {
            //                return content.toString();
            //                // throw new IOException("No input text file defined.");
            //            }
        } catch (IOException ex) {
            LOGGER.error("This stream is not a text stream.");
            throw new IOException("The input file is not a text file or has unknown characters.");
        }
        contentStr = content.toString();
        return contentStr;
    }

    /**
     * @param path
     * @return
     */
    public static String getPathWithoutPrefixSuffixSlash(final String path) {
        String pathTmp = path;

        if (path == null || path.isEmpty() || path.equals("/")) {
            return "";
        }

        if (path.startsWith("/")) {
            pathTmp = pathTmp.substring(1);
        }
        if (path.endsWith("/")) {
            pathTmp = pathTmp.substring(0, pathTmp.length() - 1);
        }
        pathTmp.replaceAll("\\s+", "");

        return pathTmp;
    }
}