@Inject convenience helper (org.opendaylight.infrautils.inject)
authorMichael Vorburger <vorburger@redhat.com>
Tue, 23 Aug 2016 13:59:43 +0000 (15:59 +0200)
committerMichael Vorburger <vorburger@redhat.com>
Mon, 29 Aug 2016 09:14:48 +0000 (11:14 +0200)
Introduces the Lifecycle interrface with the LifecycleSupport and
SingletonWithLifecycle convenience base classes, with a
ModuleSetupRuntimeException, to standardize the use of @Inject (in
@Singleton) in the ODL code base for projects using the
blueprint-maven-plugin to generate wiring XML from these Java
annotations instead of hand writing it.

Change-Id: I88313940370e6cbef30bd471b2cda8238be5beb8
Signed-off-by: Michael Vorburger <vorburger@redhat.com>
inject/pom.xml [new file with mode: 0644]
inject/src/main/java/org/opendaylight/infrautils/inject/AbstractLifecycle.java [new file with mode: 0644]
inject/src/main/java/org/opendaylight/infrautils/inject/Lifecycle.java [new file with mode: 0644]
inject/src/main/java/org/opendaylight/infrautils/inject/ModuleSetupRuntimeException.java [new file with mode: 0644]
inject/src/main/java/org/opendaylight/infrautils/inject/SingletonWithLifecycle.java [new file with mode: 0644]
inject/src/main/java/org/opendaylight/infrautils/inject/package-info.java [new file with mode: 0644]
pom.xml [new file with mode: 0755]

