[java-shib-profile] branch main updated: IDP-2121 Future Proofing the Module Plugin infrastructure for Future SP use
Rod Widdowson
rdw at steadingsoftware.com
Thu Jun 8 14:04:12 UTC 2023
This is an automated email from the git hooks/post-receive script.
rdw pushed a commit to branch main
in repository java-shib-profile.
View the commit online:
http://git.shibboleth.net/view/?p=java-shib-profile.git;a=commit;h=d33ce8b112042c88b09cef9369ee9c78c0ecf3cd
The following commit(s) were added to refs/heads/main by this push:
new d33ce8b IDP-2121 Future Proofing the Module Plugin infrastructure for Future SP use
d33ce8b is described below
commit d33ce8b112042c88b09cef9369ee9c78c0ecf3cd
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Jun 8 15:03:02 2023 +0100
IDP-2121 Future Proofing the Module Plugin infrastructure for Future SP use
https://shibboleth.atlassian.net/browse/IDP-2121
Introduce net.shibboleth.profile.installablecomponent
And move the worder classes from their temporary home in
idp...plugin
---
.../InstallableComponentInfo.java | 334 +++++++++++++++++++++
.../InstallableComponentSupport.java | 175 +++++++++++
.../InstallableComponentVersion.java | 185 ++++++++++++
.../profile/installablecomponent/package-info.java | 24 ++
4 files changed, 718 insertions(+)
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentInfo.java b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentInfo.java
new file mode 100644
index 0000000..f01ef01
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentInfo.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.profile.installablecomponent;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import net.shibboleth.profile.installablecomponent.InstallableComponentSupport.SupportLevel;
+import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Class which encapsulates the information about a given Installable Component as downloaded
+ * from the appropriate location (as a Properties file).
+ * Different variants deal with the max and min supported versions (Plugins get them from a file
+ * Non plugins derive them from the version under consideration.
+ */
+public abstract class InstallableComponentInfo {
+
+ /** regexp for spaces. */
+ private static final Pattern SPACE_CONTAINING = Pattern.compile("\\s+");
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(InstallableComponentInfo.class);
+
+ /** The support information. */
+ @Nonnull private final Map<InstallableComponentVersion, InstallableComponentInfo.VersionInfo> versionInfo = new HashMap<>();
+
+ /** The Download information. */
+ @Nonnull private final Map<InstallableComponentVersion, Pair<URL,String>> downloadInfo = new HashMap<>();
+
+ /** The Id. */
+ @Nonnull private final String componentId;
+
+ /** Whether the information was sufficient. */
+ private boolean allInfoPresent = true;
+
+ /**
+ * Constructor.
+ *
+ * @param id the id we care about
+ * @param props all the properties.
+ */
+ public InstallableComponentInfo(@Nonnull final String id, @Nonnull final Properties props) {
+ componentId = id;
+ parse(props);
+ }
+
+ /** Did the property file have enough information?
+ * @return true if something was missing.
+ */
+ public boolean isInfoComplete() {
+ return allInfoPresent;
+ }
+
+ /** Get the base URL for this version.
+ * @param version which version
+ * @return the base URL
+ */
+ @Nullable public URL getUpdateURL(@Nonnull final InstallableComponentVersion version) {
+ final Pair<URL, String> p = downloadInfo.get(version);
+ if (p == null) {
+ return null;
+ }
+ return p.getFirst();
+ }
+
+ /** Get the base Name for this version.
+ * @param version which version
+ * @return the base name
+ */
+ @Nullable public String getUpdateBaseName(@Nonnull final InstallableComponentVersion version) {
+ final Pair<URL, String> p = downloadInfo.get(version);
+ if (p == null) {
+ return null;
+ }
+ return p.getSecond();
+ }
+
+ /** Get the raw version info for this component.
+ * @return the info.
+ */
+ @Nonnull public Map<InstallableComponentVersion, InstallableComponentInfo.VersionInfo> getAvailableVersions() {
+ return versionInfo;
+ }
+
+ /** Get the Installable Component Id under consideration
+ * @return Returns the componentId.
+ */
+ @Nonnull protected String getComponentId() {
+ return componentId;
+ }
+
+ /** (try to) populate the information about this component.
+ * @param props what to load.
+ */
+ private void parse(@Nonnull final Properties props) {
+ final String name = componentId + InstallableComponentSupport.AVAILABLE_VERSIONS_PROPERTY_SUFFIX;
+ final String availableVersions = StringSupport.trim(props.getProperty(name));
+ if (availableVersions == null) {
+ log.warn("Component {}: Could not find {} property.", componentId, name);
+ allInfoPresent = false;
+ } else {
+ handleAvailableVersions(props, availableVersions);
+ }
+ }
+
+ /** Given a version find out more.
+ * @param props the property files for this component we are looking at
+ * @param version the version in question.
+ */
+ private void handleAvailableVersion(@Nonnull final Properties props, @Nonnull final String version) {
+ final InstallableComponentVersion theVersion = new InstallableComponentVersion(version);
+ if (theVersion.getMajor() == 0 && theVersion.getMinor() == 0 && theVersion.getPatch() == 0) {
+ log.warn("Component {}: Improbable version {}", componentId, version);
+ }
+ if (versionInfo.containsKey(theVersion)) {
+ log.warn("Component {}: Duplicate version {}", componentId, version);
+ }
+
+ final InstallableComponentVersion maxVersionInfo = getMaxVersion(props, version);
+ if (maxVersionInfo == null) {
+ log.warn("Component {}, Version {}: Could not find max idp version.", componentId, version);
+ allInfoPresent = false;
+ return;
+ }
+
+ final InstallableComponentVersion minVersionInfo = getMinVersion(props, version);
+ if (minVersionInfo == null) {
+ log.warn("Component {}, Version {}: Could not find min idp version.", componentId, version);
+ allInfoPresent = false;
+ return;
+ }
+
+ final String supportLevelString = StringSupport.trimOrNull(
+ props.getProperty(componentId + InstallableComponentSupport.SUPPORT_LEVEL_INTERFIX + version));
+ InstallableComponentSupport.SupportLevel supportLevel;
+ if (supportLevelString == null) {
+ log.debug("Component {}, Version {}: Could not find support level for {}.", componentId, version);
+ supportLevel = SupportLevel.Unknown;
+ } else {
+ try {
+ supportLevel = Enum.valueOf(SupportLevel.class, supportLevelString);
+ } catch (final IllegalArgumentException e) {
+ log.warn("Component {}, Version {}: Invalid support level {}.", componentId, version, supportLevelString);
+ supportLevel = SupportLevel.Unknown;
+ }
+ }
+
+ log.debug("Component {}: MaxIdP {}, MinIdP {}, Support Level {}",
+ componentId, maxVersionInfo, minVersionInfo, supportLevel);
+ final InstallableComponentInfo.VersionInfo info;
+ info = new InstallableComponentInfo.VersionInfo(maxVersionInfo, minVersionInfo, supportLevel);
+ versionInfo.put(theVersion, info);
+ String downloadURL = StringSupport.trimOrNull(
+ getDefaultedValue(props, InstallableComponentSupport.DOWNLOAD_URL_INTERFIX, version));
+ final String baseName = StringSupport.trimOrNull(
+ getDefaultedValue(props, InstallableComponentSupport.BASE_NAME_INTERFIX, version));
+ if (baseName != null && downloadURL != null) {
+ try {
+ if (!downloadURL.endsWith("/")) {
+ downloadURL += "/";
+ }
+ final URL url = new URL(downloadURL);
+ downloadInfo.put(theVersion, new Pair<>(url, baseName));
+ log.trace("Component {}, version {}: Added download URL {} baseName {} for {}",
+ componentId, theVersion, url, baseName);
+ } catch (final MalformedURLException e) {
+ log.warn("Component {}, version {}: Download URL '{}' could not be constructed",
+ componentId, theVersion, downloadURL, e);
+ }
+ } else {
+ log.info("Component {}, version {}: no download information present", componentId, theVersion);
+ }
+ }
+
+ /** Find the max supported version version we can be installed into.
+ * @param props the properties to look at
+ * @param version the component version we are enquiring about
+ * @return the version null if not found.
+ */
+ @Nullable abstract protected InstallableComponentVersion getMaxVersion(@Nonnull final Properties props, @Nonnull final String version);
+
+ /** Find the min supported version we can be installed into.
+ * @param props the properties to look at
+ * @param version the component version we are enquiring about
+ * @return the version null if not found.
+ */
+ @Nullable abstract protected InstallableComponentVersion getMinVersion(@Nonnull final Properties props, @Nonnull final String version);
+
+ /** Given a list of versions find out more.
+ * @param props the property files for the component we are looking at
+ * @param availableVersions a space delimited array of versions
+ */
+ private void handleAvailableVersions(@Nonnull final Properties props, @Nonnull final String availableVersions) {
+ final String[] versions = SPACE_CONTAINING.split(availableVersions, 0);
+
+ log.debug("Component {}: Available versions : {} ", componentId, availableVersions);
+ for (final String version:versions) {
+ assert version != null;
+ log.debug("Component {}: Considering {}", componentId, version);
+ handleAvailableVersion(props, version);
+ }
+ }
+
+ /** Look up the key derived from the component, the interfix and the version, but if that
+ * fails look for a templated definition.
+ * @param props what to look in
+ * @param interfix the interface (between the ID and the version)
+ * @param version the version.
+ * @return the suitable value
+ */
+ @Nullable private String getDefaultedValue(@Nonnull final Properties props, @Nonnull final String interfix, @Nonnull final String version) {
+ String result = props.getProperty(componentId + interfix + version);
+ if (result != null) {
+ return result;
+ }
+ result = props.getProperty(componentId + interfix + InstallableComponentSupport.VERSION_PATTERN);
+ if (result == null) {
+ return result;
+ }
+ return result.replaceAll(InstallableComponentSupport.VERSION_PATTERN_REGEX, version);
+ }
+
+ /** Can the specified component be installed into this version?
+ * @param componentVersion the version if the component as a {@link InstallableComponentVersion}
+ * @param intsallIntoVersion the version if the IDP as a {@link InstallableComponentVersion}
+ * @return whether it is supported.
+ */
+ public boolean isSupportedWithIdPVersion(@Nonnull final InstallableComponentVersion componentVersion, @Nonnull final InstallableComponentVersion intsallIntoVersion) {
+ final InstallableComponentInfo.VersionInfo info = versionInfo.get(componentVersion);
+ if (info == null) {
+ log.error("Component {}: Unknown version {} supplied.", componentId, componentVersion);
+ log.debug("Component {}: Available {}", componentId, versionInfo.keySet());
+ return false;
+ }
+ return InstallableComponentInfo.isSupportedWithIdPVersion(info, intsallIntoVersion);
+ }
+
+ /** Can the specified component be installed into this version?
+ * Worker method for all 'isSupportedWith' classes.
+ * @param componentVersionInfo the version info to consider
+ * @param installIntoVersion the version as a {@link InstallableComponentVersion}
+ * @return whether it is supported.
+ */
+ public static boolean isSupportedWithIdPVersion(@Nonnull final VersionInfo componentVersionInfo,
+ @Nonnull final InstallableComponentVersion installIntoVersion) {
+ final int maxCompare = installIntoVersion.compareTo(componentVersionInfo.getMaxSupported());
+ if (maxCompare >= 0) {
+ // Exclusive:
+ // IdP (test against) Version is GREATER THAN OR EQUAL to our Max
+ return false;
+ }
+ final int minCompare = installIntoVersion.compareTo(componentVersionInfo.getMinSupported());
+ if (minCompare >= 0) {
+ // Inclusive:
+ // IdP (test against) version is GREATER THAN OR EQUAL to our Min
+ return true;
+ }
+ return false;
+ }
+
+ /** Encapsulation of the information about a given IdP version. */
+ public static class VersionInfo {
+
+ /** Maximum version - this version is NOT SUPPORTED. */
+ private final InstallableComponentVersion maxSupported;
+
+ /** Minimum version - this version IS supported. */
+ private final InstallableComponentVersion minSupported;
+
+ /** support level. */
+ private final SupportLevel supportLevel;
+
+ /**
+ * Constructor.
+ *
+ * @param max support level
+ * @param min support level
+ * @param support support level
+ */
+ public VersionInfo(final InstallableComponentVersion max, final InstallableComponentVersion min, final SupportLevel support) {
+ maxSupported = max;
+ minSupported = min;
+ supportLevel = support;
+ }
+
+ /** get Maximum version - this version is NOT SUPPORTED.
+ * @return Returns the maxSupported.
+ */
+ public InstallableComponentVersion getMaxSupported() {
+ return maxSupported;
+ }
+
+ /** get Minimum (IdP) version - this version IS supported.
+ * @return Returns the minSupported.
+ */
+ public InstallableComponentVersion getMinSupported() {
+ return minSupported;
+ }
+
+ /** get support level.
+ * @return Returns the supportLevel.
+ */
+ public SupportLevel getSupportLevel() {
+ return supportLevel;
+ }
+ }
+}
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentSupport.java b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentSupport.java
new file mode 100644
index 0000000..ec78956
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentSupport.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.profile.installablecomponent;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.opensaml.security.httpclient.HttpClientSecurityContextHandler;
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
+import org.slf4j.Logger;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo.VersionInfo;
+import net.shibboleth.profile.plugin.Plugin;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.spring.httpclient.resource.HTTPResource;
+
+/** Useful methods for supporting Installable Components.
+ *
+ */
+public final class InstallableComponentSupport {
+
+ /** Property Name suffix for available versions inside {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String AVAILABLE_VERSIONS_PROPERTY_SUFFIX = ".versions";
+
+ /** Property Name for Download directory {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String DOWNLOAD_URL_INTERFIX = ".downloadURL.";
+
+ /** Property Name for download name {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String BASE_NAME_INTERFIX = ".baseName.";
+
+ /** Property Name for max supported IdP version inside inside {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String MAX_IDP_VERSION_INTERFIX = ".idpVersionMax.";
+
+ /** Property Name for minimum supported IdP version inside inside {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String MIN_IDP_VERSION_INTERFIX = ".idpVersionMin.";
+
+ /** Property Name for support level inside inside {@link Plugin#getUpdateURLs()}. */
+ @Nonnull public static final String SUPPORT_LEVEL_INTERFIX = ".supportLevel.";
+
+ /** Used for specifying templated keynames. */
+ @Nonnull public static final String VERSION_PATTERN = "%{version}";
+
+ /** Used for specifying templated results. */
+ @Nonnull public static final String VERSION_PATTERN_REGEX = "\\%\\{version\\}";
+
+ /** Value for support level pointed to by {@link #SUPPORT_LEVEL_INTERFIX}.*/
+ public static enum SupportLevel {
+ /** The current release. */
+ Current,
+ /** Still working but a new version is available. */
+ OutOfDate,
+ /** Out of Support. */
+ Unsupported,
+ /** Security alerts against this plugin. */
+ Secadv,
+ /** Withdrawn. */
+ Withdrawn,
+ /** Nothing published. */
+ Unknown
+ }
+
+ /** Class logger. */
+ @Nonnull private static Logger log = LoggerFactory.getLogger(InstallableComponentSupport.class);
+
+ /** Constructor. */
+ private InstallableComponentSupport() {
+ }
+
+ /** Find the best update version (plugin or IdP).
+ * @param installIntoVersion The IdP version to check.
+ * @param pluginVersion The Plugin version
+ * @param pluginInfo all about the plugin
+ * @return the best version (or null)
+ */
+ @Nullable static public InstallableComponentVersion getBestVersion(
+ @Nonnull final InstallableComponentVersion installIntoVersion,
+ @Nonnull final InstallableComponentVersion pluginVersion,
+ @Nonnull final InstallableComponentInfo pluginInfo) {
+ final List<InstallableComponentVersion> availableVersions = new ArrayList<>(pluginInfo.getAvailableVersions().keySet());
+ availableVersions.sort(null);
+ log.debug("Considering versions: {}", availableVersions);
+
+ for (int i = availableVersions.size()-1; i >= 0; i--) {
+ final InstallableComponentVersion version = availableVersions.get(i);
+ if (version.compareTo(pluginVersion) <= 0) {
+ log.debug("Version {} is less than or the same as {}. All done", version, pluginVersion);
+ return null;
+ }
+ final VersionInfo versionInfo = pluginInfo.getAvailableVersions().get(version);
+ if (versionInfo.getSupportLevel() != SupportLevel.Current) {
+ log.debug("Version {} has support level {}, ignoring", version, versionInfo.getSupportLevel());
+ continue;
+ }
+ if (!pluginInfo.isSupportedWithIdPVersion(version, installIntoVersion)) {
+ log.debug("Version {} is not supported with Application Version {}", version, installIntoVersion);
+ continue;
+ }
+ log.debug("Version {} is supported with Application Version {}", version, installIntoVersion);
+ if (pluginInfo.getUpdateURL(version) == null || pluginInfo.getUpdateBaseName(version) == null) {
+ log.debug("Version {} is does not have update information", version);
+ continue;
+ }
+ return version;
+ }
+ return null;
+ }
+
+ /** Load the property file describing all the plugin we know about from a known location.
+ * @param updateURLs where to look
+ * @param client the http client to use
+ * @param securityParameters the HttpClientSecurityParameters, if any
+ * @return the property files for the component.
+ */
+ @Nullable public static Properties loadInfo(@Nonnull final List<URL> updateURLs, @Nonnull final HttpClient client,
+ @Nullable final HttpClientSecurityParameters securityParameters) {
+ final Properties props = new Properties();
+ for (final URL url: updateURLs) {
+ final Resource propertyResource;
+ try {
+ if ("file".equals(url.getProtocol())) {
+ final String path =url.getPath();
+ assert path != null;
+ propertyResource = new FileSystemResource(path);
+ } else if ("http".equals(url.getProtocol()) || "https".equals(url.getProtocol())) {
+ final HTTPResource httpResource;
+ propertyResource = httpResource = new HTTPResource(client , url);
+ final HttpClientSecurityContextHandler handler = new HttpClientSecurityContextHandler();
+ handler.setHttpClientSecurityParameters(securityParameters);
+ handler.initialize();
+ httpResource.setHttpClientContextHandler(handler);
+ } else {
+ log.error("Only file and http[s] URLs are allowed");
+ continue;
+ }
+ log.debug("Plugin Listing: Looking for update at {}", propertyResource.getDescription());
+ if (!propertyResource.exists()) {
+ log.info("{} could not be located", propertyResource.getDescription());
+ continue;
+ }
+ props.load(propertyResource.getInputStream());
+ return props;
+ } catch (final IOException | ComponentInitializationException e) {
+ log.error("Could not open Update URL {} :", url, e);
+ continue;
+ }
+ }
+ log.error("Could not locate any active update servers");
+ return null;
+ }
+}
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentVersion.java b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentVersion.java
new file mode 100644
index 0000000..67ef39f
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/InstallableComponentVersion.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.profile.installablecomponent;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.profile.plugin.Plugin;
+import net.shibboleth.profile.module.Module;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * A version string (Major.minor.patch) as a handy class.
+ */
+public class InstallableComponentVersion implements Comparable<InstallableComponentVersion>{
+
+ /** arbitrary maximum (to help hashing and sanity). */
+ private static final int MAX_VNO = 10000;
+
+ /** Major version. */
+ private int major;
+
+ /** Minor version. */
+ private int minor;
+
+ /** Patch version. */
+ private int patch;
+
+ /**
+ * Constructor.
+ *
+ * @param version what to build from
+ * @throws NumberFormatException if it doesn't fit a 1.2.3 format or if the values are
+ * out of range
+ */
+ public InstallableComponentVersion(final String version) throws NumberFormatException {
+
+ final String versionStr = StringSupport.trimOrNull(version);
+ if (null == versionStr) {
+ throw new NumberFormatException("Empty Version not allowed");
+ }
+
+ final String[] components = versionStr.split("\\.|\\+|-");
+ if (components.length >= 1) {
+ major = parseValue(components[0]);
+ }
+ if (components.length >= 2) {
+ minor = parseValue(components[1]);
+ }
+ if (components.length >= 3) {
+ patch = parseValue(components[2]);
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param plugin what to get the version of.
+ * @throws NumberFormatException if the values are out of range
+ */
+ public InstallableComponentVersion(@Nonnull final Plugin<? extends Module> plugin) throws NumberFormatException {
+ this(plugin.getMajorVersion(), plugin.getMinorVersion(), plugin.getPatchVersion());
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param maj Major Version
+ * @param min Minor Version
+ * @param pat Patch Version
+ * @throws NumberFormatException if the values are out of range
+ */
+ public InstallableComponentVersion(final int maj, final int min, final int pat) throws NumberFormatException {
+ major = maj;
+ if (maj < 0 || maj >= MAX_VNO) {
+ throw new NumberFormatException("Improbable major version number : " + maj);
+ }
+ minor = min;
+ if (min < 0 || min >= MAX_VNO) {
+ throw new NumberFormatException("Improbable minor version number : " + min);
+ }
+ patch = pat;
+ if (pat < 0 || pat >= MAX_VNO) {
+ throw new NumberFormatException("Improbable patch version number : " + pat);
+ }
+ }
+
+ /** Get the major version.
+ * @return Returns the major version.
+ */
+ public int getMajor() {
+ return major;
+ }
+
+ /** Get the minor version.
+ * @return Returns the minor version.
+ */
+ public int getMinor() {
+ return minor;
+ }
+
+ /** Get the patch version.
+ * @return Returns the patch version.
+ */
+ public int getPatch() {
+ return patch;
+ }
+
+ /** Is this version all zeros (usually as a result of a parsing issue.
+ * @return if all nulls */
+ public boolean isNull() {
+ return major == 0 && minor ==0 && patch == 0;
+ }
+
+ /** Helper function for the constructor.
+ *
+ * Parse a string into an int with a range check.
+ * @param valueAsString what to parse
+ * @return the value as an int
+ * @throws NumberFormatException if {@link Integer#parseInt(String, int)} does
+ * or if the value is less than 0 or > {@link #MAX_VNO}.
+ */
+ private int parseValue(final String valueAsString) throws NumberFormatException{
+ final int value = Integer.parseInt(valueAsString);
+ if (value < 0 || value >= MAX_VNO) {
+ throw new NumberFormatException("Improbable version number : " + value);
+ }
+ return value;
+ }
+
+ /** {@inheritDoc} */
+ public boolean equals(final Object obj) {
+ if (obj instanceof InstallableComponentVersion) {
+ final InstallableComponentVersion other= (InstallableComponentVersion)obj;
+ return other.major == major && other.minor == minor && other.patch == patch;
+ }
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public int hashCode() {
+ long l = major*MAX_VNO*MAX_VNO;
+ l += minor * MAX_VNO;
+ l += patch;
+ return Long.hashCode(l);
+ }
+
+ /**
+ * Compares this object with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.
+ * {@inheritDoc} */
+ public int compareTo(final InstallableComponentVersion other) {
+ if (major == other.major) {
+ if (minor == other.minor) {
+ return patch - other.patch;
+ }
+ return minor - other.minor;
+ }
+ return major - other.major;
+ }
+
+ /** {@inheritDoc} */
+ public String toString() {
+ return new StringBuffer(8).append(Integer.toString(major))
+ .append('.')
+ .append(Integer.toString(minor))
+ .append('.')
+ .append(Integer.toString(patch)).toString();
+ }
+}
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/package-info.java b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/package-info.java
new file mode 100644
index 0000000..a0242b5
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/installablecomponent/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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.
+ */
+
+/**
+ * Classes for "Installable Components". Currently The IdP and IdP plugins.
+ */
+ at NonnullElements
+package net.shibboleth.profile.installablecomponent;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list