/* * Copyright (c) 2008 Stiftung Deutsches Elektronen-Synchrotron, * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY. * * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS. * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION, * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM */ package org.csstudio.sds.util; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * A utility class, which helps to validate inputs for or apply alias substitutions * to channel names. * * @author Sven Wende * */ public final class ChannelReferenceValidationUtil { /** * Private constructor. */ private ChannelReferenceValidationUtil() { } /** * Regular expression which is used to find alias names in arbitrary texts. */ private static final Pattern FIND_ALIAS_NAME_PATTERN = Pattern .compile("\\$([^$]*)\\$"); /** * Regular expression which is used to validate arbitrary inputs. In general any text is * valid. Optionally inputs can contain aliases, which are bordered by "$" * signs. In this case, the input must contain an even number of "$" signs * and at least one other sign between two "$" signs. */ private static final Pattern VALIDATE_TEXT_PATTERN = Pattern .compile("[^$]*([^$]*\\$[^$]+\\$[^$]*)*[^$]*"); /** * Generates a regular expression which is used to replace aliases in arbitrary texts. * * @param aliasName * the alias name, which should be found (without the bordering * "$" signs * * @return a regular expression which is used to replace aliases in arbitrary texts * */ private static Pattern createSearchPattern(final String aliasName) { return Pattern.compile("(\\$" + aliasName + "\\$)"); } public static List<String> getRequiredAliasNames(final String input) { List<String> result = new ArrayList<String>(); // Get a Matcher based on the target string. Matcher matcher = FIND_ALIAS_NAME_PATTERN.matcher(input); // Find all the matches. while (matcher.find()) { String name = matcher.group(1); result.add(name); } return result; } /** * Tests the validity of the provided input string. In general any non-empty * text is valid. Optionally inputs can contain aliases, which are bordered * by "$" signs. In this case, the input must contain an even number of "$" * signs and at least one other sign between two "$" signs. * * @param input * the text to be checked * @return true, if the text is valid, false otherwise */ public static boolean testValidity(final String input) { boolean result = true; if (input == null) { result = false; } else { Matcher m = VALIDATE_TEXT_PATTERN.matcher(input); result = m.matches(); } return result; } /** * Creates a canonical representation of the provided input string in which * all aliases are replaced by their values. All aliases need to be * delivered in a Map. * * @param input * the input text * @param aliases * a map, which contains the aliases * @throws ChannelReferenceValidationException * this exception is thrown, if the specified input or the * aliases cannot be processed * * @return a canonical representation of the provided input string in which * all aliases are replaced by their values */ public static String createCanonicalName(final String input, final Map<String, String> aliases) throws ChannelReferenceValidationException { // check validity of the input if (!testValidity(input)) { throw new ChannelReferenceValidationException("The name >" + input + "< is invalid"); } // check validity of all aliases for (String alias : aliases.keySet()) { String aliasValue = aliases.get(alias); if (!testValidity(aliasValue)) { throw new ChannelReferenceValidationException("The alias value >" + aliasValue + "< for the alias >" + alias + "< is invalid."); } } return getFullQualifiedName(input, new ArrayList<String>(), false, aliases); } /** * This method is called recursively, to apply alias substitutions to the * provided input text. * * @param input * the text input * @param markerList * a marker list, which contains aliases that are already on the * stack * @param isAlias * flag, which indicates whether the input is a alias (this is * necessary because aliases might contain other aliases which is * handled via the same recursive call) * @param aliases * the existing aliases as provided by the user * * @return a canonical name in which all aliases are replaced by their real * values * * @throws ChannelReferenceValidationException * this exception is thrown, if an error occurs during the * replacement procedure (e.g. in case of circular references * between aliases (e.g. when $a$=$b$ and $b$=$a$) */ private static String getFullQualifiedName(final String input, final List<String> markerList, final boolean isAlias, final Map<String, String> aliases) throws ChannelReferenceValidationException { String result = ""; if (isAlias) { if (!aliases.containsKey(input)) { throw new ChannelReferenceValidationException("The alias <" + input + "> could not be resolved!"); } else { if (markerList.contains(input)) { throw new ChannelReferenceValidationException("The alias <" + input + "> causes a circular relation."); } else { result = aliases.get(input); markerList.add(input); } } } else { result = input; } // Get a Matcher based on the target string. Matcher matcher = FIND_ALIAS_NAME_PATTERN.matcher(result); // Find all the matches. while (matcher.find()) { String requiredAliasName = matcher.group(1); String canonicalName = getFullQualifiedName(requiredAliasName, markerList, true, aliases); if(canonicalName==null || canonicalName.length()<=0) { canonicalName = "??"; } Matcher matcher2 = createSearchPattern(requiredAliasName).matcher( result); result = matcher2.replaceAll(canonicalName); } return result; } }