2 * Copyright (c) 2014 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 Module reconfiguration with associated fields.
18 * @param <M> Type of module implementation. Enables easier implementation for the <code>isSame()</code> method
20 public abstract class AbstractModule<M extends AbstractModule<M>> implements org.opendaylight.controller.config.spi.Module {
22 private static final Logger LOG = LoggerFactory.getLogger(AbstractModule.class);
24 protected final DependencyResolver dependencyResolver;
25 protected final ModuleIdentifier identifier;
27 private AutoCloseable oldInstance;
29 private AutoCloseable instance;
30 private boolean canReuseInstance = true;
33 * Called when module is configured.
35 * @param identifier id of current instance.
36 * @param dependencyResolver resolver used in dependency injection and validation.
38 public AbstractModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver) {
39 this(identifier, dependencyResolver, null, null);
43 * Called when module is reconfigured.
45 * @param identifier id of current instance.
46 * @param dependencyResolver resolver used in dependency injection and validation.
47 * @param oldModule old instance of module that is being reconfigred(replaced) by current instance. The old instance can be examined for reuse.
48 * @param oldInstance old instance wrapped by the old module. This is the resource that is actually being reused if possible or closed otherwise.
50 public AbstractModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver, final M oldModule, final AutoCloseable oldInstance) {
51 this.identifier = identifier;
52 this.dependencyResolver = dependencyResolver;
53 this.oldModule = oldModule;
54 this.oldInstance = oldInstance;
58 public ModuleIdentifier getIdentifier() {
62 public final void setCanReuseInstance(final boolean canReuseInstance) {
63 this.canReuseInstance = canReuseInstance;
68 * General algorithm for spawning/closing and reusing wrapped instances.
70 * @return current instance of wrapped resource either by reusing the old one (if present) or constructing a brand new.
73 public final AutoCloseable getInstance() {
74 if (instance == null) {
75 if (oldInstance != null && canReuseInstance && canReuseInstance(oldModule)) {
76 resolveDependencies();
77 instance = reuseInstance(oldInstance);
79 if (oldInstance != null) {
82 } catch (final Exception e) {
83 LOG.error("An error occurred while closing old instance {} for module {}", oldInstance, getIdentifier(), e);
86 resolveDependencies();
87 instance = createInstance();
88 if (instance == null) {
89 throw new IllegalStateException("Error in createInstance - null is not allowed as return value. Module: " + getIdentifier());
93 // Prevent serial memory leak: clear these references as we will not use them again.
102 * @return Brand new instance of wrapped class in case no previous instance is present or reconfiguration is impossible.
104 protected abstract AutoCloseable createInstance();
107 public final boolean canReuse(final Module oldModule) {
108 // Just cast into a specific instance
109 // TODO unify this method with canReuseInstance (required Module interface to be generic which requires quite a lot of changes)
110 return canReuseInstance && getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false;
115 * Users are welcome to override this method to provide custom logic for advanced reusability detection.
117 * @param oldModule old instance of a Module
118 * @return true if the old instance is reusable false if a new one should be spawned
120 protected abstract boolean canReuseInstance(final M oldModule);
123 * By default the oldInstance is returned since this method is by default called only if the oldModule had the same configuration and dependencies configured.
124 * Users are welcome to override this method to provide custom logic for advanced reusability.
126 * @param oldInstance old instance of a class wrapped by the module
127 * @return reused instance
129 protected AutoCloseable reuseInstance(final AutoCloseable oldInstance) {
130 // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
135 * Inject all the dependencies using dependency resolver instance.
137 protected abstract void resolveDependencies();