2 * Copyright (c) 2014, 2017 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.config.spi;
11 import org.opendaylight.controller.config.api.DependencyResolver;
12 import org.opendaylight.controller.config.api.ModuleIdentifier;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
17 * Base implementation of Module. This implementation contains base logic for
18 * Module reconfiguration with associated fields.
21 * Type of module implementation. Enables easier implementation for
22 * the <code>isSame()</code> method
24 public abstract class AbstractModule<M extends AbstractModule<M>>
25 implements org.opendaylight.controller.config.spi.Module {
27 private static final Logger LOG = LoggerFactory.getLogger(AbstractModule.class);
29 protected final DependencyResolver dependencyResolver;
30 protected final ModuleIdentifier identifier;
32 private AutoCloseable oldInstance;
34 private AutoCloseable instance;
35 private boolean canReuseInstance = true;
38 * Called when module is configured.
41 * id of current instance.
42 * @param dependencyResolver
43 * resolver used in dependency injection and validation.
45 public AbstractModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver) {
46 this(identifier, dependencyResolver, null, null);
50 * Called when module is reconfigured.
53 * id of current instance.
54 * @param dependencyResolver
55 * resolver used in dependency injection and validation.
57 * old instance of module that is being reconfigred(replaced) by
58 * current instance. The old instance can be examined for reuse.
60 * old instance wrapped by the old module. This is the resource that
61 * is actually being reused if possible or closed otherwise.
63 public AbstractModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver,
64 final M oldModule, final AutoCloseable oldInstance) {
65 this.identifier = identifier;
66 this.dependencyResolver = dependencyResolver;
67 this.oldModule = oldModule;
68 this.oldInstance = oldInstance;
72 public ModuleIdentifier getIdentifier() {
76 public final void setCanReuseInstance(final boolean canReuseInstance) {
77 this.canReuseInstance = canReuseInstance;
81 * General algorithm for spawning/closing and reusing wrapped instances.
83 * @return current instance of wrapped resource either by reusing the old one
84 * (if present) or constructing a brand new.
87 @SuppressWarnings("IllegalCatch")
88 public final AutoCloseable getInstance() {
89 if (instance == null) {
90 if (oldInstance != null && canReuseInstance && canReuseInstance(oldModule)) {
91 resolveDependencies();
92 instance = reuseInstance(oldInstance);
94 if (oldInstance != null) {
97 } catch (final Exception exception) {
98 LOG.error("An error occurred while closing old instance {} for module {}", oldInstance,
99 getIdentifier(), exception);
102 resolveDependencies();
103 instance = createInstance();
104 if (instance == null) {
105 throw new IllegalStateException(
106 "Error in createInstance - null is not allowed as return value. Module: "
111 // Prevent serial memory leak: clear these references as we will not use them
123 * @return Brand new instance of wrapped class in case no previous instance is
124 * present or reconfiguration is impossible.
126 protected abstract AutoCloseable createInstance();
129 public final boolean canReuse(final Module oldModule) {
130 // Just cast into a specific instance
131 // TODO unify this method with canReuseInstance (required Module interface to be
132 // generic which requires quite a lot of changes)
133 return canReuseInstance && getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false;
137 * Users are welcome to override this method to provide custom logic for
138 * advanced reusability detection.
141 * old instance of a Module
142 * @return true if the old instance is reusable false if a new one should be
145 protected abstract boolean canReuseInstance(M oldModule);
148 * By default the oldInstance is returned since this method is by default called
149 * only if the oldModule had the same configuration and dependencies configured.
150 * Users are welcome to override this method to provide custom logic for
151 * advanced reusability.
154 * old instance of a class wrapped by the module
155 * @return reused instance
157 protected AutoCloseable reuseInstance(final AutoCloseable oldInstance) {
158 // implement if instance reuse should be supported. Override canReuseInstance to
159 // change the criteria.
164 * Inject all the dependencies using dependency resolver instance.
166 protected abstract void resolveDependencies();