Convert aaa-password-service to OSGi DS 04/93104/8
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 16 Oct 2020 19:37:49 +0000 (21:37 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 4 Nov 2020 16:43:14 +0000 (17:43 +0100)
This patch serves as a blueprint of what a replacement for blueprint's
clustered-app-config needs to look like. Since we are replicating
the functionality of config DS -> component, this ends up being more
complicated than we'd want it.

Providing the infrastructure replacement for odl:clustered-config
is part of MDSAL-598. This patch provides one possibility how that would
be realized.

JIRA: AAA-203
JIRA: MDSAL-598
Change-Id: I760a6514ed185fc60639f7d7195159d19bf60a76
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
aaa-password-service/impl/pom.xml
aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordHashService.java [new file with mode: 0644]
aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfig.java [new file with mode: 0644]
aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfigBootstrap.java [new file with mode: 0644]
aaa-password-service/impl/src/main/resources/OSGI-INF/blueprint/password-service-blueprint.xml [deleted file]
aaa-shiro/impl/src/main/resources/OSGI-INF/blueprint/impl-blueprint.xml

index cd65e90f6c7cfb1999695aa371f7624186752a08..1f2b0cac746f8bd58efe7fcdbf885db9b1430d81 100644 (file)
@@ -31,6 +31,16 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <groupId>org.apache.shiro</groupId>
       <artifactId>shiro-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>osgi.cmpn</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>mdsal-binding-api</artifactId>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
   </dependencies>
 
   <build>
@@ -51,6 +61,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
             <Export-Package>
               org.opendaylight.aaa.impl.password.service.DefaultPasswordHashService
             </Export-Package>
+            <_dsannotations-options>norequirements</_dsannotations-options>
           </instructions>
         </configuration>
       </plugin>
diff --git a/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordHashService.java b/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordHashService.java
new file mode 100644 (file)
index 0000000..238b4f6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.impl.password.service;
+
+import org.opendaylight.aaa.api.password.service.PasswordHash;
+import org.opendaylight.aaa.api.password.service.PasswordHashService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+
+@Component(immediate = true, service = PasswordHashService.class, property = "type=default")
+public final class OSGiPasswordHashService implements PasswordHashService {
+    private volatile DefaultPasswordHashService delegate = null;
+
+    @Override
+    public PasswordHash getPasswordHash(final String password) {
+        return delegate.getPasswordHash(password);
+    }
+
+    @Override
+    public PasswordHash getPasswordHash(final String password, final String salt) {
+        return delegate.getPasswordHash(password, salt);
+    }
+
+    @Override
+    public boolean passwordsMatch(final String plaintext, final String stored, final String salt) {
+        return delegate.passwordsMatch(plaintext, stored, salt);
+    }
+
+    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MANDATORY)
+    void bindConfig(final PasswordServiceConfig config) {
+        updatedConfig(config);
+    }
+
+    void unbindConfig(final PasswordServiceConfig config) {
+        delegate = null;
+    }
+
+    void updatedConfig(final PasswordServiceConfig config) {
+        delegate = new DefaultPasswordHashService(config);
+    }
+}
diff --git a/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfig.java b/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfig.java
new file mode 100644 (file)
index 0000000..183b322
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.impl.password.service;
+
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ForwardingObject;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import org.gaul.modernizer_maven_annotations.SuppressModernizer;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+
+@Beta
+@Component(factory = OSGiPasswordServiceConfig.FACTORY_NAME)
+public final class OSGiPasswordServiceConfig extends ForwardingObject implements PasswordServiceConfig {
+    // OSGi DS Component Factory name
+    static final String FACTORY_NAME = "org.opendaylight.aaa.impl.password.service.OSGiPasswordServiceConfig";
+
+    // Keys to for activation properties
+    @VisibleForTesting
+    static final String DELEGATE = ".delegate";
+
+    private PasswordServiceConfig delegate;
+
+    @Override
+    public Map<Class<? extends Augmentation<PasswordServiceConfig>>, Augmentation<PasswordServiceConfig>>
+            augmentations() {
+        return delegate().augmentations();
+    }
+
+    @Override
+    public String getAlgorithm() {
+        return delegate().getAlgorithm();
+    }
+
+    @Override
+    public Integer getIterations() {
+        return delegate().getIterations();
+    }
+
+    @Override
+    public String getPrivateSalt() {
+        return delegate().getPrivateSalt();
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate().hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return delegate().equals(obj);
+    }
+
+    @Override
+    protected PasswordServiceConfig delegate() {
+        return verifyNotNull(delegate);
+    }
+
+    @Activate
+    void activate(final Map<String, ?> properties) {
+        delegate = (PasswordServiceConfig) verifyNotNull(properties.get(DELEGATE));
+    }
+
+    @Deactivate
+    void deactivate() {
+        delegate = null;
+    }
+
+    @SuppressModernizer
+    static Dictionary<String, ?> props(final PasswordServiceConfig delegate) {
+        final Dictionary<String, Object> ret = new Hashtable<>(2);
+        ret.put(DELEGATE, requireNonNull(delegate));
+        return ret;
+    }
+}
diff --git a/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfigBootstrap.java b/aaa-password-service/impl/src/main/java/org/opendaylight/aaa/impl/password/service/OSGiPasswordServiceConfigBootstrap.java
new file mode 100644 (file)
index 0000000..8cb741b
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.aaa.impl.password.service;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import org.checkerframework.checker.lock.qual.Holding;
+import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfigBuilder;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+@Component(immediate = true)
+public final class OSGiPasswordServiceConfigBootstrap
+        implements ClusteredDataTreeChangeListener<PasswordServiceConfig> {
+    private static final Logger LOG = LoggerFactory.getLogger(OSGiPasswordServiceConfigBootstrap.class);
+
+    @Reference
+    DataBroker dataBroker = null;
+
+    @Reference(target = "(component.factory=" + OSGiPasswordServiceConfig.FACTORY_NAME + ")")
+    ComponentFactory configFactory = null;
+
+    private ListenerRegistration<?> registration;
+    private ComponentInstance instance;
+
+    @Activate
+    synchronized void activate() {
+        registration = dataBroker.registerDataTreeChangeListener(
+            DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.create(PasswordServiceConfig.class)), this);
+        LOG.info("Listening for password service configuration");
+    }
+
+    @Deactivate
+    synchronized void deactivate() {
+        registration.close();
+        registration = null;
+        if (instance != null) {
+            instance.dispose();
+            instance = null;
+        }
+        LOG.info("No longer listening for password service configuration");
+    }
+
+    @Override
+    public synchronized void onInitialData() {
+        updateInstance(null);
+    }
+
+    @Override
+    public synchronized void onDataTreeChanged(final Collection<DataTreeModification<PasswordServiceConfig>> changes) {
+        // FIXME: at this point we need to populate default values -- from the XML file
+        updateInstance(Iterables.getLast(changes).getRootNode().getDataAfter());
+    }
+
+    @Holding("this")
+    private void updateInstance(final PasswordServiceConfig config) {
+        if (registration != null) {
+            final ComponentInstance newInstance = configFactory.newInstance(
+                OSGiPasswordServiceConfig.props(config != null ? config : new PasswordServiceConfigBuilder().build()));
+            if (instance != null) {
+                instance.dispose();
+            }
+            instance = newInstance;
+        }
+    }
+}
diff --git a/aaa-password-service/impl/src/main/resources/OSGI-INF/blueprint/password-service-blueprint.xml b/aaa-password-service/impl/src/main/resources/OSGI-INF/blueprint/password-service-blueprint.xml
deleted file mode 100644 (file)
index 019493c..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
-Copyright © 2018 Inocybe Technologies and others. All rights reserved.
-
-This program and the accompanying materials are made available under the
-terms of the Eclipse Public License v1.0 which accompanies this distribution,
-and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
-  xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
-  odl:use-default-for-reference-types="true">
-
-    <odl:clustered-app-config
-            binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.password.service.config.rev170619.PasswordServiceConfig"
-            id="passwordServiceConfig" default-config-file-name="aaa-password-service-config.xml" />
-
-    <bean id="passwordService" class="org.opendaylight.aaa.impl.password.service.DefaultPasswordHashService">
-        <argument ref="passwordServiceConfig" />
-    </bean>
-    <service ref="passwordService" interface="org.opendaylight.aaa.api.password.service.PasswordHashService"
-        odl:type="default"/>
-
-</blueprint>
index ab045e202abe98dbe6249f8b10c81e088d8df997..28807c6b1e808f4ca67a86ce60d0c00975e84230 100644 (file)
@@ -21,8 +21,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.DatastoreConfig" />
 
   <reference id="authService" interface="org.opendaylight.aaa.api.AuthenticationService"/>
-  <reference id="passwordService" interface="org.opendaylight.aaa.api.password.service.PasswordHashService"
-      odl:type="default"/>
+  <reference id="passwordService" interface="org.opendaylight.aaa.api.password.service.PasswordHashService"/>
 
   <bean id="idmStore" class="org.opendaylight.aaa.datastore.h2.H2Store">
     <argument value="${dbUsername}" />