io.personium.common.utils.PersoniumCoreUtils.java Source code

Java tutorial

Introduction

Here is the source code for io.personium.common.utils.PersoniumCoreUtils.java

Source

/**
 * personium.io
 * Copyright 2014-2018 FUJITSU LIMITED
 *
 * 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 io.personium.common.utils;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.CharEncoding;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;

/**
 * Class that defines various utility functions.
 */
public final class PersoniumCoreUtils {

    /** Logger. */
    static Logger log = LoggerFactory.getLogger(PersoniumCoreUtils.class);

    private static final String AUTHZ_BASIC = "Basic ";
    private static final int BITS_HEX_DIGIT = 4;
    private static final int HEX_DIGIT_MASK = 0x0F;
    private static final int CHARS_PREFIX_ODATA_DATE = 7;
    private static final int CHARS_SUFFIX_ODATA_DATE = 3;

    private static String fqdn = null;

    private PersoniumCoreUtils() {
    }

    /**
     * Set FQDN.
     * @param fqdnValue FQDN of this unit
     */
    public static void setFQDN(String fqdnValue) {
        if (fqdn == null) {
            fqdn = fqdnValue;
        }
    }

    /**
     * Get FQDN.
     * @return FQDN of this unit.
     */
    public static String getFQDN() {
        return fqdn;
    }

    /**
     * Personium's http headers.
     */
    public static class HttpHeaders {
        /** Account????. */
        public static final String X_PERSONIUM_CREDENTIAL = "X-Personium-Credential";
        /**
         * X-Personium-Unit-User.
         * MasterToken???????????
         * ?????????
         */
        public static final String X_PERSONIUM_UNIT_USER = "X-Personium-Unit-User";
        /** Depth. */
        public static final String DEPTH = "Depth";
        /** X-HTTP-Method-Override. */
        public static final String X_HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override";
        /** X-Override. */
        public static final String X_OVERRIDE = "X-Override";
        /** X-Forwarded-Proto. */
        public static final String X_FORWARDED_PROTO = "X-Forwarded-Proto";
        /** X-Forwarded-Host. */
        public static final String X_FORWARDED_HOST = "X-Forwarded-Host";
        /** X-Forwarded-Path. */
        public static final String X_FORWARDED_PATH = "X-Forwarded-Path";
        /** X-Personium-Unit-Host. */
        public static final String X_PERSONIUM_UNIT_HOST = "X-Personium-Unit-Host";
        /** X-Personium-Version. */
        public static final String X_PERSONIUM_VERSION = "X-Personium-Version";
        /** X-Personium-Recursive. */
        public static final String X_PERSONIUM_RECURSIVE = "X-Personium-Recursive";
        /** X-Personium-RequestKey. */
        public static final String X_PERSONIUM_REQUESTKEY = "X-Personium-RequestKey";
        /** X-Personium-EventId header. */
        public static final String X_PERSONIUM_EVENTID = "X-Personium-EventId";
        /** X-Personium-RuleChain header. */
        public static final String X_PERSONIUM_RULECHAIN = "X-Personium-RuleChain";
        /** X-Personium-Via header. */
        public static final String X_PERSONIUM_VIA = "X-Personium-Via";
        // CORS
        /** Access-Control-Allow-Origin. */
        public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
        /** Access-Control-Allow-Headers. */
        public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
        /** Access-Control-Request-Headers. */
        public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
        /** Access-Control-Allow-Methods. */
        public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
        /** Access-Control-Expose-Headers. */
        public static final String ACCESS_CONTROLE_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
        /** Access-Control-Allow-Credentials. */
        public static final String ACCESS_CONTROLE_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
        /** Access-Control-Max-Age. */
        public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";

        /** Origin. */
        public static final String ORIGIN = "Origin";
        /** Allow. */
        public static final String ALLOW = "Allow";
        /** Range. */
        public static final String RANGE = "Range";
        /** Accept-Range. */
        public static final String ACCEPT_RANGES = "Accept-Ranges";
        /** Content-Range. */
        public static final String CONTENT_RANGE = "Content-Range";

        /**
         * ?.
         */
        public static class Value {
            /**
             * *
             */
            public static final String ASTERISK = "*";
        }
    }

