All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.brooklyn.util.text.BrooklynVersionSyntax Maven / Gradle / Ivy

Go to download

Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else

There is a newer version: 1.1.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.brooklyn.util.text;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Preconditions;

/** Utilities for parsing and working with versions following the recommended Brooklyn scheme,
 * following major.minor.patch-qualifier syntax,
 * with support for mapping to OSGi. 
 * 

* See tests for examples, {@link VersionComparator} for more notes, and its tests for more examples. */ public class BrooklynVersionSyntax { private static final String SNAPSHOT = "SNAPSHOT"; public static final String USABLE_REGEX = "[^:\\s/\\\\]+"; public static final String DOT = "\\."; public final static String OSGI_TOKEN_CHARS = "A-Za-z0-9_-"; public final static String OSGI_TOKEN_REGEX = "[" + OSGI_TOKEN_CHARS + "]+"; public final static String NUMBER = "[0-9]+"; public final static String QUALIFIER = OSGI_TOKEN_REGEX; public final static String VALID_OSGI_VERSION_REGEX = NUMBER + "(" + DOT + NUMBER + "(" + DOT + NUMBER + "(" + DOT + QUALIFIER + ")?" + ")?" + ")?"; public final static String GOOD_BROOKLYN_VERSION_REGEX = NUMBER + "(" + DOT + NUMBER + "(" + DOT + NUMBER + "(" + "-" + QUALIFIER + ")?" + ")?" + ")?"; private static boolean isUsable(String candidate) { return candidate!=null && candidate.matches(USABLE_REGEX); } /** * For versions we currently work with any non-empty string that does not contain a ':' or whitespace. * However we discourage things that are not OSGi versions; see {@link #isValidOsgiVersion(String)}. * In some places (eg bundles) the use of OSGi version syntax may be enforced. */ public static boolean isUsableVersion(String candidate) { return isUsable(candidate); } /** True if the argument matches the Brooklyn version syntax, * MAJOR.MINOR.POINT-QUALIFIER or part thereof (not ending in a period though), * where the first three are whole numbers and the final piece is any valid OSGi token * (containing letters, numbers, _ and -; no full stops). * See also {@link #isValidOsgiVersion(String)} and note this _requires_ a different separator to OSGi. */ public static boolean isGoodBrooklynVersion(String candidate) { return candidate!=null && candidate.matches(GOOD_BROOKLYN_VERSION_REGEX); } /** True if the argument matches the OSGi version spec, of the form * MAJOR.MINOR.POINT.QUALIFIER or part thereof (not ending in a period though), * where the first three are whole numbers and the final piece is any valid OSGi token * (containing letters, numbers, _ and -; no full stops). * See also {@link #isGoodBrooklynVersion(String)}. */ public static boolean isValidOsgiVersion(String candidate) { return candidate!=null && candidate.matches(VALID_OSGI_VERSION_REGEX); } /** Creates a string satisfying {@link #isValidOsgiVersion(String)} based on the input. * For input satisfying {@link #isGoodBrooklynVersion(String)} the only change will be in the qualifer separator * (from "-" to ".") and making any "0" minor/patch token explicit (so "1-x" becomes "1.0.0.x"), * and the change can be reversed using {@link #toGoodBrooklynVersion(String)} (modulo insertion of "0"'s for minor/patch numbers if missing). * For input satisfying {@link #isValidOsgiVersion(String)}, the only change will be insertions of 0 for minor/patch. * Precise behaviour for other input is not guaranteed but callers can expect output which resembles the input, * with any major/minor/patch string at the front preserved and internal contiguous alphanumeric sequences preserved. */ public static String toValidOsgiVersion(String input) { Preconditions.checkNotNull(input); return toGoodVersion(input, ".", true); /* Note Maven has and used: DefaultMaven2OsgiConverter * from https://github.com/apache/felix/blob/trunk/tools/maven-bundle-plugin/src/main/java/org/apache/maven/shared/osgi/DefaultMaven2OsgiConverter.java * but it (a) is more complicated, and (b) doesn't aggressively find numbers e.g. "1beta" goes to "0.0.0.1beta" instead of "1.0.0.beta" */ } /** * See {@link #toValidOsgiVersion(String)}, but takes a version range (in the standard OSGi format). */ public static String toValidOsgiVersionRange(String input) { String beginning = ""; String ending = ""; if (input.startsWith("[") || input.startsWith("(")) { beginning = input.substring(0, 1); } if (input.endsWith("]") || input.endsWith(")")) { ending = input.substring(input.length() - 1, input.length()); } String middle = input.substring(beginning.length(), input.length() - ending.length()); String[] middleParts = middle.split(","); StringBuilder result = new StringBuilder(); result.append(beginning); for (int i = 0; i < middleParts.length; i++) { String middlePart = middleParts[i]; if (i != 0) result.append(","); result.append(toValidOsgiVersion(middlePart.trim())); } result.append(ending); return result.toString(); } /** Creates a string satisfying {@link #isGoodBrooklynVersion(String)} based on the input. * For input satisfying {@link #isGoodBrooklynVersion(String)} the input will be returned unchanged. * For input satisfying {@link #isValidOsgiVersion(String)} the qualifier separator will be changed to "-", * and {@link #toValidOsgiVersion(String)} can be used to reverse the input (modulo insertion of "0"'s for minor/patch numbers if missing). * Precise behaviour for other input is not guaranteed but callers can expect output which resembles the input, * with any major/minor/patch string at the front preserved and internal contiguous alphanumeric sequences preserved. */ public static String toGoodBrooklynVersion(String input) { return toGoodVersion(input, "-", false); } private static String toGoodVersion(String input, String qualifierSeparator, boolean requireMinorAndPatch) { Preconditions.checkNotNull(input); final String FUZZY_REGEX = "(" + NUMBER + "(" + DOT + NUMBER + "(" + DOT + NUMBER + ")?)?)?" + "(" + ".*)"; Matcher m = Pattern.compile(FUZZY_REGEX).matcher(input); if (!m.matches()) { throw new IllegalStateException("fuzzy matcher should match anything: '"+input+"'"); // sanity check - shouldn't happen } StringBuilder result = new StringBuilder(); if (Strings.isEmpty(m.group(1))) { result.append("0.0.0"); } else { result.append(m.group(1)); if (requireMinorAndPatch) { if (Strings.isEmpty(m.group(2))) { result.append(".0"); } if (Strings.isEmpty(m.group(3))) { result.append(".0"); } } } String q = m.group(4); if (Strings.isNonEmpty(q)) { boolean collapsedUnsupported = false; boolean starting = true; result.append(qualifierSeparator); for (int i=0; i= c) || ('a' <= c && 'z' >= c) || ('0' <= c && '9' >= c); starting = false; if (!include) { if (c=='-' || c=='_' || c=='.') { // treat these as separator chars, and drop them if (q.length()==1) { // unless there are no other chars (e.g. version "1." becomes "1-_" unsupported = true; } } else { // treat other chars as unsupported unsupported = true; } } } else { include = ('A' <= c && 'Z' >= c) || ('a' <= c && 'z' >= c) || ('0' <= c && '9' >= c) || c=='-' || c=='_'; if (!include) { // treat as unsupported, unless we've collapsed if (!collapsedUnsupported) { unsupported = true; } } } if (include) { result.append(c); collapsedUnsupported = false; } else if (unsupported) { // stick a "_" in for unsupported chars result.append('_'); collapsedUnsupported = true; } } } return result.toString(); } /** Returns true if the given strings are equal when mapped according to {@link #toValidOsgiVersion(String)} */ public static boolean equalAsOsgiVersions(String v1, String v2) { if (v1==null || v2==null) return (v1==null && v2==null); return toValidOsgiVersion(v1).equals(toValidOsgiVersion(v2)); } public static boolean isSnapshot(String version) { if (version==null) return false; return version.toUpperCase().contains(SNAPSHOT); } /** * Returns the version without "SNAPSHOT" (normally this will return the next expected release version). * For example, "1.0.0.SNAPSHOT" or "1.0.0-SNAPSHOT" becomes "1.0.0". */ public static String stripSnapshot(String input) { if (input==null) return input; int stripIndex = input.toUpperCase().indexOf(SNAPSHOT); if (stripIndex <= 0) return input; char charBeforeSnapshot = input.charAt(stripIndex - 1); if (charBeforeSnapshot == '.' || charBeforeSnapshot == '_' || charBeforeSnapshot == '-') { stripIndex--; } return (stripIndex <= 0) ? input : input.substring(0, stripIndex); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy