--- /dev/null
+################################################################################
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF 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.
+#
+################################################################################
+
+#
+# Java platform package export properties.
+#
+
+# Standard package set. Note that:
+# - javax.transaction* is exported with a mandatory attribute
+jre-1.6= \
+ javax.accessibility, \
+ javax.activation;version="1.1", \
+ javax.activity, \
+ javax.annotation;version="1.1", \
+ javax.annotation.processing;version="1.1", \
+ javax.crypto, \
+ javax.crypto.interfaces, \
+ javax.crypto.spec, \
+ javax.imageio, \
+ javax.imageio.event, \
+ javax.imageio.metadata, \
+ javax.imageio.plugins.bmp, \
+ javax.imageio.plugins.jpeg, \
+ javax.imageio.spi, \
+ javax.imageio.stream, \
+ javax.jws, \
+ javax.jws.soap, \
+ javax.lang.model, \
+ javax.lang.model.element, \
+ javax.lang.model.type, \
+ javax.lang.model.util, \
+ javax.management, \
+ javax.management.loading, \
+ javax.management.modelmbean, \
+ javax.management.monitor, \
+ javax.management.openmbean, \
+ javax.management.relation, \
+ javax.management.remote, \
+ javax.management.remote.rmi, \
+ javax.management.timer, \
+ javax.naming, \
+ javax.naming.directory, \
+ javax.naming.event, \
+ javax.naming.ldap, \
+ javax.naming.spi, \
+ javax.net, \
+ javax.net.ssl, \
+ javax.print, \
+ javax.print.attribute, \
+ javax.print.attribute.standard, \
+ javax.print.event, \
+ javax.rmi, \
+ javax.rmi.CORBA, \
+ javax.rmi.ssl, \
+ javax.script, \
+ javax.security.auth, \
+ javax.security.auth.callback, \
+ javax.security.auth.kerberos, \
+ javax.security.auth.login, \
+ javax.security.auth.spi, \
+ javax.security.auth.x500, \
+ javax.security.cert, \
+ javax.security.sasl, \
+ javax.sound.midi, \
+ javax.sound.midi.spi, \
+ javax.sound.sampled, \
+ javax.sound.sampled.spi, \
+ javax.sql, \
+ javax.sql.rowset, \
+ javax.sql.rowset.serial, \
+ javax.sql.rowset.spi, \
+ javax.swing, \
+ javax.swing.border, \
+ javax.swing.colorchooser, \
+ javax.swing.event, \
+ javax.swing.filechooser, \
+ javax.swing.plaf, \
+ javax.swing.plaf.basic, \
+ javax.swing.plaf.metal, \
+ javax.swing.plaf.multi, \
+ javax.swing.plaf.synth, \
+ javax.swing.table, \
+ javax.swing.text, \
+ javax.swing.text.html, \
+ javax.swing.text.html.parser, \
+ javax.swing.text.rtf, \
+ javax.swing.tree, \
+ javax.swing.undo, \
+ javax.tools, \
+ javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \
+ javax.xml, \
+ javax.xml.bind;version="2.2.1", \
+ javax.xml.bind.annotation;version="2.2.1", \
+ javax.xml.bind.annotation.adapters;version="2.2.1", \
+ javax.xml.bind.attachment;version="2.2.1", \
+ javax.xml.bind.helpers;version="2.2.1", \
+ javax.xml.bind.util;version="2.2.1", \
+ javax.xml.crypto, \
+ javax.xml.crypto.dom, \
+ javax.xml.crypto.dsig, \
+ javax.xml.crypto.dsig.dom, \
+ javax.xml.crypto.dsig.keyinfo, \
+ javax.xml.crypto.dsig.spec, \
+ javax.xml.datatype, \
+ javax.xml.namespace, \
+ javax.xml.parsers, \
+ javax.xml.soap;version="1.3", \
+ javax.xml.stream;version="1.2", \
+ javax.xml.stream.events;version="1.2", \
+ javax.xml.stream.util;version="1.2", \
+ javax.xml.transform, \
+ javax.xml.transform.dom, \
+ javax.xml.transform.sax, \
+ javax.xml.transform.stax, \
+ javax.xml.transform.stream, \
+ javax.xml.validation, \
+ javax.xml.ws;version="2.2", \
+ javax.xml.ws.handler;version="2.2", \
+ javax.xml.ws.handler.soap;version="2.2", \
+ javax.xml.ws.http;version="2.2", \
+ javax.xml.ws.soap;version="2.2", \
+ javax.xml.ws.spi;version="2.2", \
+ javax.xml.ws.wsaddressing;version="2.2", \
+ javax.xml.ws.spi.http;version="2.2", \
+ javax.xml.xpath, \
+ org.ietf.jgss, \
+ org.omg.CORBA, \
+ org.omg.CORBA_2_3, \
+ org.omg.CORBA_2_3.portable, \
+ org.omg.CORBA.DynAnyPackage, \
+ org.omg.CORBA.ORBPackage, \
+ org.omg.CORBA.portable, \
+ org.omg.CORBA.TypeCodePackage, \
+ org.omg.CosNaming, \
+ org.omg.CosNaming.NamingContextExtPackage, \
+ org.omg.CosNaming.NamingContextPackage, \
+ org.omg.Dynamic, \
+ org.omg.DynamicAny, \
+ org.omg.DynamicAny.DynAnyFactoryPackage, \
+ org.omg.DynamicAny.DynAnyPackage, \
+ org.omg.IOP, \
+ org.omg.IOP.CodecFactoryPackage, \
+ org.omg.IOP.CodecPackage, \
+ org.omg.Messaging, \
+ org.omg.PortableInterceptor, \
+ org.omg.PortableInterceptor.ORBInitInfoPackage, \
+ org.omg.PortableServer, \
+ org.omg.PortableServer.CurrentPackage, \
+ org.omg.PortableServer.POAManagerPackage, \
+ org.omg.PortableServer.POAPackage, \
+ org.omg.PortableServer.portable, \
+ org.omg.PortableServer.ServantLocatorPackage, \
+ org.omg.SendingContext, \
+ org.omg.stub.java.rmi, \
+ org.omg.stub.javax.management.remote.rmi, \
+ org.w3c.dom, \
+ org.w3c.dom.bootstrap, \
+ org.w3c.dom.css, \
+ org.w3c.dom.events, \
+ org.w3c.dom.html, \
+ org.w3c.dom.ls, \
+ org.w3c.dom.ranges, \
+ org.w3c.dom.stylesheets, \
+ org.w3c.dom.traversal, \
+ org.w3c.dom.views, \
+ org.w3c.dom.xpath, \
+ org.xml.sax, \
+ org.xml.sax.ext, \
+ org.xml.sax.helpers, \
+ sun.misc
+
+# Standard package set. Note that:
+# - javax.transaction* is exported with a mandatory attribute
+jre-1.7= \
+ javax.accessibility, \
+ javax.activation;version="1.1", \
+ javax.activity, \
+ javax.annotation;version="1.2", \
+ javax.annotation.processing;version="1.2", \
+ javax.crypto, \
+ javax.crypto.interfaces, \
+ javax.crypto.spec, \
+ javax.imageio, \
+ javax.imageio.event, \
+ javax.imageio.metadata, \
+ javax.imageio.plugins.bmp, \
+ javax.imageio.plugins.jpeg, \
+ javax.imageio.spi, \
+ javax.imageio.stream, \
+ javax.jws, \
+ javax.jws.soap, \
+ javax.lang.model, \
+ javax.lang.model.element, \
+ javax.lang.model.type, \
+ javax.lang.model.util, \
+ javax.management, \
+ javax.management.loading, \
+ javax.management.modelmbean, \
+ javax.management.monitor, \
+ javax.management.openmbean, \
+ javax.management.relation, \
+ javax.management.remote, \
+ javax.management.remote.rmi, \
+ javax.management.timer, \
+ javax.naming, \
+ javax.naming.directory, \
+ javax.naming.event, \
+ javax.naming.ldap, \
+ javax.naming.spi, \
+ javax.net, \
+ javax.net.ssl, \
+ javax.print, \
+ javax.print.attribute, \
+ javax.print.attribute.standard, \
+ javax.print.event, \
+ javax.rmi, \
+ javax.rmi.CORBA, \
+ javax.rmi.ssl, \
+ javax.script, \
+ javax.security.auth, \
+ javax.security.auth.callback, \
+ javax.security.auth.kerberos, \
+ javax.security.auth.login, \
+ javax.security.auth.spi, \
+ javax.security.auth.x500, \
+ javax.security.cert, \
+ javax.security.sasl, \
+ javax.sound.midi, \
+ javax.sound.midi.spi, \
+ javax.sound.sampled, \
+ javax.sound.sampled.spi, \
+ javax.sql, \
+ javax.sql.rowset, \
+ javax.sql.rowset.serial, \
+ javax.sql.rowset.spi, \
+ javax.swing, \
+ javax.swing.border, \
+ javax.swing.colorchooser, \
+ javax.swing.event, \
+ javax.swing.filechooser, \
+ javax.swing.plaf, \
+ javax.swing.plaf.basic, \
+ javax.swing.plaf.metal, \
+ javax.swing.plaf.multi, \
+ javax.swing.plaf.synth, \
+ javax.swing.table, \
+ javax.swing.text, \
+ javax.swing.text.html, \
+ javax.swing.text.html.parser, \
+ javax.swing.text.rtf, \
+ javax.swing.tree, \
+ javax.swing.undo, \
+ javax.tools, \
+ javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \
+ javax.xml, \
+ javax.xml.bind;version="2.2.1", \
+ javax.xml.bind.annotation;version="2.2.1", \
+ javax.xml.bind.annotation.adapters;version="2.2.1", \
+ javax.xml.bind.attachment;version="2.2.1", \
+ javax.xml.bind.helpers;version="2.2.1", \
+ javax.xml.bind.util;version="2.2.1", \
+ javax.xml.crypto, \
+ javax.xml.crypto.dom, \
+ javax.xml.crypto.dsig, \
+ javax.xml.crypto.dsig.dom, \
+ javax.xml.crypto.dsig.keyinfo, \
+ javax.xml.crypto.dsig.spec, \
+ javax.xml.datatype, \
+ javax.xml.namespace, \
+ javax.xml.parsers, \
+ javax.xml.soap;version="1.3", \
+ javax.xml.stream;version="1.2", \
+ javax.xml.stream.events;version="1.2", \
+ javax.xml.stream.util;version="1.2", \
+ javax.xml.transform, \
+ javax.xml.transform.dom, \
+ javax.xml.transform.sax, \
+ javax.xml.transform.stax, \
+ javax.xml.transform.stream, \
+ javax.xml.validation, \
+ javax.xml.ws;version="2.2", \
+ javax.xml.ws.handler;version="2.2", \
+ javax.xml.ws.handler.soap;version="2.2", \
+ javax.xml.ws.http;version="2.2", \
+ javax.xml.ws.soap;version="2.2", \
+ javax.xml.ws.spi;version="2.2", \
+ javax.xml.ws.wsaddressing;version="2.2", \
+ javax.xml.ws.spi.http;version="2.2", \
+ javax.xml.xpath, \
+ org.ietf.jgss, \
+ org.omg.CORBA, \
+ org.omg.CORBA_2_3, \
+ org.omg.CORBA_2_3.portable, \
+ org.omg.CORBA.DynAnyPackage, \
+ org.omg.CORBA.ORBPackage, \
+ org.omg.CORBA.portable, \
+ org.omg.CORBA.TypeCodePackage, \
+ org.omg.CosNaming, \
+ org.omg.CosNaming.NamingContextExtPackage, \
+ org.omg.CosNaming.NamingContextPackage, \
+ org.omg.Dynamic, \
+ org.omg.DynamicAny, \
+ org.omg.DynamicAny.DynAnyFactoryPackage, \
+ org.omg.DynamicAny.DynAnyPackage, \
+ org.omg.IOP, \
+ org.omg.IOP.CodecFactoryPackage, \
+ org.omg.IOP.CodecPackage, \
+ org.omg.Messaging, \
+ org.omg.PortableInterceptor, \
+ org.omg.PortableInterceptor.ORBInitInfoPackage, \
+ org.omg.PortableServer, \
+ org.omg.PortableServer.CurrentPackage, \
+ org.omg.PortableServer.POAManagerPackage, \
+ org.omg.PortableServer.POAPackage, \
+ org.omg.PortableServer.portable, \
+ org.omg.PortableServer.ServantLocatorPackage, \
+ org.omg.SendingContext, \
+ org.omg.stub.java.rmi, \
+ org.omg.stub.javax.management.remote.rmi, \
+ org.w3c.dom, \
+ org.w3c.dom.bootstrap, \
+ org.w3c.dom.css, \
+ org.w3c.dom.events, \
+ org.w3c.dom.html, \
+ org.w3c.dom.ls, \
+ org.w3c.dom.ranges, \
+ org.w3c.dom.stylesheets, \
+ org.w3c.dom.traversal, \
+ org.w3c.dom.views, \
+ org.w3c.dom.xpath, \
+ org.xml.sax, \
+ org.xml.sax.ext, \
+ org.xml.sax.helpers, \
+ sun.misc
+
+jre-1.8= \
+ javax.accessibility, \
+ javax.activation;version="1.1", \
+ javax.activity, \
+ javax.annotation;version="1.2", \
+ javax.annotation.processing;version="1.2", \
+ javax.crypto, \
+ javax.crypto.interfaces, \
+ javax.crypto.spec, \
+ javax.imageio, \
+ javax.imageio.event, \
+ javax.imageio.metadata, \
+ javax.imageio.plugins.bmp, \
+ javax.imageio.plugins.jpeg, \
+ javax.imageio.spi, \
+ javax.imageio.stream, \
+ javax.jws, \
+ javax.jws.soap, \
+ javax.lang.model, \
+ javax.lang.model.element, \
+ javax.lang.model.type, \
+ javax.lang.model.util, \
+ javax.management, \
+ javax.management.loading, \
+ javax.management.modelmbean, \
+ javax.management.monitor, \
+ javax.management.openmbean, \
+ javax.management.relation, \
+ javax.management.remote, \
+ javax.management.remote.rmi, \
+ javax.management.timer, \
+ javax.naming, \
+ javax.naming.directory, \
+ javax.naming.event, \
+ javax.naming.ldap, \
+ javax.naming.spi, \
+ javax.net, \
+ javax.net.ssl, \
+ javax.print, \
+ javax.print.attribute, \
+ javax.print.attribute.standard, \
+ javax.print.event, \
+ javax.rmi, \
+ javax.rmi.CORBA, \
+ javax.rmi.ssl, \
+ javax.script, \
+ javax.security.auth, \
+ javax.security.auth.callback, \
+ javax.security.auth.kerberos, \
+ javax.security.auth.login, \
+ javax.security.auth.spi, \
+ javax.security.auth.x500, \
+ javax.security.cert, \
+ javax.security.sasl, \
+ javax.sound.midi, \
+ javax.sound.midi.spi, \
+ javax.sound.sampled, \
+ javax.sound.sampled.spi, \
+ javax.sql, \
+ javax.sql.rowset, \
+ javax.sql.rowset.serial, \
+ javax.sql.rowset.spi, \
+ javax.swing, \
+ javax.swing.border, \
+ javax.swing.colorchooser, \
+ javax.swing.event, \
+ javax.swing.filechooser, \
+ javax.swing.plaf, \
+ javax.swing.plaf.basic, \
+ javax.swing.plaf.metal, \
+ javax.swing.plaf.multi, \
+ javax.swing.plaf.synth, \
+ javax.swing.table, \
+ javax.swing.text, \
+ javax.swing.text.html, \
+ javax.swing.text.html.parser, \
+ javax.swing.text.rtf, \
+ javax.swing.tree, \
+ javax.swing.undo, \
+ javax.tools, \
+ javax.transaction; javax.transaction.xa; partial=true; mandatory:=partial, \
+ javax.xml, \
+ javax.xml.bind;version="2.2.1", \
+ javax.xml.bind.annotation;version="2.2.1", \
+ javax.xml.bind.annotation.adapters;version="2.2.1", \
+ javax.xml.bind.attachment;version="2.2.1", \
+ javax.xml.bind.helpers;version="2.2.1", \
+ javax.xml.bind.util;version="2.2.1", \
+ javax.xml.crypto, \
+ javax.xml.crypto.dom, \
+ javax.xml.crypto.dsig, \
+ javax.xml.crypto.dsig.dom, \
+ javax.xml.crypto.dsig.keyinfo, \
+ javax.xml.crypto.dsig.spec, \
+ javax.xml.datatype, \
+ javax.xml.namespace, \
+ javax.xml.parsers, \
+ javax.xml.soap;version="1.3", \
+ javax.xml.stream;version="1.2", \
+ javax.xml.stream.events;version="1.2", \
+ javax.xml.stream.util;version="1.2", \
+ javax.xml.transform, \
+ javax.xml.transform.dom, \
+ javax.xml.transform.sax, \
+ javax.xml.transform.stax, \
+ javax.xml.transform.stream, \
+ javax.xml.validation, \
+ javax.xml.ws;version="2.2", \
+ javax.xml.ws.handler;version="2.2", \
+ javax.xml.ws.handler.soap;version="2.2", \
+ javax.xml.ws.http;version="2.2", \
+ javax.xml.ws.soap;version="2.2", \
+ javax.xml.ws.spi;version="2.2", \
+ javax.xml.ws.wsaddressing;version="2.2", \
+ javax.xml.ws.spi.http;version="2.2", \
+ javax.xml.xpath, \
+ org.ietf.jgss, \
+ org.omg.CORBA, \
+ org.omg.CORBA_2_3, \
+ org.omg.CORBA_2_3.portable, \
+ org.omg.CORBA.DynAnyPackage, \
+ org.omg.CORBA.ORBPackage, \
+ org.omg.CORBA.portable, \
+ org.omg.CORBA.TypeCodePackage, \
+ org.omg.CosNaming, \
+ org.omg.CosNaming.NamingContextExtPackage, \
+ org.omg.CosNaming.NamingContextPackage, \
+ org.omg.Dynamic, \
+ org.omg.DynamicAny, \
+ org.omg.DynamicAny.DynAnyFactoryPackage, \
+ org.omg.DynamicAny.DynAnyPackage, \
+ org.omg.IOP, \
+ org.omg.IOP.CodecFactoryPackage, \
+ org.omg.IOP.CodecPackage, \
+ org.omg.Messaging, \
+ org.omg.PortableInterceptor, \
+ org.omg.PortableInterceptor.ORBInitInfoPackage, \
+ org.omg.PortableServer, \
+ org.omg.PortableServer.CurrentPackage, \
+ org.omg.PortableServer.POAManagerPackage, \
+ org.omg.PortableServer.POAPackage, \
+ org.omg.PortableServer.portable, \
+ org.omg.PortableServer.ServantLocatorPackage, \
+ org.omg.SendingContext, \
+ org.omg.stub.java.rmi, \
+ org.omg.stub.javax.management.remote.rmi, \
+ org.w3c.dom, \
+ org.w3c.dom.bootstrap, \
+ org.w3c.dom.css, \
+ org.w3c.dom.events, \
+ org.w3c.dom.html, \
+ org.w3c.dom.ls, \
+ org.w3c.dom.ranges, \
+ org.w3c.dom.stylesheets, \
+ org.w3c.dom.traversal, \
+ org.w3c.dom.views, \
+ org.w3c.dom.xpath, \
+ org.xml.sax, \
+ org.xml.sax.ext, \
+ org.xml.sax.helpers, \
+ sun.misc
module ${artifactId} {
yang-version 1;
- namespace "urn:opendaylight:params:xml:ns:yang:example";
+ namespace "urn:opendaylight:params:xml:ns:yang:${artifactId}";
prefix "${artifactId}";
revision "2015-01-05" {
<?xml version="1.0" encoding="UTF-8"?>
<!-- vi: set et smarttab sw=4 tabstop=4: -->
<!--
-Necessary TODO: Put your copyright statement here
+${copyright}
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v1.0 which accompanies this distribution,
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
<?xml version="1.0" encoding="UTF-8"?>
-<!-- TODO: Put your copyright here:
-<your copyright> and others. All rights reserved.
+<!--
+${copyright} 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 INTERNAL
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
- <artifactId>${artifactId}</artifactId>
+ <artifactId>${artifactId}-karaf</artifactId>
<version>${version}</version>
<name>${project.artifactId}</name>
<prerequisites>
<?xml version="1.0" encoding="UTF-8"?>
-<!-- TODO: Put your copyright here:
-<your copyright> and others. All rights reserved.
+<!--
+${copyright} 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 INTERNAL
<T> T resolveInstance(Class<T> expectedType, ObjectName objectName,
JmxAttribute jmxAttribute);
+
/**
* To be used during commit phase to resolve identity-ref config attributes.
*
*/
<T> T newMXBeanProxy(ObjectName objectName, Class<T> interfaceClass);
+ /**
+ * Check whether a dependency will be reused or (re)created. Useful when deciding if current module could be also reused.
+ *
+ * @param objectName ObjectName ID of a dependency
+ * @param jmxAttribute JMXAttribute ID of a dependency
+ * @return true if the dependency will be reused false otherwise
+ */
+ boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute);
}
--- /dev/null
+package org.opendaylight.controller.config.spi;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base implementation of Module. This implementation contains base logic for Module reconfiguration with associated fields.
+ * @param <M> Type of module implementation. Enables easier implementation for the {@link #isSame} method
+ */
+public abstract class AbstractModule<M extends AbstractModule<M>> implements org.opendaylight.controller.config.spi.Module {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractModule.class);
+
+ private final M oldModule;
+ private final AutoCloseable oldInstance;
+ protected final ModuleIdentifier identifier;
+ private AutoCloseable instance;
+ protected final DependencyResolver dependencyResolver;
+
+ /**
+ * Called when module is configured.
+ *
+ * @param identifier id of current instance.
+ * @param dependencyResolver resolver used in dependency injection and validation.
+ */
+ public AbstractModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
+ this(identifier, dependencyResolver, null, null);
+ }
+
+ /**
+ * Called when module is reconfigured.
+ *
+ * @param identifier id of current instance.
+ * @param dependencyResolver resolver used in dependency injection and validation.
+ * @param oldModule old instance of module that is being reconfigred(replaced) by current instance. The old instance can be examined for reuse.
+ * @param oldInstance old instance wrapped by the old module. This is the resource that is actually being reused if possible or closed otherwise.
+ */
+ public AbstractModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver, M oldModule, AutoCloseable oldInstance) {
+ this.identifier = identifier;
+ this.dependencyResolver = dependencyResolver;
+ this.oldModule = oldModule;
+ this.oldInstance = oldInstance;
+ }
+
+ @Override
+ public ModuleIdentifier getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ *
+ * General algorithm for spawning/closing and reusing wrapped instances.
+ *
+ * @return current instance of wrapped resource either by reusing the old one (if present) or constructing a brand new.
+ */
+ @Override
+ public final AutoCloseable getInstance() {
+ if(instance==null) {
+ if(oldInstance!=null && canReuseInstance(oldModule)) {
+ resolveDependencies();
+ instance = reuseInstance(oldInstance);
+ } else {
+ if(oldInstance!=null) {
+ try {
+ oldInstance.close();
+ } catch(Exception e) {
+ LOG.error("An error occurred while closing old instance {} for module {}", oldInstance, getIdentifier(), e);
+ }
+ }
+ resolveDependencies();
+ instance = createInstance();
+ if (instance == null) {
+ throw new IllegalStateException("Error in createInstance - null is not allowed as return value. Module: " + getIdentifier());
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * @return Brand new instance of wrapped class in case no previous instance is present or reconfiguration is impossible.
+ */
+ protected abstract AutoCloseable createInstance();
+
+ @Override
+ public final boolean canReuse(Module oldModule) {
+ // Just cast into a specific instance
+ // TODO unify this method with canReuseInstance (required Module interface to be generic which requires quite a lot of changes)
+ return getClass().isInstance(oldModule) ? canReuseInstance((M) oldModule) : false;
+ }
+
+ /**
+ *
+ * Users are welcome to override this method to provide custom logic for advanced reusability detection.
+ *
+ * @param oldModule old instance of a Module
+ * @return true if the old instance is reusable false if a new one should be spawned
+ */
+ protected abstract boolean canReuseInstance(final M oldModule);
+
+ /**
+ * By default the oldInstance is returned since this method is by default called only if the oldModule had the same configuration and dependencies configured.
+ * Users are welcome to override this method to provide custom logic for advanced reusability.
+ *
+ * @param oldInstance old instance of a class wrapped by the module
+ * @return reused instance
+ */
+ protected AutoCloseable reuseInstance(AutoCloseable oldInstance) {
+ // implement if instance reuse should be supported. Override canReuseInstance to change the criteria.
+ return oldInstance;
+ }
+
+ /**
+ * Inject all the dependencies using dependency resolver instance.
+ */
+ protected abstract void resolveDependencies();
+}
*/
AutoCloseable getInstance();
+
+ /**
+ * Compare current module with oldModule and if the instance/live object
+ * produced by the old module can be reused in this module as well return true.
+ * Typically true should be returned if the old module had the same configuration.
+ *
+ *
+ * @param oldModule old instance of Module
+ * @return true if the instance produced by oldModule can be reused with current instance as well.
+ */
+ public boolean canReuse(Module oldModule);
+
+
}
}
}
- // destroy all live objects one after another in order of the dependency
- // hierarchy
+ // destroy all live objects one after another in order of the dependency hierarchy, from top to bottom
List<DestroyedModule> destroyedModules = currentConfig
.getModulesToBeDestroyed();
for (DestroyedModule destroyedModule : destroyedModules) {
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.String.format;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
LOG.trace("Committing transaction {}", getTransactionIdentifier());
- // call getInstance()
- for (Entry<ModuleIdentifier, Module> entry : dependencyResolverManager
- .getAllModules().entrySet()) {
- Module module = entry.getValue();
- ModuleIdentifier name = entry.getKey();
+ Map<ModuleIdentifier, Module> allModules = dependencyResolverManager.getAllModules();
+
+ // call getInstance() on all Modules from top to bottom (from source to target of the dependency relation)
+ // The source of a dependency closes itself and calls getInstance recursively on the dependencies (in case of reconfiguration)
+ // This makes close() calls from top to bottom while createInstance() calls are performed bottom to top
+ List<ModuleIdentifier> sortedModuleIdentifiers = Lists.reverse(dependencyResolverManager.getSortedModuleIdentifiers());
+ for (ModuleIdentifier moduleIdentifier : sortedModuleIdentifiers) {
+ Module module = allModules.get(moduleIdentifier);
+
try {
LOG.debug("About to commit {} in transaction {}",
- name, getTransactionIdentifier());
+ moduleIdentifier, getTransactionIdentifier());
AutoCloseable instance = module.getInstance();
- checkNotNull(instance, "Instance is null:{} in transaction {}", name, getTransactionIdentifier());
+ checkNotNull(instance, "Instance is null:{} in transaction {}", moduleIdentifier, getTransactionIdentifier());
} catch (Exception e) {
- LOG.error("Commit failed on {} in transaction {}", name,
+ LOG.error("Commit failed on {} in transaction {}", moduleIdentifier,
getTransactionIdentifier(), e);
internalAbort();
throw new IllegalStateException(
format("Error - getInstance() failed for %s in transaction %s",
- name, getTransactionIdentifier()), e);
+ moduleIdentifier, getTransactionIdentifier()), e);
}
}
- // count dependency order
-
LOG.trace("Committed configuration {}", getTransactionIdentifier());
transactionStatus.setCommitted();
- return dependencyResolverManager.getSortedModuleIdentifiers();
+ return sortedModuleIdentifiers;
}
@Override
import static java.lang.String.format;
+import com.google.common.base.Preconditions;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@Override
public <T> T resolveInstance(Class<T> expectedType, ObjectName dependentReadOnlyON,
JmxAttribute jmxAttribute) {
- if (expectedType == null || dependentReadOnlyON == null || jmxAttribute == null) {
- throw new IllegalArgumentException(format(
- "Null parameters not allowed, got %s %s %s", expectedType,
- dependentReadOnlyON, jmxAttribute));
- }
- ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
- transactionStatus.checkCommitStarted();
- transactionStatus.checkNotCommitted();
+ Module module = resolveModuleInstance(dependentReadOnlyON, jmxAttribute);
- ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
- translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
- Module module = modulesHolder.findModule(dependentModuleIdentifier,
- jmxAttribute);
synchronized (this) {
- dependencies.add(dependentModuleIdentifier);
+ dependencies.add(module.getIdentifier());
}
AutoCloseable instance = module.getInstance();
if (instance == null) {
String message = format(
"Error while %s resolving instance %s. getInstance() returned null. "
+ "Expected type %s , attribute %s", name,
- dependentModuleIdentifier, expectedType, jmxAttribute
+ module.getIdentifier(), expectedType, jmxAttribute
);
throw new JmxAttributeValidationException(message, jmxAttribute);
}
}
}
+ private Module resolveModuleInstance(ObjectName dependentReadOnlyON,
+ JmxAttribute jmxAttribute) {
+ Preconditions.checkArgument(dependentReadOnlyON != null ,"dependentReadOnlyON");
+ Preconditions.checkArgument(jmxAttribute != null, "jmxAttribute");
+ ObjectName translatedDependentReadOnlyON = translateServiceRefIfPossible(dependentReadOnlyON);
+ transactionStatus.checkCommitStarted();
+ transactionStatus.checkNotCommitted();
+
+ ModuleIdentifier dependentModuleIdentifier = ObjectNameUtil.fromON(
+ translatedDependentReadOnlyON, ObjectNameUtil.TYPE_MODULE);
+
+ return Preconditions.checkNotNull(modulesHolder.findModule(dependentModuleIdentifier, jmxAttribute));
+ }
+
+ @Override
+ public boolean canReuseDependency(ObjectName objectName, JmxAttribute jmxAttribute) {
+ Preconditions.checkNotNull(objectName);
+ Preconditions.checkNotNull(jmxAttribute);
+
+ Module currentModule = resolveModuleInstance(objectName, jmxAttribute);
+ ModuleIdentifier identifier = currentModule.getIdentifier();
+ ModuleInternalTransactionalInfo moduleInternalTransactionalInfo = modulesHolder.findModuleInternalTransactionalInfo(identifier);
+
+ if(moduleInternalTransactionalInfo.hasOldModule()) {
+ Module oldModule = moduleInternalTransactionalInfo.getOldInternalInfo().getReadableModule().getModule();
+ return currentModule.canReuse(oldModule);
+ }
+ return false;
+ }
+
@Override
public <T extends BaseIdentity> Class<? extends T> resolveIdentity(IdentityAttributeRef identityRef, Class<T> expectedBaseClass) {
final QName qName = QName.create(identityRef.getqNameOfIdentity());
@Override
public int compareTo(DependencyResolverImpl o) {
- transactionStatus.checkCommitted();
+ transactionStatus.checkCommitStarted();
return Integer.compare(getMaxDependencyDepth(),
o.getMaxDependencyDepth());
}
}
void countMaxDependencyDepth(DependencyResolverManager manager) {
- transactionStatus.checkCommitted();
+ // We can calculate the dependency after second phase commit was started
+ // Second phase commit starts after validation and validation adds the dependencies into the dependency resolver, which are necessary for the calculation
+ // FIXME generated code for abstract module declares validate method as non-final
+ // Overriding the validate would cause recreate every time instead of reuse + also possibly wrong close order if there is another module depending
+ transactionStatus.checkCommitStarted();
if (maxDependencyDepth == null) {
maxDependencyDepth = getMaxDepth(this, manager,
new LinkedHashSet<ModuleIdentifier>());
* things?
*/
private List<DependencyResolverImpl> getAllSorted() {
- transactionStatus.checkCommitted();
+ transactionStatus.checkCommitStarted();
List<DependencyResolverImpl> sorted = new ArrayList<>(
moduleIdentifiersToDependencyResolverMap.values());
for (DependencyResolverImpl dri : sorted) {
*/
package org.opendaylight.controller.config.manager.impl.dependencyresolver;
+import com.google.common.base.Preconditions;
import javax.annotation.Nullable;
import org.opendaylight.controller.config.api.ModuleIdentifier;
import org.opendaylight.controller.config.manager.impl.ModuleInternalInfo;
@Nullable
public ModuleInternalInfo getOldInternalInfo() {
- if (maybeOldInternalInfo == null) {
- throw new NullPointerException();
- }
- return maybeOldInternalInfo;
+ return Preconditions.checkNotNull(maybeOldInternalInfo);
}
public TransactionModuleJMXRegistration getTransactionModuleJMXRegistration() {
this.id = id==null ? new ModuleIdentifier(getClass().getCanonicalName(), "mock") : id;
}
+
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return instance!=null;
+ }
+
@Override
public void validate() {
}
moduleName124, instanceName134);
assertEquals(Sets.newHashSet(name1), beans);
}
-
-}
+}
\ No newline at end of file
// switch to second phase committed
reset(transactionStatus);
+ doNothing().when(transactionStatus).checkCommitStarted();
doNothing().when(transactionStatus).checkCommitted();
+ doNothing().when(transactionStatus).checkNotCommitted();
+
List<ModuleIdentifier> sortedModuleIdentifiers = tested
.getSortedModuleIdentifiers();
assertEquals(
private static Module mockedModule() {
Module mockedModule = mock(Module.class);
doReturn(mock(AutoCloseable.class)).when(mockedModule).getInstance();
+ doReturn(new ModuleIdentifier("fact", "instance")).when(mockedModule).getIdentifier();
return mockedModule;
}
return instance;
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return false;
+ }
+
@Override
public ModuleIdentifier getIdentifier() {
return identifier;
}
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return false;
+ }
+
@Override
public Closeable getInstance() {
return new MockedThreadPool(threadCount);
"Parameter 'ThreadCount' must be greater than 0");
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return false;
+ }
+
@Override
public int getThreadCount() {
return threadCount;
"Parameter 'threadCount' must be greater than 0");
}
+ @Override
+ public boolean canReuse(final Module oldModule) {
+ return isReusable() && triggerNewInstanceCreation == false;
+ }
+
@Override
public Closeable getInstance() {
if (instance == null) {
private FixedThreadPoolModuleFactory factory;
private final String nameInstance = "fixedInstance";
+ private ObjectName threadFactoryON;
@Before
public void setUp() {
assertBeanCount(1, factory.getImplementationName());
transaction = configRegistryClient.createTransaction();
+ NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON, NamingThreadFactoryModuleMXBean.class);
+ namingThreadFactoryModuleMXBean.setNamePrefix("newPrefix");
CommitStatus status = transaction.commit();
assertBeanCount(1, factory.getImplementationName());
- assertStatus(status, 0, 0, 2);
+ assertStatus(status, 0, 2, 0);
}
@Test
FixedThreadPoolModuleMXBean mxBean = transaction.newMXBeanProxy(nameCreated, FixedThreadPoolModuleMXBean.class);
mxBean.setMaxThreadCount(numberOfThreads);
- ObjectName threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming");
+ threadFactoryON = transaction.createModule(NamingThreadFactoryModuleFactory.NAME, "naming");
NamingThreadFactoryModuleMXBean namingThreadFactoryModuleMXBean = transaction.newMXBeanProxy(threadFactoryON,
NamingThreadFactoryModuleMXBean.class);
namingThreadFactoryModuleMXBean.setNamePrefix(prefix);
doReturn(mock(ExecutorService.class)).when(pool).getExecutor();
return pool;
}
-
}
return fact;
}
+ @Override
+ public boolean canReuse(Module oldModule) {
+ return false;
+ }
+
}
private final String registratorType;
public AbstractModuleTemplate(Header header, String packageName,
- String abstractModuleName, List<String> implementedIfcs,
- List<ModuleField> moduleFields, List<MethodDefinition> methods,
+ String abstractModuleName, List<String> extendedClasses,
+ List<String> implementedIfcs, List<ModuleField> moduleFields, List<MethodDefinition> methods,
boolean isRuntime, String registratorType) {
- super(header, packageName, abstractModuleName, Collections
- .<String> emptyList(), implementedIfcs, Collections
- .<Field> emptyList(), methods, true, false, Collections
- .<Constructor> emptyList());
+ super(header, packageName, abstractModuleName, extendedClasses,
+ implementedIfcs, Collections.<Field> emptyList(), methods,
+ true, false, Collections.<Constructor> emptyList());
this.moduleFields = moduleFields;
this.runtime = isRuntime;
this.registratorType = registratorType;
static List<String> checkCardinality(List<String> extendedClass) {
if (extendedClass.size() > 1) {
throw new IllegalArgumentException(
- "Class cannot have more than one super " + "class");
+ "Class cannot have more than one super class, found: " + extendedClass);
}
return extendedClass;
}
import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.runtime.RuntimeBean;
-import org.opendaylight.controller.config.spi.Module;
+import org.opendaylight.controller.config.spi.AbstractModule;
import org.opendaylight.controller.config.yangjmxgenerator.AbstractEntry;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
List<ModuleField> moduleFields = attrProcessor.getModuleFields();
List<String> implementedIfcs = Lists.newArrayList(
- Module.class.getCanonicalName(),
mbe.getFullyQualifiedName(mbe.getMXBeanInterfaceName()));
for (String implementedService : mbe.getProvidedServices().keySet()) {
.getCanonicalName());
}
+ List<String> extendedClasses = Collections.singletonList(AbstractModule.class.getCanonicalName() + "<" + mbe.getAbstractModuleName() + ">");
+
AbstractModuleTemplate abstractModuleTemplate = new AbstractModuleTemplate(
getHeaderFromEntry(mbe), mbe.getPackageName(),
- mbe.getAbstractModuleName(), implementedIfcs, moduleFields,
+ mbe.getAbstractModuleName(), extendedClasses, implementedIfcs, moduleFields,
attrProcessor.getMethods(), generateRuntime,
registratorFullyQualifiedName);
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
+import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
-import java.util.ArrayList;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.AbstractModuleTemplate;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.IdentityRefModuleField;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Method;
+import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.FullyQualifiedName;
import org.opendaylight.controller.config.yangjmxgenerator.plugin.java.GeneratedObject;
public class AbsModuleGeneratedObjectFactory {
+ private static final Function<String, FullyQualifiedName> FULLY_QUALIFIED_NAME_FUNCTION = new Function<String, FullyQualifiedName>() {
+ @Override
+ public FullyQualifiedName apply(final String input) {
+ return FullyQualifiedName.fromString(input);
+ }
+ };
+
public GeneratedObject toGeneratedObject(ModuleMXBeanEntry mbe, Optional<String> copyright) {
FullyQualifiedName abstractFQN = new FullyQualifiedName(mbe.getPackageName(), mbe.getAbstractModuleName());
Optional<String> classJavaDoc = Optional.fromNullable(mbe.getNullableDescription());
AbstractModuleTemplate abstractModuleTemplate = TemplateFactory.abstractModuleTemplateFromMbe(mbe);
Optional<String> header = abstractModuleTemplate.getHeaderString();
- List<FullyQualifiedName> implementedInterfaces = new ArrayList<>();
- for(String implemented: abstractModuleTemplate.getTypeDeclaration().getImplemented()) {
- implementedInterfaces.add(FullyQualifiedName.fromString(implemented));
- }
+ List<FullyQualifiedName> implementedInterfaces = Lists.transform(abstractModuleTemplate.getTypeDeclaration().getImplemented(), FULLY_QUALIFIED_NAME_FUNCTION);
+
+ Optional<FullyQualifiedName> extended =
+ Optional.fromNullable(
+ Iterables.getFirst(
+ Collections2.transform(abstractModuleTemplate.getTypeDeclaration().getExtended(), FULLY_QUALIFIED_NAME_FUNCTION), null));
+
Optional<FullyQualifiedName> maybeRegistratorType;
if (abstractModuleTemplate.isRuntime()) {
maybeRegistratorType = Optional.of(FullyQualifiedName.fromString(abstractModuleTemplate.getRegistratorType()));
maybeRegistratorType = Optional.absent();
}
- return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, implementedInterfaces,
+ return toGeneratedObject(abstractFQN, copyright, header, classJavaDoc, extended, implementedInterfaces,
abstractModuleTemplate.getModuleFields(), maybeRegistratorType, abstractModuleTemplate.getMethods(),
mbe.getYangModuleQName());
}
Optional<String> copyright,
Optional<String> header,
Optional<String> classJavaDoc,
+ Optional<FullyQualifiedName> extended,
List<FullyQualifiedName> implementedInterfaces,
List<ModuleField> moduleFields,
Optional<FullyQualifiedName> maybeRegistratorType,
for(FullyQualifiedName implemented: implementedInterfaces) {
b.addImplementsFQN(implemented);
}
+ if(extended.isPresent()) {
+ b.addExtendsFQN(extended.get());
+ }
if (classJavaDoc.isPresent()) {
b.addClassAnnotation(format("@%s(value=\"%s\")", Description.class.getCanonicalName(), classJavaDoc.get()));
}
b.addToBody("//attributes end");
- b.addToBody(getCommonFields(abstractFQN));
-
-
b.addToBody(getNewConstructor(abstractFQN));
b.addToBody(getCopyFromOldConstructor(abstractFQN));
b.addToBody(getCachesOfResolvedDependencies(moduleFields));
b.addToBody(getCachesOfResolvedIdentityRefs(moduleFields));
- b.addToBody(getGetInstance(moduleFields));
+ b.addToBody(getResolveDependencies(moduleFields));
b.addToBody(getReuseLogic(moduleFields, abstractFQN));
b.addToBody(getEqualsAndHashCode(abstractFQN));
b.addToBody(getMethods(methods));
+ b.addToBody(getGetLogger());
return new GeneratedObjectBuilder(b.build()).toGeneratedObject();
}
// loop through fields, do deep equals on each field
for (ModuleField moduleField : moduleFields) {
+ result += format(
+ "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
+ "return false;\n"+
+ "}\n", moduleField.getName());
+
if (moduleField.isListOfDependencies()) {
result += format(
- "if (%1$sDependency.equals(other.%1$sDependency) == false) {\n"+
- "return false;\n"+
- "}\n"+
- "for (int idx = 0; idx < %1$sDependency.size(); idx++) {\n"+
- "if (%1$sDependency.get(idx) != other.%1$sDependency.get(idx)) {\n"+
- "return false;\n"+
- "}\n"+
- "}\n" ,moduleField.getName());
+ "for (int idx = 0; idx < %1$s.size(); idx++) {\n"+
+ "if (!dependencyResolver.canReuseDependency(%1$s.get(idx), %1$sJmxAttribute)) {\n"+
+ "return false;\n"+
+ "}\n"+
+ "}\n" , moduleField.getName());
} else if (moduleField.isDependent()) {
result += format(
- "if (%sDependency != other.%1$sDependency) { // reference to dependency must be same\n"+
- "return false;\n"+
- "}\n",moduleField.getName());
- } else {
- result += format(
- "if (java.util.Objects.deepEquals(%s, other.%1$s) == false) {\n"+
- "return false;\n"+
- "}\n", moduleField.getName());
+ // If a reference is null (ie optional reference) it makes no sens to call canReuse on it
+ // In such case we continue in the isSame method because if we have null here, the previous value was null as well
+ // If the previous value was not null and current is or vice verse, the deepEquals comparison would return false
+ "if(%1$s!= null) {\n" +
+ "if (!dependencyResolver.canReuseDependency(%1$s, %1$sJmxAttribute)) { // reference to dependency must be reusable as well\n" +
+ "return false;\n" +
+ "}\n" +
+ "}\n", moduleField.getName());
}
}
+
result += "\n"+
"return true;\n"+
"}\n";
return result;
}
- private static String getGetInstance(List<ModuleField> moduleFields) {
- String result = "\n"+
- "@Override\n"+
- format("public final %s getInstance() {\n", AutoCloseable.class.getCanonicalName())+
- "if(instance==null) {\n";
- // create instance start
-
+ private static String getResolveDependencies(final List<ModuleField> moduleFields) {
// loop through dependent fields, use dependency resolver to instantiate dependencies. Do it in loop in case field represents list of dependencies.
Map<ModuleField, String> resolveDependenciesMap = new HashMap<>();
for(ModuleField moduleField: moduleFields) {
String osgi = moduleField.getDependency().getSie().getExportedOsgiClassName();
if (moduleField.isList()) {
str = format(
- "%sDependency = new java.util.ArrayList<%s>();\n"+
- "for(javax.management.ObjectName dep : %1$s) {\n"+
- "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
- "}\n", moduleField.getName(), osgi);
+ "%sDependency = new java.util.ArrayList<%s>();\n"+
+ "for(javax.management.ObjectName dep : %1$s) {\n"+
+ "%1$sDependency.add(dependencyResolver.resolveInstance(%2$s.class, dep, %1$sJmxAttribute));\n"+
+ "}\n", moduleField.getName(), osgi);
} else {
str = format(
- "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
- moduleField.getName(), osgi);
+ "%1$sDependency = dependencyResolver.resolveInstance(%2$s.class, %1$s, %1$sJmxAttribute);\n",
+ moduleField.getName(), osgi);
}
resolveDependenciesMap.put(moduleField, str);
}
}
+ String result = "\n"
+ + "protected final void resolveDependencies() {\n";
// wrap each field resolvation statement with if !=null when dependency is not mandatory
for (Map.Entry<ModuleField, String> entry : resolveDependenciesMap.entrySet()) {
if (entry.getKey().getDependency().isMandatory() == false) {
result += format("if (%s!=null){\n", moduleField.getName());
if (moduleField.isList()) {
result += format(
- "for(%s candidate : %s) {\n"+
- "candidate.injectDependencyResolver(dependencyResolver);\n"+
- "}\n", moduleField.getGenericInnerType(), moduleField.getName());
+ "for(%s candidate : %s) {\n"+
+ "candidate.injectDependencyResolver(dependencyResolver);\n"+
+ "}\n", moduleField.getGenericInnerType(), moduleField.getName());
} else {
result += format("%s.injectDependencyResolver(dependencyResolver);\n", moduleField.getName());
}
result += "}\n";
}
}
-
- // create instance end: reuse and recreate logic
- result += "if(oldInstance!=null && canReuseInstance(oldModule)) {\n"+
- "instance = reuseInstance(oldInstance);\n"+
- "} else {\n"+
- "if(oldInstance!=null) {\n"+
- "try {\n"+
- "oldInstance.close();\n"+
- "} catch(Exception e) {\n"+
- "logger.error(\"An error occurred while closing old instance \" + oldInstance, e);\n"+
- "}\n"+
- "}\n"+
- "instance = createInstance();\n"+
- "if (instance == null) {\n"+
- "throw new IllegalStateException(\"Error in createInstance - null is not allowed as return value\");\n"+
- "}\n"+
- "}\n"+
- "}\n"+
- "return instance;\n"+
- "}\n"+
- format("public abstract %s createInstance();\n", AutoCloseable.class.getCanonicalName());
-
+ result += "}\n";
return result;
}
- private static String getCommonFields(FullyQualifiedName abstractFQN) {
- return "\n"+
- format("private final %s oldModule;\n", abstractFQN.getTypeName())+
- format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+
- format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+
- format("protected final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+
- format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+
- "@Override\n"+
- format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+
- "return identifier;\n"+
- "}\n";
- }
-
private static String getCachesOfResolvedIdentityRefs(List<ModuleField> moduleFields) {
StringBuilder result = new StringBuilder();
for (ModuleField moduleField : moduleFields) {
"public void validate() {\n";
// validate each mandatory dependency
for(ModuleField moduleField: moduleFields) {
- if (moduleField.isDependent() && moduleField.getDependency().isMandatory()) {
+ if (moduleField.isDependent()) {
if (moduleField.isList()) {
result += "" +
format("for(javax.management.ObjectName dep : %s) {\n", moduleField.getName()) +
moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName()) +
"}\n";
} else {
- result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);",
+ if(moduleField.getDependency().isMandatory() == false) {
+ result += format("if(%s != null) {\n", moduleField.getName());
+ }
+ result += format("dependencyResolver.validateDependency(%s.class, %s, %sJmxAttribute);\n",
moduleField.getDependency().getSie().getFullyQualifiedName(), moduleField.getName(), moduleField.getName());
+ if(moduleField.getDependency().isMandatory() == false) {
+ result += "}\n";
+ }
}
}
}
}
private static String getLoggerDefinition(FullyQualifiedName fqn) {
- return format("private static final %s logger = %s.getLogger(%s.class);",
+ return format("private static final %s LOGGER = %s.getLogger(%s.class);",
Logger.class.getCanonicalName(), LoggerFactory.class.getCanonicalName(), fqn);
}
private static String getConstructorStart(FullyQualifiedName fqn,
LinkedHashMap<String, String> parameters, String after) {
String paramString = Joiner.on(",").withKeyValueSeparator(" ").join(parameters);
- String setters = "";
- for (String paramName : parameters.values()) {
- setters += format("this.%s = %1$s;\n", paramName);
- }
return format("public %s(", fqn.getTypeName()) +
paramString +
") {\n" +
- setters +
after +
"}\n";
}
LinkedHashMap<String, String> parameters = new LinkedHashMap<>();
parameters.put(ModuleIdentifier.class.getCanonicalName(), "identifier");
parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
-
- String setToNulls = "this.oldInstance=null;\n" +
- "this.oldModule=null;\n";
- return getConstructorStart(abstractFQN, parameters, setToNulls);
+ String init = "super(identifier, dependencyResolver);\n";
+ return getConstructorStart(abstractFQN, parameters, init);
}
private static String getCopyFromOldConstructor(FullyQualifiedName abstractFQN) {
parameters.put(DependencyResolver.class.getCanonicalName(), "dependencyResolver");
parameters.put(abstractFQN.getTypeName(), "oldModule");
parameters.put(AutoCloseable.class.getCanonicalName(), "oldInstance");
- return getConstructorStart(abstractFQN, parameters, "");
+ String init = "super(identifier, dependencyResolver, oldModule, oldInstance);\n";
+ return getConstructorStart(abstractFQN, parameters, init);
+ }
+
+ public String getGetLogger() {
+ return new MethodDefinition(Logger.class.getCanonicalName(), "getLogger", Collections.<Field>emptyList(), "return LOGGER;").toString();
}
}
import org.opendaylight.controller.config.api.annotations.Description;
import org.opendaylight.controller.config.api.annotations.RequireInterface;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.spi.AbstractModule;
import org.opendaylight.controller.config.spi.Module;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ConfigConstants;
assertContains(visitor.implmts,
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.java.DynamicThreadPoolModuleMXBean",
- Module.class.getCanonicalName(),
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ScheduledThreadPoolServiceInterface",
PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ThreadPoolServiceInterface");
+ assertContains(visitor.extnds, AbstractModule.class.getCanonicalName());
assertEquals(2, visitor.constructors.size());
Set<String> fieldDeclarations = visitor.fieldDeclarations;
assertDeclaredField(fieldDeclarations,
assertDeclaredField(fieldDeclarations,
"private java.lang.Long coreSize");
assertDeclaredField(fieldDeclarations, "private byte[] binary");
- assertEquals(22, fieldDeclarations.size());
+ assertEquals(17, fieldDeclarations.size());
assertEquals(1, visitor.requireIfc.size());
String reqIfc = visitor.requireIfc.get("setThreadfactory");
assertContains(reqIfc, PackageTranslatorTest.EXPECTED_PACKAGE_PREFIX
+ ".threads.ThreadFactoryServiceInterface");
- assertEquals("Incorrenct number of generated methods", 27,
+ assertEquals("Incorrenct number of generated methods", 26,
visitor.methods.size());
assertEquals("Incorrenct number of generated method descriptions", 3,
visitor.methodDescriptions.size());
*.java
+!CheckedAutoCloseable.java
--- /dev/null
+package org.opendaylight.controller.config.yang.test.impl;
+
+import com.google.common.base.Preconditions;
+
+public class CheckedAutoCloseable implements AutoCloseable {
+ private boolean closed = false;
+
+ @Override
+ public synchronized void close() throws Exception {
+ Preconditions.checkState(closed == false);
+ this.closed = true;
+ }
+
+ public synchronized boolean isClosed() {
+ return this.closed;
+ }
+}
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
}
logger.info("IdentityContainer Afi class: {}", getIdentitiesContainer().resolveAfi());
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
- return new AutoCloseable() {
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable() {
@Override
- public void close() throws Exception {
+ public synchronized void close() throws Exception {
+ if(getSingleDependency() != null && getSingleDependency().isClosed() == true) {
+ // Simulate a cleanup on dependencies that should not be closed yet
+ throw new java.lang.Error("Dependency was closed first");
+ }
+ for (org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable autoCloseable : getTestingDepsDependency()) {
+ if(autoCloseable.isClosed() == true) {
+ // Simulate a cleanup on dependencies that should not be closed yet
+ throw new java.lang.Error("Dependency was closed first");
+ }
+ }
+ super.close();
}
- };
+ };
\ No newline at end of file
- return org.opendaylight.controller.config.yang.test.util.NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+ final AutoCloseable runtime = org.opendaylight.controller.config.yang.test.util.NetconfTestImplModuleUtil.registerRuntimeBeans(this);
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable() {
+ @Override
+ public synchronized void close() throws Exception {
+ runtime.close();
+ }
+ };
\ No newline at end of file
- return new AutoCloseable() {
- @Override
- public void close() throws Exception {
- }
- };
+ return new org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable();
\ No newline at end of file
}
}
}
+
}
+
}
}
}
}
}
+ container single {
+ uses config:service-ref {
+ refine type {
+ mandatory false;
+ config:required-identity test:testing;
+ }
+ }
+ }
+
+ leaf simple {
+ type boolean;
+ default false;
+ }
}
}
}
"Test api";
base "config:service-type";
- config:java-class "java.lang.AutoCloseable";
+ config:java-class "org.opendaylight.controller.config.yang.test.impl.CheckedAutoCloseable";
}
}
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getInstanceName;
import static org.opendaylight.controller.config.api.jmx.ObjectNameUtil.getTransactionName;
import java.util.List;
import javax.management.ObjectName;
+import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
assertNull(getTransactionName(d1WithoutTxName));
transaction.commit();
}
+
+ @Test
+ public void testCloseOrdering() throws Exception {
+ // Tests whether close is called in correct order on the module instances on following graph
+ // Each module tests whether its dependencies were closed before it (to simulate resource clean up failure)
+ // R1
+ // | \
+ // M1 M2
+ // |
+ // L1
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName r1 = transaction.createModule(factory.getImplementationName(), "root1");
+ ObjectName m1 = transaction.createModule(factory.getImplementationName(), "middle1");
+ ObjectName m2 = transaction.createModule(factory.getImplementationName(), "middle2");
+ ObjectName l1 = transaction.createModule(factory.getImplementationName(), "leaf1");
+
+ MultipleDependenciesModuleMXBean r1Proxy = transaction.newMXBeanProxy(r1, MultipleDependenciesModuleMXBean.class);
+ MultipleDependenciesModuleMXBean i1Proxy = transaction.newMXBeanProxy(m1, MultipleDependenciesModuleMXBean.class);
+ r1Proxy.setSingle(m1);
+ i1Proxy.setSingle(l1);
+ r1Proxy.setTestingDeps(asList(m2));
+ transaction.commit();
+
+ configRegistryClient.createTransaction().commit();
+ transaction = configRegistryClient.createTransaction();
+ MultipleDependenciesModuleMXBean l1Proxy = transaction.newMXBeanProxy(l1, MultipleDependenciesModuleMXBean.class);
+ l1Proxy.setSimple(true);
+ transaction.commit();
+ }
+
+ @Test
+ public void testDestroyModuleDependency() throws Exception {
+ ConfigTransactionJMXClient transaction = configRegistryClient.createTransaction();
+ ObjectName r1 = transaction.createModule(factory.getImplementationName(), "root1");
+ ObjectName m1 = transaction.createModule(factory.getImplementationName(), "middle1");
+
+ MultipleDependenciesModuleMXBean r1Proxy = transaction.newMXBeanProxy(r1, MultipleDependenciesModuleMXBean.class);
+ r1Proxy.setSingle(m1);
+ transaction.commit();
+
+ transaction = configRegistryClient.createTransaction();
+ transaction.destroyModule(factory.getImplementationName(), "middle1");
+ try {
+ transaction.commit();
+ fail("Validation exception expected");
+ } catch (ValidationException e) {
+ assertThat(e.getFailedValidations().keySet(), CoreMatchers.hasItem("multiple-dependencies"));
+ }
+ }
}
* @return FiniteDuration
*/
FiniteDuration getIsolatedCheckInterval();
+
+
+ /**
+ * The multiplication factor to be used to determine shard election timeout. The election timeout
+ * is determined by multiplying the election timeout factor with the heartbeat duration.
+ */
+ long getElectionTimeoutFactor();
+
}
public static final FiniteDuration HEART_BEAT_INTERVAL =
new FiniteDuration(100, TimeUnit.MILLISECONDS);
-
private FiniteDuration heartBeatInterval = HEART_BEAT_INTERVAL;
private long snapshotBatchCount = SNAPSHOT_BATCH_COUNT;
private int journalRecoveryLogBatchSize = JOURNAL_RECOVERY_LOG_BATCH_SIZE;
// in-memory journal can use before it needs to snapshot
private int snapshotDataThresholdPercentage = 12;
+ private long electionTimeoutFactor = 2;
+
public void setHeartBeatInterval(FiniteDuration heartBeatInterval) {
this.heartBeatInterval = heartBeatInterval;
}
this.isolatedLeaderCheckInterval = isolatedLeaderCheckInterval;
}
+ public void setElectionTimeoutFactor(long electionTimeoutFactor){
+ this.electionTimeoutFactor = electionTimeoutFactor;
+ }
+
@Override
public long getSnapshotBatchCount() {
return snapshotBatchCount;
@Override
public FiniteDuration getElectionTimeOutInterval() {
- // returns 2 times the heart beat interval
- return getHeartBeatInterval().$times(2);
+ return getHeartBeatInterval().$times(electionTimeoutFactor);
}
@Override
public FiniteDuration getIsolatedCheckInterval() {
return isolatedLeaderCheckInterval;
}
+
+ @Override
+ public long getElectionTimeoutFactor() {
+ return electionTimeoutFactor;
+ }
}
onRecoveryComplete();
- RaftActorBehavior oldBehavior = currentBehavior;
- currentBehavior = new Follower(context);
- handleBehaviorChange(oldBehavior, currentBehavior);
+ initializeBehavior();
}
}
}
replicatedLog.lastIndex(), replicatedLog.snapshotIndex,
replicatedLog.snapshotTerm, replicatedLog.size());
+ initializeBehavior();
+ }
+
+ protected void initializeBehavior(){
+ changeCurrentBehavior(new Follower(context));
+ }
+
+ protected void changeCurrentBehavior(RaftActorBehavior newBehavior){
RaftActorBehavior oldBehavior = currentBehavior;
- currentBehavior = new Follower(context);
+ currentBehavior = newBehavior;
handleBehaviorChange(oldBehavior, currentBehavior);
}
if (oldBehavior != currentBehavior){
onStateChanged();
}
- if (oldBehavior != null) {
- // it can happen that the state has not changed but the leader has changed.
- onLeaderChanged(oldBehavior.getLeaderId(), currentBehavior.getLeaderId());
- if (getRoleChangeNotifier().isPresent() && oldBehavior.state() != currentBehavior.state()) {
- // we do not want to notify when the behavior/role is set for the first time (i.e follower)
- getRoleChangeNotifier().get().tell(new RoleChanged(getId(), oldBehavior.state().name(),
- currentBehavior.state().name()), getSelf());
- }
+ String oldBehaviorLeaderId = oldBehavior == null? null : oldBehavior.getLeaderId();
+ String oldBehaviorState = oldBehavior == null? null : oldBehavior.state().name();
+
+ // it can happen that the state has not changed but the leader has changed.
+ onLeaderChanged(oldBehaviorLeaderId, currentBehavior.getLeaderId());
+
+ if (getRoleChangeNotifier().isPresent() &&
+ (oldBehavior == null || (oldBehavior.state() != currentBehavior.state()))) {
+ getRoleChangeNotifier().get().tell(
+ new RoleChanged(getId(), oldBehaviorState , currentBehavior.state().name()),
+ getSelf());
}
}
import akka.actor.ActorRef;
import akka.actor.Cancellable;
import akka.event.LoggingAdapter;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
import org.opendaylight.controller.cluster.raft.ClientRequestTracker;
import org.opendaylight.controller.cluster.raft.RaftActorContext;
import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
import scala.concurrent.duration.FiniteDuration;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-
/**
* Abstract class that represents the behavior of a RaftActor
* <p/>
protected FiniteDuration electionDuration() {
long variance = new Random().nextInt(context.getConfigParams().getElectionTimeVariance());
return context.getConfigParams().getElectionTimeOutInterval().$plus(
- new FiniteDuration(variance, TimeUnit.MILLISECONDS));
+ new FiniteDuration(variance, TimeUnit.MILLISECONDS));
}
/**
TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(id,
Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), notifierActor), id);
- MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
- mockRaftActor.setCurrentBehavior(new Follower(mockRaftActor.getRaftActorContext()));
-
// sleeping for a minimum of 2 seconds, if it spans more its fine.
Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
List<Object> matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
assertNotNull(matches);
- assertEquals(2, matches.size());
+ assertEquals(3, matches.size());
- // check if the notifier got a role change from Follower to Candidate
+ // check if the notifier got a role change from null to Follower
RoleChanged raftRoleChanged = (RoleChanged) matches.get(0);
assertEquals(id, raftRoleChanged.getMemberId());
+ assertNull(raftRoleChanged.getOldRole());
+ assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
+
+ // check if the notifier got a role change from Follower to Candidate
+ raftRoleChanged = (RoleChanged) matches.get(1);
+ assertEquals(id, raftRoleChanged.getMemberId());
assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
// check if the notifier got a role change from Candidate to Leader
- raftRoleChanged = (RoleChanged) matches.get(1);
+ raftRoleChanged = (RoleChanged) matches.get(2);
assertEquals(id, raftRoleChanged.getMemberId());
assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<name>yang-schema-service</name>
</operational-schema-service>
+ <operational-properties>
+ <persistent>false</persistent>
+ </operational-properties>
</module>
<module>
private final Timeout shardLeaderElectionTimeout;
private final boolean persistent;
private final ConfigurationReader configurationReader;
+ private final long shardElectionTimeoutFactor;
private DatastoreContext(InMemoryDOMDataStoreConfigProperties dataStoreProperties,
ConfigParams shardRaftConfig, String dataStoreMXBeanType, int operationTimeoutInSeconds,
Duration shardTransactionIdleTimeout, int shardTransactionCommitTimeoutInSeconds,
int shardTransactionCommitQueueCapacity, Timeout shardInitializationTimeout,
Timeout shardLeaderElectionTimeout,
- boolean persistent, ConfigurationReader configurationReader) {
+ boolean persistent, ConfigurationReader configurationReader, long shardElectionTimeoutFactor) {
this.dataStoreProperties = dataStoreProperties;
this.shardRaftConfig = shardRaftConfig;
this.dataStoreMXBeanType = dataStoreMXBeanType;
this.shardLeaderElectionTimeout = shardLeaderElectionTimeout;
this.persistent = persistent;
this.configurationReader = configurationReader;
+ this.shardElectionTimeoutFactor = shardElectionTimeoutFactor;
}
public static Builder newBuilder() {
return configurationReader;
}
+ public long getShardElectionTimeoutFactor(){
+ return this.shardElectionTimeoutFactor;
+ }
+
public static class Builder {
private InMemoryDOMDataStoreConfigProperties dataStoreProperties;
private Duration shardTransactionIdleTimeout = Duration.create(10, TimeUnit.MINUTES);
private ConfigurationReader configurationReader = new FileConfigurationReader();
private int shardIsolatedLeaderCheckIntervalInMillis = shardHeartbeatIntervalInMillis * 10;
private int shardSnapshotDataThresholdPercentage = 12;
+ private long shardElectionTimeoutFactor = 2;
public Builder shardTransactionIdleTimeout(Duration shardTransactionIdleTimeout) {
this.shardTransactionIdleTimeout = shardTransactionIdleTimeout;
return this;
}
+ public Builder shardElectionTimeoutFactor(long shardElectionTimeoutFactor){
+ this.shardElectionTimeoutFactor = shardElectionTimeoutFactor;
+ return this;
+ }
+
public DatastoreContext build() {
DefaultConfigParamsImpl raftConfig = new DefaultConfigParamsImpl();
raftConfig.setJournalRecoveryLogBatchSize(shardJournalRecoveryLogBatchSize);
raftConfig.setSnapshotBatchCount(shardSnapshotBatchCount);
raftConfig.setSnapshotDataThresholdPercentage(shardSnapshotDataThresholdPercentage);
+ raftConfig.setElectionTimeoutFactor(shardElectionTimeoutFactor);
raftConfig.setIsolatedLeaderCheckInterval(
new FiniteDuration(shardIsolatedLeaderCheckIntervalInMillis, TimeUnit.MILLISECONDS));
operationTimeoutInSeconds, shardTransactionIdleTimeout,
shardTransactionCommitTimeoutInSeconds, shardTransactionCommitQueueCapacity,
shardInitializationTimeout, shardLeaderElectionTimeout,
- persistent, configurationReader);
+ persistent, configurationReader, shardElectionTimeoutFactor);
}
}
}
private Cancellable txCommitTimeoutCheckSchedule;
- private Optional<ActorRef> roleChangeNotifier;
+ private final Optional<ActorRef> roleChangeNotifier;
/**
* Coordinates persistence recovery on startup.
doAbortTransaction(abort.getTransactionID(), getSender());
}
- private void doAbortTransaction(final String transactionID, final ActorRef sender) {
+ void doAbortTransaction(final String transactionID, final ActorRef sender) {
final CohortEntry cohortEntry = commitCoordinator.getCohortEntryIfCurrent(transactionID);
if(cohortEntry != null) {
LOG.debug("Aborting transaction {}", transactionID);
.persistent(props.getPersistent().booleanValue())
.shardIsolatedLeaderCheckIntervalInMillis(
props.getShardIsolatedLeaderCheckIntervalInMillis().getValue())
+ .shardElectionTimeoutFactor(props.getShardElectionTimeoutFactor().getValue())
.build();
return DistributedDataStoreFactory.createInstance("config", getConfigSchemaServiceDependency(),
.persistent(props.getPersistent().booleanValue())
.shardIsolatedLeaderCheckIntervalInMillis(
props.getShardIsolatedLeaderCheckIntervalInMillis().getValue())
+ .shardElectionTimeoutFactor(props.getShardElectionTimeoutFactor().getValue())
.build();
return DistributedDataStoreFactory.createInstance("operational",
description "The interval at which a shard will send a heart beat message to its remote shard.";
}
+ leaf shard-election-timeout-factor {
+ default 2;
+ type non-zero-uint32-type;
+ description "The multiplication factor to be used to determine shard election timeout. The shard election timeout
+ is determined by multiplying shard-heartbeat-interval-in-millis with the shard-election-timeout-factor";
+ }
+
leaf operation-timeout-in-seconds {
default 5;
type operation-timeout-type;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.cluster.datastore.DatastoreContext.Builder;
import org.opendaylight.controller.cluster.datastore.identifiers.ShardIdentifier;
import org.opendaylight.controller.cluster.datastore.messages.AbortTransaction;
import org.opendaylight.controller.cluster.datastore.messages.AbortTransactionReply;
private final ShardIdentifier shardID = ShardIdentifier.builder().memberName("member-1")
.shardName("inventory").type("config" + NEXT_SHARD_NUM.getAndIncrement()).build();
- private DatastoreContext dataStoreContext = DatastoreContext.newBuilder().
+ private final Builder dataStoreContextBuilder = DatastoreContext.newBuilder().
shardJournalRecoveryLogBatchSize(3).shardSnapshotBatchCount(5000).
- shardHeartbeatIntervalInMillis(100).build();
+ shardHeartbeatIntervalInMillis(100);
@Before
public void setUp() {
+ Builder newBuilder = DatastoreContext.newBuilder();
InMemorySnapshotStore.clear();
InMemoryJournal.clear();
}
InMemoryJournal.clear();
}
+ private DatastoreContext newDatastoreContext() {
+ return dataStoreContextBuilder.build();
+ }
+
private Props newShardProps() {
return Shard.props(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT);
+ newDatastoreContext(), SCHEMA_CONTEXT);
}
@Test
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
public void onReceiveCommand(final Object message) throws Exception {
if(message instanceof ElectionTimeout && firstElectionTimeout) {
class TestShard extends Shard {
TestShard() {
super(shardID, Collections.<ShardIdentifier, String>singletonMap(shardID, null),
- dataStoreContext, SCHEMA_CONTEXT);
+ newDatastoreContext(), SCHEMA_CONTEXT);
}
Map<String, String> getPeerAddresses() {
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
protected void onRecoveryComplete() {
try {
assertTrue("Missing leaf " + TestModel.ID_QNAME.getLocalName(), idLeaf.isPresent());
assertEquals(TestModel.ID_QNAME.getLocalName() + " value", 1, idLeaf.get().getValue());
- for(int i = 0; i < 20 * 5; i++) {
- long lastLogIndex = shard.underlyingActor().getShardMBean().getLastLogIndex();
- if(lastLogIndex == 2) {
- break;
- }
- Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+ verifyLastLogIndex(shard, 2);
+
+ shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
+ }};
+ }
+
+ private void verifyLastLogIndex(TestActorRef<Shard> shard, long expectedValue) {
+ for(int i = 0; i < 20 * 5; i++) {
+ long lastLogIndex = shard.underlyingActor().getShardMBean().getLastLogIndex();
+ if(lastLogIndex == expectedValue) {
+ break;
}
+ Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
+ }
+
+ assertEquals("Last log index", expectedValue, shard.underlyingActor().getShardMBean().getLastLogIndex());
+ }
+
+ @Test
+ public void testCommitWithPersistenceDisabled() throws Throwable {
+ dataStoreContextBuilder.persistent(false);
+ new ShardTestKit(getSystem()) {{
+ final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
+ newShardProps().withDispatcher(Dispatchers.DefaultDispatcherId()),
+ "testCommitPhaseFailure");
- assertEquals("Last log index", 2, shard.underlyingActor().getShardMBean().getLastLogIndex());
+ waitUntilLeader(shard);
+
+ InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
+
+ // Setup a simulated transactions with a mock cohort.
+
+ String transactionID = "tx";
+ MutableCompositeModification modification = new MutableCompositeModification();
+ NormalizedNode<?, ?> containerNode = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
+ DOMStoreThreePhaseCommitCohort cohort = setupMockWriteTransaction("cohort", dataStore,
+ TestModel.TEST_PATH, containerNode, modification);
+
+ FiniteDuration duration = duration("5 seconds");
+
+ // Simulate the ForwardedReadyTransaction messages that would be sent
+ // by the ShardTransaction.
+
+ shard.tell(new ForwardedReadyTransaction(transactionID, CURRENT_VERSION,
+ cohort, modification, true), getRef());
+ expectMsgClass(duration, ReadyTransactionReply.SERIALIZABLE_CLASS);
+
+ // Send the CanCommitTransaction message.
+
+ shard.tell(new CanCommitTransaction(transactionID).toSerializable(), getRef());
+ CanCommitTransactionReply canCommitReply = CanCommitTransactionReply.fromSerializable(
+ expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
+ assertEquals("Can commit", true, canCommitReply.getCanCommit());
+
+ // Send the CanCommitTransaction message.
+
+ shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef());
+ expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
+
+ InOrder inOrder = inOrder(cohort);
+ inOrder.verify(cohort).canCommit();
+ inOrder.verify(cohort).preCommit();
+ inOrder.verify(cohort).commit();
+
+ NormalizedNode<?, ?> actualNode = readStore(shard, TestModel.TEST_PATH);
+ assertEquals(TestModel.TEST_QNAME.getLocalName(), containerNode, actualNode);
shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
}};
}
@Test
- @Ignore("This test will work only if replication is turned on. Needs modification due to optimizations added to Shard/RaftActor.")
public void testAbortBeforeFinishCommit() throws Throwable {
new ShardTestKit(getSystem()) {{
final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
waitUntilLeader(shard);
final FiniteDuration duration = duration("5 seconds");
- final Timeout timeout = new Timeout(duration);
-
InMemoryDOMDataStore dataStore = shard.underlyingActor().getDataStore();
final String transactionID = "tx1";
- final CountDownLatch abortComplete = new CountDownLatch(1);
Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>> preCommit =
new Function<DOMStoreThreePhaseCommitCohort,ListenableFuture<Void>>() {
@Override
public ListenableFuture<Void> apply(final DOMStoreThreePhaseCommitCohort cohort) {
ListenableFuture<Void> preCommitFuture = cohort.preCommit();
- Future<Object> abortFuture = Patterns.ask(shard,
- new AbortTransaction(transactionID).toSerializable(), timeout);
- abortFuture.onComplete(new OnComplete<Object>() {
- @Override
- public void onComplete(final Throwable e, final Object resp) {
- abortComplete.countDown();
- }
- }, getSystem().dispatcher());
+ // Simulate an AbortTransaction message occurring during replication, after
+ // persisting and before finishing the commit to the in-memory store.
+ // We have no followers so due to optimizations in the RaftActor, it does not
+ // attempt replication and thus we can't send an AbortTransaction message b/c
+ // it would be processed too late after CommitTransaction completes. So we'll
+ // simulate an AbortTransaction message occurring during replication by calling
+ // the shard directly.
+ //
+ shard.underlyingActor().doAbortTransaction(transactionID, null);
return preCommitFuture;
}
expectMsgClass(duration, CanCommitTransactionReply.SERIALIZABLE_CLASS));
assertEquals("Can commit", true, canCommitReply.getCanCommit());
- Future<Object> commitFuture = Patterns.ask(shard,
- new CommitTransaction(transactionID).toSerializable(), timeout);
-
- assertEquals("Abort complete", true, abortComplete.await(5, TimeUnit.SECONDS));
-
- Await.result(commitFuture, duration);
+ shard.tell(new CommitTransaction(transactionID).toSerializable(), getRef());
+ expectMsgClass(duration, CommitTransactionReply.SERIALIZABLE_CLASS);
NormalizedNode<?, ?> node = readStore(shard, TestModel.TEST_PATH);
+
+ // Since we're simulating an abort occurring during replication and before finish commit,
+ // the data should still get written to the in-memory store since we've gotten past
+ // canCommit and preCommit and persisted the data.
assertNotNull(TestModel.TEST_QNAME.getLocalName() + " not found", node);
shard.tell(PoisonPill.getInstance(), ActorRef.noSender());
@Test
public void testTransactionCommitTimeout() throws Throwable {
- dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitTimeoutInSeconds(1).build();
+ dataStoreContextBuilder.shardTransactionCommitTimeoutInSeconds(1);
new ShardTestKit(getSystem()) {{
final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
@Test
public void testTransactionCommitQueueCapacityExceeded() throws Throwable {
- dataStoreContext = DatastoreContext.newBuilder().shardTransactionCommitQueueCapacity(1).build();
+ dataStoreContextBuilder.shardTransactionCommitQueueCapacity(1);
new ShardTestKit(getSystem()) {{
final TestActorRef<Shard> shard = TestActorRef.create(getSystem(),
// Wait for the 2nd Tx to complete the canCommit phase.
- final CountDownLatch latch = new CountDownLatch(1);
- canCommitFuture.onComplete(new OnComplete<Object>() {
- @Override
- public void onComplete(final Throwable t, final Object resp) {
- latch.countDown();
- }
- }, getSystem().dispatcher());
-
- assertEquals("2nd CanCommit complete", true, latch.await(5, TimeUnit.SECONDS));
+ Await.ready(canCommitFuture, duration);
InOrder inOrder = inOrder(cohort1, cohort2);
inOrder.verify(cohort1).canCommit();
@Override
public Shard create() throws Exception {
return new Shard(shardID, Collections.<ShardIdentifier,String>emptyMap(),
- dataStoreContext, SCHEMA_CONTEXT) {
+ newDatastoreContext(), SCHEMA_CONTEXT) {
@Override
protected void commitSnapshot(final long sequenceNumber) {
super.commitSnapshot(sequenceNumber);
public void setGlobalSchema(final SchemaContext globalSchema) {
this.globalSchema = globalSchema;
- this.dataNormalizer = new DataNormalizer(globalSchema);
+ dataNormalizer = new DataNormalizer(globalSchema);
}
public void setMountService(final DOMMountPointService mountService) {
}
public void setSchemas(final SchemaContext schemas) {
- this.onGlobalContextUpdated(schemas);
+ onGlobalContextUpdated(schemas);
}
public InstanceIdentifierContext toInstanceIdentifier(final String restconfInstance) {
- return this.toIdentifier(restconfInstance, false);
+ return toIdentifier(restconfInstance, false);
}
public SchemaContext getGlobalSchema() {
}
public InstanceIdentifierContext toMountPointIdentifier(final String restconfInstance) {
- return this.toIdentifier(restconfInstance, true);
+ return toIdentifier(restconfInstance, true);
}
private InstanceIdentifierContext toIdentifier(final String restconfInstance, final boolean toMountPointIdentifier) {
- this.checkPreconditions();
+ checkPreconditions();
final List<String> pathArgs = urlPathArgsDecode(SLASH_SPLITTER.split(restconfInstance));
omitFirstAndLastEmptyString(pathArgs);
return null;
}
- String first = pathArgs.iterator().next();
+ final String first = pathArgs.iterator().next();
final String startModule = ControllerContext.toModuleName(first);
if (startModule == null) {
throw new RestconfDocumentedException("First node in URI has to be in format \"moduleName:nodeName\"",
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
- InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder();
- Module latestModule = globalSchema.findModuleByName(startModule, null);
- InstanceIdentifierContext iiWithSchemaNode = this.collectPathArguments(builder, pathArgs, latestModule, null,
+ final InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder();
+ final Module latestModule = globalSchema.findModuleByName(startModule, null);
+ final InstanceIdentifierContext iiWithSchemaNode = collectPathArguments(builder, pathArgs, latestModule, null,
toMountPointIdentifier);
if (iiWithSchemaNode == null) {
return list;
}
- String head = list.iterator().next();
+ final String head = list.iterator().next();
if (head.isEmpty()) {
list.remove(0);
}
return list;
}
- String last = list.get(list.size() - 1);
+ final String last = list.get(list.size() - 1);
if (last.isEmpty()) {
list.remove(list.size() - 1);
}
return list;
}
public Module findModuleByName(final String moduleName) {
- this.checkPreconditions();
+ checkPreconditions();
Preconditions.checkArgument(moduleName != null && !moduleName.isEmpty());
return globalSchema.findModuleByName(moduleName, null);
}
}
public Module findModuleByNamespace(final URI namespace) {
- this.checkPreconditions();
+ checkPreconditions();
Preconditions.checkArgument(namespace != null);
return globalSchema.findModuleByNamespaceAndRevision(namespace, null);
}
}
public Module findModuleByNameAndRevision(final QName module) {
- this.checkPreconditions();
+ checkPreconditions();
Preconditions.checkArgument(module != null && module.getLocalName() != null && module.getRevision() != null);
return globalSchema.findModuleByName(module.getLocalName(), module.getRevision());
}
public Module findModuleByNameAndRevision(final DOMMountPoint mountPoint, final QName module) {
- this.checkPreconditions();
+ checkPreconditions();
Preconditions.checkArgument(module != null && module.getLocalName() != null && module.getRevision() != null
&& mountPoint != null);
- SchemaContext schemaContext = mountPoint.getSchemaContext();
+ final SchemaContext schemaContext = mountPoint.getSchemaContext();
return schemaContext == null ? null : schemaContext.findModuleByName(module.getLocalName(),
module.getRevision());
}
public DataNodeContainer getDataNodeContainerFor(final YangInstanceIdentifier path) {
- this.checkPreconditions();
+ checkPreconditions();
final Iterable<PathArgument> elements = path.getPathArguments();
- PathArgument head = elements.iterator().next();
+ final PathArgument head = elements.iterator().next();
final QName startQName = head.getNodeType();
final Module initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.getNamespace(),
startQName.getRevision());
DataNodeContainer node = initialModule;
for (final PathArgument element : elements) {
- QName _nodeType = element.getNodeType();
+ final QName _nodeType = element.getNodeType();
final DataSchemaNode potentialNode = ControllerContext.childByQName(node, _nodeType);
if (potentialNode == null || !ControllerContext.isListOrContainer(potentialNode)) {
return null;
}
public String toFullRestconfIdentifier(final YangInstanceIdentifier path) {
- this.checkPreconditions();
+ checkPreconditions();
final Iterable<PathArgument> elements = path.getPathArguments();
final StringBuilder builder = new StringBuilder();
- PathArgument head = elements.iterator().next();
+ final PathArgument head = elements.iterator().next();
final QName startQName = head.getNodeType();
final Module initialModule = globalSchema.findModuleByNamespaceAndRevision(startQName.getNamespace(),
startQName.getRevision());
DataNodeContainer node = initialModule;
for (final PathArgument element : elements) {
- QName _nodeType = element.getNodeType();
+ final QName _nodeType = element.getNodeType();
final DataSchemaNode potentialNode = ControllerContext.childByQName(node, _nodeType);
if (!ControllerContext.isListOrContainer(potentialNode)) {
return null;
}
public String findModuleNameByNamespace(final URI namespace) {
- this.checkPreconditions();
+ checkPreconditions();
final Module module = this.findModuleByNamespace(namespace);
return module == null ? null : module.getName();
}
public Set<Module> getAllModules(final DOMMountPoint mountPoint) {
- this.checkPreconditions();
+ checkPreconditions();
- SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext();
+ final SchemaContext schemaContext = mountPoint == null ? null : mountPoint.getSchemaContext();
return schemaContext == null ? null : schemaContext.getModules();
}
public Set<Module> getAllModules() {
- this.checkPreconditions();
+ checkPreconditions();
return globalSchema.getModules();
}
}
public CharSequence toRestconfIdentifier(final QName qname) {
- this.checkPreconditions();
+ checkPreconditions();
return toRestconfIdentifier(globalSchema, qname);
}
};
public DataSchemaNode getRestconfModuleErrorsSchemaNode() {
- Module restconfModule = getRestconfModule();
+ final Module restconfModule = getRestconfModule();
if (restconfModule == null) {
return null;
}
- Set<GroupingDefinition> groupings = restconfModule.getGroupings();
+ final Set<GroupingDefinition> groupings = restconfModule.getGroupings();
- Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, ERRORS_GROUPING_FILTER);
+ final Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, ERRORS_GROUPING_FILTER);
final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
- List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
+ final List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
Draft02.RestConfModule.ERRORS_CONTAINER_SCHEMA_NODE);
return Iterables.getFirst(instanceDataChildrenByName, null);
}
return null;
}
- Set<GroupingDefinition> groupings = restconfModule.getGroupings();
- Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, GROUPING_FILTER);
+ final Set<GroupingDefinition> groupings = restconfModule.getGroupings();
+ final Iterable<GroupingDefinition> filteredGroups = Iterables.filter(groupings, GROUPING_FILTER);
final GroupingDefinition restconfGrouping = Iterables.getFirst(filteredGroups, null);
- List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
+ final List<DataSchemaNode> instanceDataChildrenByName = findInstanceDataChildrenByName(restconfGrouping,
Draft02.RestConfModule.RESTCONF_CONTAINER_SCHEMA_NODE);
final DataSchemaNode restconfContainer = Iterables.getFirst(instanceDataChildrenByName, null);
if (Objects.equal(schemaNodeName, Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
((DataNodeContainer) restconfContainer), Draft02.RestConfModule.OPERATIONS_CONTAINER_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
} else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
((DataNodeContainer) restconfContainer), Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
} else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE)) {
Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
} else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
((DataNodeContainer) restconfContainer), Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
} else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE)) {
Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
} else if (Objects.equal(schemaNodeName, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE)) {
- List<DataSchemaNode> instances = findInstanceDataChildrenByName(
+ final List<DataSchemaNode> instances = findInstanceDataChildrenByName(
((DataNodeContainer) restconfContainer), Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
return Iterables.getFirst(instances, null);
}
}
private static DataSchemaNode dataNodeChildByQName(final DataNodeContainer container, final QName name) {
- DataSchemaNode ret = container.getDataChildByName(name);
+ final DataSchemaNode ret = container.getDataChildByName(name);
if (ret == null) {
for (final DataSchemaNode node : container.getChildNodes()) {
if ((node instanceof ChoiceNode)) {
final ChoiceNode choiceNode = ((ChoiceNode) node);
- DataSchemaNode childByQName = ControllerContext.childByQName(choiceNode, name);
+ final DataSchemaNode childByQName = ControllerContext.childByQName(choiceNode, name);
if (childByQName != null) {
return childByQName;
}
return new InstanceIdentifierContext(builder.toInstance(), ((DataSchemaNode) parentNode), mountPoint,mountPoint != null ? mountPoint.getSchemaContext() : globalSchema);
}
- String head = strings.iterator().next();
+ final String head = strings.iterator().next();
final String nodeName = toNodeName(head);
final String moduleName = ControllerContext.toModuleName(head);
throw new RestconfDocumentedException("Mount point does not exist.", ErrorType.PROTOCOL,
ErrorTag.UNKNOWN_ELEMENT);
}
- DOMMountPoint mount = mountOpt.get();
+ final DOMMountPoint mount = mountOpt.get();
final SchemaContext mountPointSchema = mount.getSchemaContext();
if (mountPointSchema == null) {
}
if (returnJustMountPoint) {
- YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
+ final YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
return new InstanceIdentifierContext(instance, mountPointSchema, mount,mountPointSchema);
}
if (strings.size() == 1) {
- YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
+ final YangInstanceIdentifier instance = YangInstanceIdentifier.builder().toInstance();
return new InstanceIdentifierContext(instance, mountPointSchema, mount,mountPointSchema);
}
+ "\" module does not exist in mount point.", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
- List<String> subList = strings.subList(1, strings.size());
- return this.collectPathArguments(YangInstanceIdentifier.builder(), subList, moduleBehindMountPoint, mount,
+ final List<String> subList = strings.subList(1, strings.size());
+ return collectPathArguments(YangInstanceIdentifier.builder(), subList, moduleBehindMountPoint, mount,
returnJustMountPoint);
}
Module module = null;
if (mountPoint == null) {
+ checkPreconditions();
module = globalSchema.findModuleByName(moduleName, null);
if (module == null) {
throw new RestconfDocumentedException("\"" + moduleName + "\" module does not exist.",
ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT);
}
} else {
- SchemaContext schemaContext = mountPoint.getSchemaContext();
+ final SchemaContext schemaContext = mountPoint.getSchemaContext();
if (schemaContext != null) {
module = schemaContext.findModuleByName(moduleName, null);
} else {
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
- this.addKeyValue(keyValues, listNode.getDataChildByName(key), uriKeyValue, mountPoint);
+ addKeyValue(keyValues, listNode.getDataChildByName(key), uriKeyValue, mountPoint);
i++;
}
}
if ((targetNode instanceof DataNodeContainer)) {
final List<String> remaining = strings.subList(consumed, strings.size());
- return this.collectPathArguments(builder, remaining, ((DataNodeContainer) targetNode), mountPoint,
+ return collectPathArguments(builder, remaining, ((DataNodeContainer) targetNode), mountPoint,
returnJustMountPoint);
}
final List<DataSchemaNode> potentialSchemaNodes = findInstanceDataChildrenByName(container, name);
- Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+ final Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
@Override
public boolean apply(final DataSchemaNode node) {
return Objects.equal(node.getQName().getNamespace(), namespace);
}
};
- Iterable<DataSchemaNode> result = Iterables.filter(potentialSchemaNodes, filter);
+ final Iterable<DataSchemaNode> result = Iterables.filter(potentialSchemaNodes, filter);
return Iterables.getFirst(result, null);
}
Preconditions.<DataNodeContainer> checkNotNull(container);
Preconditions.<String> checkNotNull(name);
- List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<DataSchemaNode>();
+ final List<DataSchemaNode> instantiatedDataNodeContainers = new ArrayList<DataSchemaNode>();
collectInstanceDataNodeContainers(instantiatedDataNodeContainers, container, name);
return instantiatedDataNodeContainers;
}
private static void collectInstanceDataNodeContainers(final List<DataSchemaNode> potentialSchemaNodes,
final DataNodeContainer container, final String name) {
- Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
+ final Predicate<DataSchemaNode> filter = new Predicate<DataSchemaNode>() {
@Override
public boolean apply(final DataSchemaNode node) {
return Objects.equal(node.getQName().getLocalName(), name);
}
};
- Iterable<DataSchemaNode> nodes = Iterables.filter(container.getChildNodes(), filter);
+ final Iterable<DataSchemaNode> nodes = Iterables.filter(container.getChildNodes(), filter);
// Can't combine this loop with the filter above because the filter is
// lazily-applied by Iterables.filter.
}
}
- Iterable<ChoiceNode> choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceNode.class);
- Iterable<Set<ChoiceCaseNode>> map = Iterables.transform(choiceNodes, CHOICE_FUNCTION);
+ final Iterable<ChoiceNode> choiceNodes = Iterables.filter(container.getChildNodes(), ChoiceNode.class);
+ final Iterable<Set<ChoiceCaseNode>> map = Iterables.transform(choiceNodes, CHOICE_FUNCTION);
final Iterable<ChoiceCaseNode> allCases = Iterables.<ChoiceCaseNode> concat(map);
for (final ChoiceCaseNode caze : allCases) {
final String urlDecoded = urlPathArgDecode(uriValue);
final TypeDefinition<? extends Object> typedef = ((LeafSchemaNode) node).getType();
- Codec<Object, Object> codec = RestCodec.from(typedef, mountPoint);
+ final Codec<Object, Object> codec = RestCodec.from(typedef, mountPoint);
Object decoded = codec == null ? null : codec.deserialize(urlDecoded);
String additionalInfo = "";
if (decoded == null) {
- TypeDefinition<? extends Object> baseType = RestUtil.resolveBaseTypeFrom(typedef);
+ final TypeDefinition<? extends Object> baseType = RestUtil.resolveBaseTypeFrom(typedef);
if ((baseType instanceof IdentityrefTypeDefinition)) {
- decoded = this.toQName(urlDecoded);
+ decoded = toQName(urlDecoded);
additionalInfo = "For key which is of type identityref it should be in format module_name:identity_name.";
}
}
}
private QName toQName(final String name) {
+ checkPreconditions();
final String module = toModuleName(name);
final String node = toNodeName(name);
final Module m = globalSchema.findModuleByName(module, null);
}
public RpcDefinition getRpcDefinition(final String name) {
- final QName validName = this.toQName(name);
- return validName == null ? null : this.qnameToRpc.get().get(validName);
+ final QName validName = toQName(name);
+ return validName == null ? null : qnameToRpc.get().get(validName);
}
@Override
}
// FIXME: still not completely atomic
- this.qnameToRpc.set(ImmutableMap.copyOf(newMap));
- this.setGlobalSchema(context);
+ qnameToRpc.set(ImmutableMap.copyOf(newMap));
+ setGlobalSchema(context);
}
}
public static List<String> urlPathArgsDecode(final Iterable<String> strings) {
try {
- List<String> decodedPathArgs = new ArrayList<String>();
+ final List<String> decodedPathArgs = new ArrayList<String>();
for (final String pathArg : strings) {
- String _decode = URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET);
+ final String _decode = URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET);
decodedPathArgs.add(_decode);
}
return decodedPathArgs;
- } catch (UnsupportedEncodingException e) {
+ } catch (final UnsupportedEncodingException e) {
throw new RestconfDocumentedException("Invalid URL path '" + strings + "': " + e.getMessage(),
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
if (pathArg != null) {
try {
return URLDecoder.decode(pathArg, URI_ENCODING_CHAR_SET);
- } catch (UnsupportedEncodingException e) {
+ } catch (final UnsupportedEncodingException e) {
throw new RestconfDocumentedException("Invalid URL path arg '" + pathArg + "': " + e.getMessage(),
ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
private CharSequence convertToRestconfIdentifier(final NodeIdentifierWithPredicates argument,
final ListSchemaNode node) {
- QName nodeType = argument.getNodeType();
+ final QName nodeType = argument.getNodeType();
final CharSequence nodeIdentifier = this.toRestconfIdentifier(nodeType);
final Map<QName, Object> keyValues = argument.getKeyValues();
- StringBuilder builder = new StringBuilder();
+ final StringBuilder builder = new StringBuilder();
builder.append('/');
builder.append(nodeIdentifier);
builder.append('/');
- List<QName> keyDefinition = node.getKeyDefinition();
+ final List<QName> keyDefinition = node.getKeyDefinition();
boolean hasElements = false;
for (final QName key : keyDefinition) {
if (!hasElements) {
}
try {
- builder.append(this.toUriString(keyValues.get(key)));
- } catch (UnsupportedEncodingException e) {
+ builder.append(toUriString(keyValues.get(key)));
+ } catch (final UnsupportedEncodingException e) {
LOG.error("Error parsing URI: {}", keyValues.get(key), e);
return null;
}
final CompositeNode compositeNode) {
try {
return dataNormalizer.toNormalized(legacy, compositeNode);
- } catch (NullPointerException e) {
+ } catch (final NullPointerException e) {
throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e);
}
}
public YangInstanceIdentifier toNormalized(final YangInstanceIdentifier legacy) {
try {
return dataNormalizer.toNormalized(legacy);
- } catch (NullPointerException e) {
+ } catch (final NullPointerException e) {
throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e);
}
}
final NormalizedNode<?,?> normalizedNode) {
try {
return dataNormalizer.toLegacy(instanceIdentifier, normalizedNode);
- } catch (NullPointerException e) {
+ } catch (final NullPointerException e) {
throw new RestconfDocumentedException("Data normalizer isn't set. Normalization isn't possible", e);
}
}
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>com.google.common.collect,
- org.opendaylight.yangtools.yang.binding,
- org.opendaylight.yangtools.yang.common,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,</Import-Package>
<Export-Package>org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,</Export-Package>
</instructions>
</configuration>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>com.google.common.collect,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
- org.opendaylight.yangtools.yang.binding,
- org.opendaylight.yangtools.yang.common,</Import-Package>
<Export-Package>org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.*</Export-Package>
</instructions>
</configuration>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Private-Package></Private-Package>
<Export-Package>org.opendaylight.controller.netconf.api,
org.opendaylight.controller.netconf.api.jmx,
org.opendaylight.controller.netconf.api.xml,
<configuration>
<instructions>
<Export-Package>org.opendaylight.controller.netconf.client.*,</Export-Package>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- io.netty.channel,
- io.netty.channel.socket,
- io.netty.util,
- io.netty.util.concurrent,
- javax.annotation,
- javax.net.ssl,
- javax.xml.namespace,
- javax.xml.parsers,
- javax.xml.xpath,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.util.*,
- org.opendaylight.controller.netconf.nettyutil.*,
- org.opendaylight.protocol.framework,
- org.openexi.*,
- org.slf4j,
- org.w3c.dom,
- org.xml.sax,
- io.netty.handler.codec</Import-Package>
</instructions>
</configuration>
</plugin>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.impl.osgi.NetconfImplActivator</Bundle-Activator>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- io.netty.channel,
- io.netty.channel.socket,
- io.netty.util,
- io.netty.util.concurrent,
- io.netty.buffer,
- io.netty.handler.codec,
- io.netty.channel.nio,
- io.netty.channel.local,
- javax.annotation,
- javax.management,
- javax.net.ssl,
- javax.xml.namespace,
- javax.xml.xpath,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.api.jmx,
- org.opendaylight.controller.netconf.mapping.api,
- org.opendaylight.controller.netconf.util.*,
- org.opendaylight.protocol.framework,
- org.osgi.framework,
- org.osgi.util.tracker,
- org.slf4j,
- org.w3c.dom,
- org.xml.sax,
- io.netty.util.internal,
- org.opendaylight.controller.netconf.api.monitoring,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
- org.opendaylight.yangtools.yang.binding,
- org.openexi.*,
- org.opendaylight.controller.netconf.nettyutil.*</Import-Package>
</instructions>
</configuration>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Private-Package></Private-Package>
- <Import-Package>com.google.common.base,
- org.opendaylight.controller.netconf.api,
- org.w3c.dom</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.mapping.api,</Export-Package>
</instructions>
</configuration>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringActivator</Bundle-Activator>
- <Import-Package>com.google.common.base,
- com.google.common.collect,
- com.google.common.io,
- org.opendaylight.controller.netconf.api,
- org.opendaylight.controller.netconf.mapping.api,
- org.opendaylight.controller.netconf.util.mapping,
- org.opendaylight.controller.netconf.util.exception,
- org.osgi.framework,
- org.slf4j,
- org.w3c.dom,
- javax.xml.bind,
- javax.xml.bind.annotation,
- javax.xml.transform,
- javax.xml.transform.dom,
- org.opendaylight.controller.netconf.util.xml,
- io.netty.util.internal,
- javax.annotation,
- org.opendaylight.controller.netconf.api.monitoring,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924,
- org.osgi.util.tracker,
- org.opendaylight.yangtools.yang.common,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.sessions,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.rev101004.netconf.state.schemas,
- org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210,
- org.opendaylight.yangtools.yang.binding,</Import-Package>
</instructions>
</configuration>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>*</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.nettyutil,
org.opendaylight.controller.netconf.nettyutil.handler,
org.opendaylight.controller.netconf.nettyutil.handler.exi,
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator</Bundle-Activator>
- <Import-Package>*</Import-Package>
</instructions>
</configuration>
</plugin>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.tcp.osgi.NetconfTCPActivator</Bundle-Activator>
- <Import-Package>com.google.common.base, io.netty.bootstrap, io.netty.channel, io.netty.channel.local,
- io.netty.channel.nio, io.netty.channel.socket, io.netty.channel.socket.nio, io.netty.handler.logging,
- io.netty.util.concurrent, org.opendaylight.controller.netconf.util.osgi, org.osgi.framework, org.slf4j</Import-Package>
</instructions>
</configuration>
</plugin>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>com.google.common.base, com.google.common.collect, io.netty.channel,
- io.netty.util.concurrent, javax.annotation, javax.xml.namespace, javax.xml.parsers, javax.xml.transform,
- javax.xml.transform.dom, javax.xml.transform.stream, javax.xml.validation, javax.xml.xpath,
- org.opendaylight.controller.netconf.api, org.opendaylight.controller.netconf.api.xml,
- org.opendaylight.controller.netconf.mapping.api,
- org.osgi.framework, org.slf4j, org.w3c.dom, org.xml.sax,io.netty.channel.local</Import-Package>
<Export-Package>org.opendaylight.controller.netconf.util.*</Export-Package>
</instructions>
</configuration>