    /**
     * Definition of http methods.
     */
    public static class HttpMethod {
        /** MERGE. */
        public static final String MERGE = "MERGE";
        /** MKCOL. */
        public static final String MKCOL = "MKCOL";
        /** PROPFIND. */
        public static final String PROPFIND = "PROPFIND";
        /** PROPPATCH. */
        public static final String PROPPATCH = "PROPPATCH";
        /** ACL. */
        public static final String ACL = "ACL";
        /** COPY. */
        public static final String COPY = "COPY";
        /** MOVE. */
        public static final String MOVE = "MOVE";
        /** LOCK. */
        public static final String LOCK = "LOCK";
        /** UNLOCK. */
        public static final String UNLOCK = "UNLOCK";
    }

    /**
     * Constant definition for XML.
     */
    public static class XmlConst {
        /** urn:x-personium:xmlns. */
        public static final String NS_PERSONIUM = "urn:x-personium:xmlns";
        /** XML Name Space p:. */
        public static final String NS_PREFIX_PERSONIUM = "p";

        /** service. */
        public static final String SERVICE = "service";
        /** odata. */
        public static final String ODATA = "odata";

        /** cellstatus. */
        public static final String CELL_STATUS = "cellstatus";
    }

    /**
     * XML?DOM?????.
     * @param node ???
     * @return ???
     */
    public static String nodeToString(final Node node) {
        StringWriter sw = new StringWriter();
        try {
            Transformer t = TransformerFactory.newInstance().newTransformer();
            t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            t.transform(new DOMSource(node), new StreamResult(sw));
        } catch (TransformerException te) {
            throw new RuntimeException("nodeToString Transformer Exception", te);
        }
        return sw.toString();
    }