diff --git a/inject/pom.xml b/inject/pom.xml
new file mode 100644 (file)
index 0000000..20011b0
--- /dev/null
@@ -0,0 +1,50 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent</artifactId>
+    <version>1.8.0-SNAPSHOT</version>
+    <relativePath />
+  </parent>
+
+  <groupId>org.opendaylight.infrautils</groupId>
+  <artifactId>inject</artifactId>
+  <version>1.1.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <propertyExpansion>checkstyle.violationSeverity=error</propertyExpansion>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.opendaylight.infrautils.inject
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <!-- TODO Remove this when https://git.opendaylight.org/gerrit/#/c/44502/ is merged -->
+    <dependency>
+        <groupId>javax.inject</groupId>
+        <artifactId>javax.inject</artifactId>
+        <version>1</version>
+      </dependency>
+  </dependencies>
+
+</project>
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/AbstractLifecycle.java b/inject/src/main/java/org/opendaylight/infrautils/inject/AbstractLifecycle.java
new file mode 100644 (file)
index 0000000..7ac3d98
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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.infrautils.inject;
+
+import java.util.concurrent.atomic.AtomicReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Support class for {@link Lifecycle}. Provides a convenient base
+ * implementation including correct thread safety, exception handling and check
+ * for accidental unnecessary re-start &amp; stop. Subclasses must implement
+ * {@link #start()} &amp; {@link #stop()}.
+ *
+ * @author Michael Vorburger (with guidance re. AtomicReference from Tom Pantelis)
+ */
+public abstract class AbstractLifecycle implements Lifecycle {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractLifecycle.class);
+
+    private enum State {
+        STARTED, STOPPED
+    }
+
+    private AtomicReference<State> state = new AtomicReference<>(State.STOPPED);
+
+    protected abstract void start() throws Exception;
+
+    protected abstract void stop() throws Exception;
+
+    /**
+     * Please implement {@link #start()} instead of overriding this (here intentionally final) method.
+     */
+    @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public final void init() throws ModuleSetupRuntimeException {
+        if (state.compareAndSet(State.STOPPED, State.STARTED)) {
+            try {
+                start();
+            } catch (Exception e) {
+                throw new ModuleSetupRuntimeException(e);
+            }
+        } else {
+            LOG.warn("Lifecycled object already started; ignoring start()");
+        }
+    }
+
+    /**
+     * Please implement {@link #stop()} instead of overriding this (here intentionally final) method.
+     */
+    @Override
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    public final void destroy() throws ModuleSetupRuntimeException {
+        if (state.compareAndSet(State.STARTED, State.STOPPED)) {
+            try {
+                stop();
+            } catch (Exception e) {
+                throw new ModuleSetupRuntimeException(e);
+            }
+        } else {
+            LOG.warn("Lifecycled object already stopped; ignoring stop()");
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        return state.get() == State.STARTED;
+    }
+
+}
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/Lifecycle.java b/inject/src/main/java/org/opendaylight/infrautils/inject/Lifecycle.java
new file mode 100644 (file)
index 0000000..b35f505
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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.infrautils.inject;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+/**
+ * Something which can be {@link #init()}-ialized and {@link #destroy()}-d.
+ *
+ * <p>Annotated so that Dependency Injection Frameworks (whichever) automatically call these methods during wiring.
+ *
+ * @see AbstractLifecycle
+ * @see SingletonWithLifecycle
+ *
+ * @author Michael Vorburger
+ */
+public interface Lifecycle {
+
+    @PostConstruct
+    void init() throws ModuleSetupRuntimeException;
+
+    @PreDestroy
+    void destroy() throws ModuleSetupRuntimeException;
+
+    boolean isRunning();
+
+}
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/ModuleSetupRuntimeException.java b/inject/src/main/java/org/opendaylight/infrautils/inject/ModuleSetupRuntimeException.java
new file mode 100644 (file)
index 0000000..4158a7a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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.infrautils.inject;
+
+/**
+ * Exception to throw from a static Dependency Inject Framework's "Wiring" class.
+ *
+ * <p>Also used in {@link Lifecycle#init()} and {@link Lifecycle#destroy()}, because
+ * those methods are typically called from DI's Wiring classes (typically implicitly
+ * by a DI framework, and not hand-written Wiring code).
+ *
+ * <p>For example, throw this from methods in a class implementing Guice's Module
+ * interface, or from methods annotated with Dagger's @Provides in a @Module
+ * class, which <i>"may only throw unchecked exceptions"</i>.  In particular, when you
+ * have to catch checked exceptions while creating objects, wrap them into this
+ * unchecked Exception.
+ *
+ * <p>When you use this Exception in a Dagger/Guice/etc. Module, you should
+ * probably write a simple test for the Module, just to verify it (alone) works
+ * at run-time (if there is a checked exception to catch, it probably
+ * initializes something that is non-trivial and could fail; so best to have a
+ * non-regression test for that Module).
+ *
+ * @author Michael Vorburger
+ */
+public class ModuleSetupRuntimeException extends RuntimeException {
+
+    private static final long serialVersionUID = -1795982967617796415L;
+
+    public ModuleSetupRuntimeException(Exception cause) {
+        super(cause);
+    }
+}
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/SingletonWithLifecycle.java b/inject/src/main/java/org/opendaylight/infrautils/inject/SingletonWithLifecycle.java
new file mode 100644 (file)
index 0000000..e685578
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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.infrautils.inject;
+
+import javax.inject.Scope;
+import javax.inject.Singleton;
+
+/**
+ * A Singleton AbstractLifecycle.
+ *
+ * <p>In ODL, most wired objects ("beans") are {@link Singleton}, and it therefore
+ * makes sense to have this class and let both exposed Services and wired
+ * objects internal to bundles extend this.
+ *
+ * <p>Future use of DI in ODL may introduce additional non-{@link Singleton} {@link Scope}s.
+ *
+ * @author Michael Vorburger
+ */
+@Singleton
+public abstract class SingletonWithLifecycle extends AbstractLifecycle {
+}
diff --git a/inject/src/main/java/org/opendaylight/infrautils/inject/package-info.java b/inject/src/main/java/org/opendaylight/infrautils/inject/package-info.java
new file mode 100644 (file)
index 0000000..de89cb9
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc. 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
+ */
+
+/**
+ * The interfaces and classes in this package are "for convenience". Technically
+ * you do NOT have to implement or extend any of these to work with Dependency
+ * Injection - and could instead just apply these annotations to a class
+ * yourself etc. But defining this once and encouraging projects to use this
+ * establishes uniformity, which also helps other reading your code to recognize
+ * a class as being of the respective kind.
+ */
+package org.opendaylight.infrautils.inject;
diff --git a/pom.xml b/pom.xml
new file mode 100755 (executable)
index 0000000..688abdc
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=2 tabstop=2: -->
+<!--
+ Copyright © 2016 Red Hat, Inc. 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.odlparent</groupId>
+    <artifactId>odlparent</artifactId>
+    <version>1.8.0-SNAPSHOT</version>
+    <relativePath />
+  </parent>
+
+  <groupId>org.opendaylight.infrautils</groupId>
+  <artifactId>inject-aggregator</artifactId>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>inject</module>
+  </modules>
+
+  <!--
+      Maven Site Configuration
+
+      The following configuration is necessary for maven-site-plugin to
+      correctly identify the correct deployment path for OpenDaylight Maven
+      sites.
+  -->
+  <url>${odl.site.url}/${project.groupId}/${stream}/${project.artifactId}/</url>
+
+  <distributionManagement>
+    <site>
+      <id>opendaylight-site</id>
+      <url>${nexus.site.url}/${project.artifactId}/</url>
+    </site>
+  </distributionManagement>
+</project>