001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.engine.service.shared;
018
019import java.net.MalformedURLException;
020import java.net.URI;
021import java.net.URISyntaxException;
022import java.net.URL;
023import java.util.Optional;
024import java.util.function.Function;
025
026import org.conqat.engine.resource.util.UniformPathUtils;
027import org.conqat.lib.commons.string.StringUtils;
028
029import com.google.common.net.UrlEscapers;
030
031/**
032 * Utility methods for services.
033 */
034public class ServiceUtils {
035
036        /**
037         * Encodes the given url path segment. Slashes will be escaped. If you want to
038         * keep them you need to split the input before and supply them one by one.
039         */
040        public static String encodePathSegment(String pathSegment) {
041                return UrlEscapers.urlPathSegmentEscaper().escape(pathSegment);
042        }
043
044        /**
045         * Encodes the given value as query parameter (includes slashes and + symbols).
046         */
047        public static String encodeQueryParameter(String queryParameter) {
048                return UrlEscapers.urlFormParameterEscaper().escape(queryParameter);
049        }
050
051        /**
052         * Encodes the given uniform path by URL-encoding each segment while preserving
053         * the slashes.
054         */
055        public static String encodeUniformPath(String uniformPath) {
056                boolean leadingSlash = uniformPath.startsWith("/");
057
058                String[] parts = UniformPathUtils.splitPath(uniformPath);
059                for (int i = 0; i < parts.length; i++) {
060                        parts[i] = encodePathSegment(parts[i]);
061                }
062                if (leadingSlash) {
063                        return "/" + UniformPathUtils.concatenate(parts);
064                }
065                return UniformPathUtils.concatenate(parts);
066        }
067
068        /** Uses Java API to check if the server address is valid */
069        public static boolean isValidServerAddress(String address) {
070                try {
071                        // Check whether the given address is both a valid URL and a valid
072                        // URI.
073                        new URL(address);
074                        new URI(address);
075                } catch (URISyntaxException e) {
076                        return false;
077                } catch (MalformedURLException e) {
078                        return false;
079                }
080                return true;
081        }
082
083        /**
084         * Produces a specific error message if the identifier is invalid (e.g.,
085         * contains linebreaks, invisible unicode chars, or is empty). The error message
086         * contains the (truncated) text if it is not empty.
087         * 
088         * @param identifierText
089         *            the text of the identifier (e.g., "x" or "foo")
090         * @param identifierDescription
091         *            a description of what this identifier should be (e.g., "Group
092         *            name" or "Id"). This is used at the beginning of the error message
093         *            and therefore should start with an uppercase letter.
094         */
095        public static Optional<String> getErrorMessageForInvalidIdentifiers(String identifierText,
096                        String identifierDescription) {
097                Function<String, String> truncate = identifier -> "\""
098                                + StringUtils.removeAll(StringUtils.truncate(identifier, 9, "..."), "\n") + "\"";
099                if (identifierText.contains("\n")) {
100                        return Optional.of(identifierDescription + " " + truncate.apply(identifierText) + " contains linebreaks");
101                }
102                if (identifierText.matches(".*\\p{C}.*")) {
103                        return Optional.of(identifierDescription + " " + truncate.apply(identifierText)
104                                        + " contains invisible Unicode control characters");
105                }
106                if (identifierText.equals(StringUtils.EMPTY_STRING)) {
107                        return Optional.ofNullable(identifierDescription + " is empty");
108                }
109                return Optional.empty();
110        }
111}