[java-shib-profile] 03/03: IDP-2121 Future Proofing the Module Plugin infrastructure for Future SP use

Rod Widdowson rdw at steadingsoftware.com
Fri Jun 9 09:35:30 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=f1fe7542c6abc9a31b1f759636c414c51ebc3180

commit f1fe7542c6abc9a31b1f759636c414c51ebc3180
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Thu Jun 8 19:46:39 2023 +0100

    IDP-2121 Future Proofing the Module Plugin infrastructure for Future SP use
    
    https://shibboleth.atlassian.net/browse/IDP-2121
    
    Push the Property driven Plugin down to shib-profile
---
 .../shibboleth/profile/plugin/PluginException.java |  67 ++++++
 .../profile/plugin/PropertyDrivenPlugin.java       | 233 +++++++++++++++++++++
 2 files changed, 300 insertions(+)

diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PluginException.java b/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PluginException.java
new file mode 100644
index 0000000..b82d945
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PluginException.java
@@ -0,0 +1,67 @@
+/*
+ * 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.plugin;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Plugin exception class.
+ * 
+ * @since 9.0.0
+ */
+ at ThreadSafe
+public class PluginException extends Exception {
+
+    /** Serial number. */
+    private static final long serialVersionUID = -2356509887689187370L;
+
+    /** Constructor. */
+    public PluginException() {
+        
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param message exception message
+     */
+    public PluginException(@Nullable final String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param wrappedException exception to be wrapped by this one
+     */
+    public PluginException(@Nullable final Exception wrappedException) {
+        super(wrappedException);
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param message exception message
+     * @param wrappedException exception to be wrapped by this one
+     */
+    public PluginException(@Nullable final String message, @Nullable final Exception wrappedException) {
+        super(message, wrappedException);
+    }
+    
+}
\ No newline at end of file
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PropertyDrivenPlugin.java b/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PropertyDrivenPlugin.java
new file mode 100644
index 0000000..90f8173
--- /dev/null
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/plugin/PropertyDrivenPlugin.java
@@ -0,0 +1,233 @@
+/*
+ * 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.plugin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
+import net.shibboleth.shared.annotation.constraint.NonNegative;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.profile.module.Module;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Implementation of {@link IdPPlugin} relying on Java {@link Properties}.
+ * 
+ * @since 4.1.0
+ */
+public abstract class PropertyDrivenPlugin<T extends Module> extends AbstractPlugin<T> implements Plugin<T> {
+
+    /** Default name of plugin properties resource. */
+    @Nonnull @NotEmpty public static final String DEFAULT_RESOURCE = "plugin.properties";
+
+    /** Property for plugin ID. */
+    @Nonnull @NotEmpty public static final String PLUGIN_ID_PROPERTY = "plugin.id";
+
+    /** Property for plugin version. */
+    @Nonnull @NotEmpty public static final String PLUGIN_VERSION_PROPERTY = "plugin.version";
+
+    /** Property for plugin license. */
+    @Nonnull @NotEmpty public static final String PLUGIN_LICENSE_PROPERTY = "plugin.license";
+
+    /** Prefix of property for plugin update URL. */
+    @Nonnull @NotEmpty public static final String PLUGIN_URL_PROPERTY = "plugin.url.";
+
+    /** Property for plugin's required modules. */
+    @Nonnull @NotEmpty public static final String PLUGIN_REQ_MODULES_PROPERTY = "plugin.modules.required";
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(PropertyDrivenPlugin.class);
+
+    /** Properties describing plugin. */
+    @Nonnull private final Properties pluginProperties;
+
+    /** Non-defaulted plugin ID. */
+    @Nullable private String pluginId;
+    
+    /** Handles parsing of plugin version. */
+    @Nullable private InstallableComponentVersion pluginVersion;
+    
+    /** Plugin update URLs. */
+    @Nonnull @NonnullElements private List<URL> updateURLs = CollectionSupport.emptyList();
+    
+    /** Required modules. */
+    @Nonnull @NonnullElements private Set<String> requiredModules = CollectionSupport.emptySet();
+
+    /**
+     * Constructor.
+     *
+     * @param claz type of object used to locate default module.properties resource
+     * 
+     * @throws IOException if unable to read file
+     * @throws PluginException if the plugin is not in a valid state
+     */
+    public PropertyDrivenPlugin(@Nonnull final Class<? extends Plugin<T>> claz) throws IOException, PluginException {
+        this(claz.getResourceAsStream(DEFAULT_RESOURCE));
+    }
+    
+    /**
+     * Constructor.
+     *
+     * @param inputStream property stream
+     * 
+     * @throws IOException if unable to read file
+     * @throws PluginException if the plugin is not in a valid state
+     */
+    public PropertyDrivenPlugin(@Nonnull final InputStream inputStream)
+            throws IOException, PluginException {
+        pluginProperties = new Properties();
+        pluginProperties.load(inputStream);
+        load();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param properties property set
+     * 
+     * @throws PluginException if the plugin is not in a valid state
+     */
+    public PropertyDrivenPlugin(@Nonnull final Properties properties) throws PluginException {
+        pluginProperties = Constraint.isNotNull(properties, "Properties cannot be null");
+        load();
+    }
+    
+    /**
+     * Load plugin information from properties.
+     * 
+     * @throws PluginException on errors
+     */
+    protected void load() throws PluginException {
+        
+        pluginId = StringSupport.trimOrNull(pluginProperties.getProperty(PLUGIN_ID_PROPERTY));
+        
+        String version = getClass().getPackage().getImplementationVersion();
+        if (version == null) {
+            version = StringSupport.trimOrNull(pluginProperties.getProperty(PLUGIN_VERSION_PROPERTY));
+            if (version == null) {
+                throw new PluginException("No plugin version property or package attribute available for " + pluginId);
+            }
+        } else {
+            log.debug("Ignoring plugin '{}' version property in favor of package manifest", pluginId);
+        }
+        
+        try {
+            pluginVersion = new InstallableComponentVersion(version);
+        } catch (final NumberFormatException e) {
+            throw new PluginException(e);
+        }
+
+        final List<URL> urls = new ArrayList<>();
+        
+        for (Integer urlnum = 1; ; ++urlnum) {
+            
+            final String urlstr = pluginProperties.getProperty(PLUGIN_URL_PROPERTY + urlnum.toString());
+            if (urlstr == null) {
+                break;
+            }
+            
+            try {
+                urls.add(new URL(urlstr));
+            } catch (final MalformedURLException e) {
+                log.error("Unable to convert property value '{}' to URL", urlstr, e);
+            }
+        }
+        
+        urls.addAll(getDefaultUpdateURLs());
+        
+        updateURLs = CollectionSupport.copyToList(urls);
+        
+        requiredModules = CollectionSupport.copyToSet(StringSupport.normalizeStringCollection(
+                StringSupport.stringToList(pluginProperties.getProperty(PLUGIN_REQ_MODULES_PROPERTY, ""), ",")));
+
+        log.debug("Plugin {} loaded", getPluginId());
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NotEmpty public String getPluginId() {
+        if (pluginId != null) {
+            return pluginId;
+        }
+        return super.getPluginId();
+    }
+    
+    /** {@inheritDoc} */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<URL> getUpdateURLs() {
+        return updateURLs;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public Set<String> getRequiredModules() {
+        return requiredModules;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public String getLicenseFileLocation() {
+        return pluginProperties.getProperty(PLUGIN_LICENSE_PROPERTY);
+    }
+
+    /** {@inheritDoc} */
+    @NonNegative public int getMajorVersion() {
+        assert pluginVersion != null;
+        return pluginVersion.getMajor();
+    }
+
+    /** {@inheritDoc} */
+    @NonNegative public int getMinorVersion() {
+        assert pluginVersion != null;
+        return pluginVersion.getMinor();
+    }
+
+    /** {@inheritDoc} */
+    @NonNegative public int getPatchVersion() {
+        assert pluginVersion != null;
+        return pluginVersion.getPatch();
+    }
+    
+    /**
+     * Provides default update locations to use.
+     * 
+     * @return default update locations
+     * @throws PluginException if a derived class throws it (see derived classes)
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive protected List<URL> getDefaultUpdateURLs() throws PluginException {
+        return CollectionSupport.emptyList();
+    }
+    
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list