    /**
     * ?String???????.
     * @param resPath 
     * @param encoding Encoding
     * @return ???
     */
    public static String readStringResource(final String resPath, final String encoding) {
        InputStream is = null;
        BufferedReader br = null;
        try {
            is = PersoniumCoreUtils.class.getClassLoader().getResourceAsStream(resPath);
            br = new BufferedReader(new InputStreamReader(is, encoding));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            return sb.toString();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * Base64url??.
     * ??RFC648??????????????? ---------------------------------------------------
     * http://tools.ietf.org/html/rfc4648 --------------------------------------------------- 5. Base 64 Encoding with
     * URL and Filename Safe Alphabet The Base 64 encoding with an URL and filename safe alphabet has been used in [12].
     * ????????[12]? ???? An alternative alphabet has been suggested that would use "~" as the
     * 63rd character. Since the "~" character has special meaning in some file system environments, the encoding
     * described in this section is recommended instead. The remaining unreserved URI character is ".", but some file
     * system environments do not permit multiple "." in a filename, thus making the "." character unattractive as well.
     * ???????"~"???? ???"~"?????????? ??????????????????
     * ????"."???????"." ????"."???? The pad character "=" is typically percent-encoded
     * when used in an URI [9], but if the data length is known implicitly, this can be avoided by skipping the padding;
     * see section 3.2. [9]???????"="???? ????????????????
     * ??????????.??? This encoding may be referred to as "base64url". This encoding should not be regarded
     * as the same as the "base64" encoding and should not be referred to as only "base64". Unless clarified otherwise,
     * "base64" refers to the base 64 in the previous section. ????"base64url"??????????
     * "base64"??????????????????? ?????????????????"base64"? ?????? This encoding is
     * technically identical to the previous one, except for the 62:nd and 63:rd alphabet character, as indicated in
     * Table 2. ?????????? ???????????????????? Table 2: The "URL and Filename safe" Base
     * 64 Alphabet ?????? Value Encoding Value Encoding Value Encoding Value Encoding 0 A 17 R
     * 34 i 51 z 1 B 18 S 35 j 52 0 2 C 19 T 36 k 53 1 3 D 20 U 37 l 54 2 4 E 21 V 38 m 55 3 5 F 22 W 39 n 56 4 6 G 23 X
     * 40 o 57 5 7 H 24 Y 41 p 58 6 8 I 25 Z 42 q 59 7 9 J 26 a 43 r 60 8 10 K 27 b 44 s 61 9 11 L 28 c 45 t 62 -
     * (minus) 12 M 29 d 46 u 63 _ 13 N 30 e 47 v (underline) 14 O 31 f 48 w 15 P 32 g 49 x 16 Q 33 h 50 y (pad) =
     * @param in ???byte
     * @return ?????
     */
    public static String encodeBase64Url(final byte[] in) {
        return Base64.encodeBase64URLSafeString(in);
    }

    /**
     * Base64url??.
     * @param inStr 
     * @return 
     */
    public static String encodeBase64Url(final InputStream inStr) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int l = 0;
        try {
            while ((l = inStr.read()) != -1) {
                baos.write(l);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Base64.encodeBase64URLSafeString(baos.toByteArray());
    }

    /**
     * Base64url??.
     * @param in ???
     * @return ??byte
     */
    public static byte[] decodeBase64Url(final String in) {
        return Base64.decodeBase64(in);
    }

    /**
     * ?16????. TODO ??????????????????.
     * @param input ?
     * @return 16
     */
    public static String byteArray2HexString(final byte[] input) {
        StringBuffer buff = new StringBuffer();
        int count = input.length;
        for (int i = 0; i < count; i++) {
            buff.append(Integer.toHexString((input[i] >> BITS_HEX_DIGIT) & HEX_DIGIT_MASK));
            buff.append(Integer.toHexString(input[i] & HEX_DIGIT_MASK));
        }
        return buff.toString();
    }

    /**
     * URL??.
     * @param in Url???
     * @return Url??
     */
    public static String encodeUrlComp(final String in) {
        try {
            return URLEncoder.encode(in, CharEncoding.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * URL??.
     * @param in Url??
     * @return ?
     */
    public static String decodeUrlComp(final String in) {
        try {
            return URLDecoder.decode(in, CharEncoding.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * InputStream?????String??.
     * @param is InputStream
     * @return 
     */
    public static String readInputStreamAsString(InputStream is) {

        InputStreamReader isr = null;
        BufferedReader reader = null;
        String bodyString = null;
        try {

            isr = new InputStreamReader(is, "UTF-8");
            reader = new BufferedReader(isr);
            StringBuffer sb = new StringBuffer();
            int chr;
            while ((chr = is.read()) != -1) {
                sb.append((char) chr);
            }
            bodyString = sb.toString();
        } catch (IllegalStateException e) {
            log.info(e.getMessage());
        } catch (IOException e) {
            log.info(e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (isr != null) {
                    isr.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                log.info(e.getMessage());
            }
        }

        return bodyString;
    }

    /**
     * Authorization?Basic???????.
     * @param authzHeaderValue Authorization?
     * @return id, pw?????????null
     */
    public static String[] parseBasicAuthzHeader(String authzHeaderValue) {
        if (authzHeaderValue == null || !authzHeaderValue.startsWith(AUTHZ_BASIC)) {
            return null;
        }
        try {
            // ???
            byte[] bytes = PersoniumCoreUtils.decodeBase64Url(authzHeaderValue.substring(AUTHZ_BASIC.length()));
            String rawStr = new String(bytes, CharEncoding.UTF_8);
            int pos = rawStr.indexOf(":");
            // ???:???????????
            if (pos == -1) {
                return null;
            }
            String username = rawStr.substring(0, pos);
            String password = rawStr.substring(pos + 1);
            return new String[] { decodeUrlComp(username), decodeUrlComp(password) };
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }

    /**
     * basic???????.
     * @param id id
     * @param pw pw
     * @return basic??
     */
    public static String createBasicAuthzHeader(final String id, final String pw) {
        String line = encodeUrlComp(id) + ":" + encodeUrlComp(pw);
        try {
            return encodeBase64Url(line.getBytes(CharEncoding.UTF_8));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * ??BaseUri?UriInfo??????.
     * @param uriInfo UriInfo
     * @param baseLevelsAbove BaseUriRequestUri????
     * @return UriInfo
     */
    public static UriInfo createUriInfo(final UriInfo uriInfo, final int baseLevelsAbove) {
        PersoniumUriInfo ret = new PersoniumUriInfo(uriInfo, baseLevelsAbove, null);
        return ret;
    }

    /**
     * ??BaseUri?UriInfo??????.
     * @param uriInfo UriInfo
     * @param baseLevelsAbove BaseUriRequestUri????
     * @param add 
     * @return UriInfo
     */
    public static UriInfo createUriInfo(final UriInfo uriInfo, final int baseLevelsAbove, final String add) {
        PersoniumUriInfo ret = new PersoniumUriInfo(uriInfo, baseLevelsAbove, add);
        return ret;
    }

    /**
     * OData?Datetime JSON(Date(\/ ... \/) ?)??Date?????.
     * @param odataDatetime OData?Datetime JSON
     * @return Date
     */
    public static Date parseODataDatetime(final String odataDatetime) {
        String dateValue = odataDatetime.substring(CHARS_PREFIX_ODATA_DATE,
                odataDatetime.length() - CHARS_SUFFIX_ODATA_DATE);
        return new Date(Long.valueOf(dateValue));
    }

    /**
     * OPTIONS??????ResponseBuilder?????.
     * @param allowedMethods ??HTTP.
     * @return ResponseBuilder
     */
    public static ResponseBuilder responseBuilderForOptions(String... allowedMethods) {
        StringBuilder allowedMethodsBuilder = new StringBuilder(javax.ws.rs.HttpMethod.OPTIONS);
        if (allowedMethods != null && allowedMethods.length > 0) {
            allowedMethodsBuilder.append(", ");
            allowedMethodsBuilder.append(StringUtils.join(allowedMethods, ", "));
        }
        return Response.ok().header(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, allowedMethodsBuilder.toString())
                .header(HttpHeaders.ALLOW, allowedMethodsBuilder.toString());
    }

    /**
     * ?BaseUri()??UriInfo????UriInfo?Wrapper.
     */
    public static final class PersoniumUriInfo implements UriInfo {
        UriBuilder baseUriBuilder;
        UriInfo core;

        /**
         * Constructor.
         * @param uriInfo UriInfo
         * @param baseLevelsAbove ????
         * @param add 
         */
        public PersoniumUriInfo(final UriInfo uriInfo, final int baseLevelsAbove, final String add) {
            this.core = uriInfo;
            String reqUrl = uriInfo.getRequestUri().toASCIIString();
            if (reqUrl.endsWith("/")) {
                reqUrl = reqUrl.substring(0, reqUrl.length() - 1);
            }
            String[] urlSplitted = reqUrl.split("/");
            urlSplitted = (String[]) ArrayUtils.subarray(urlSplitted, 0, urlSplitted.length - baseLevelsAbove);
            reqUrl = StringUtils.join(urlSplitted, "/") + "/";
            if (add != null && add.length() != 0) {
                reqUrl = reqUrl + add + "/";
            }
            this.baseUriBuilder = UriBuilder.fromUri(reqUrl);
        }

        @Override
        public String getPath() {
            return this.getPath(true);
        }

        @Override
        public String getPath(final boolean decode) {
            String sReq = null;
            String sBas = null;
            if (decode) {
                sReq = this.getRequestUri().toString();
                sBas = this.getBaseUri().toString();
            } else {
                sReq = this.getRequestUri().toASCIIString();
                sBas = this.getBaseUri().toASCIIString();
            }
            return sReq.substring(sBas.length());
        }

        @Override
        public List<PathSegment> getPathSegments() {
            return this.core.getPathSegments();
        }

        @Override
        public List<PathSegment> getPathSegments(final boolean decode) {
            return this.core.getPathSegments(decode);
        }

        @Override
        public URI getRequestUri() {
            return this.core.getRequestUri();
        }

        @Override
        public UriBuilder getRequestUriBuilder() {
            return this.core.getRequestUriBuilder();
        }

        @Override
        public URI getAbsolutePath() {
            return this.core.getAbsolutePath();
        }

        @Override
        public UriBuilder getAbsolutePathBuilder() {
            return this.core.getAbsolutePathBuilder();
        }

        @Override
        public URI getBaseUri() {
            return this.baseUriBuilder.build();
        }

        @Override
        public UriBuilder getBaseUriBuilder() {
            return this.baseUriBuilder;
        }

        @Override
        public MultivaluedMap<String, String> getPathParameters() {
            return this.core.getPathParameters();
        }

        @Override
        public MultivaluedMap<String, String> getPathParameters(final boolean decode) {
            return this.core.getPathParameters(decode);
        }

        @Override
        public MultivaluedMap<String, String> getQueryParameters() {
            return this.core.getQueryParameters();
        }

        @Override
        public MultivaluedMap<String, String> getQueryParameters(final boolean decode) {
            return this.core.getQueryParameters(decode);
        }

        @Override
        public List<String> getMatchedURIs() {
            return this.core.getMatchedURIs();
        }

        @Override
        public List<String> getMatchedURIs(final boolean decode) {
            return this.core.getMatchedURIs(decode);
        }

        @Override
        public List<Object> getMatchedResources() {
            return this.core.getMatchedResources();
        }
    }
}