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}