From c961bd752be1fb2eee707cb5c7c44d1bda0894d2 Mon Sep 17 00:00:00 2001 From: Jan Srnicek Date: Thu, 25 Aug 2016 16:27:23 +0200 Subject: HONEYCOMB-140 - Honeycomb Plugin Archetype Change-Id: I6e04fb769e82fb539dbd6a79bb465974796137a4 Signed-off-by: Jan Srnicek --- tools/archetype/Readme.adoc | 13 +++ tools/archetype/pom.xml | 17 +++ .../META-INF/maven/archetype-metadata.xml | 53 +++++++++ .../__rootArtifactId__-api/pom.xml | 62 +++++++++++ .../src/main/yang/__rootArtifactId__.yang | 49 +++++++++ .../__rootArtifactId__-impl/Readme.adoc | 3 + .../__rootArtifactId__-impl/pom.xml | 75 +++++++++++++ .../src/main/java/CrudService.java | 64 +++++++++++ .../src/main/java/ElementCrudService.java | 121 +++++++++++++++++++++ .../src/main/java/Module.java | 81 ++++++++++++++ .../src/main/java/ModuleConfiguration.java | 46 ++++++++ .../src/main/java/init/ConfigDataInitializer.java | 58 ++++++++++ .../src/main/java/read/ElementStateCustomizer.java | 93 ++++++++++++++++ .../main/java/read/ModuleStateReaderFactory.java | 71 ++++++++++++ .../src/main/java/write/ElementCustomizer.java | 69 ++++++++++++ .../src/main/java/write/ModuleWriterFactory.java | 61 +++++++++++ .../config/__rootArtifactId__.json | 3 + .../src/main/resources/archetype-resources/pom.xml | 57 ++++++++++ tools/pom.xml | 20 ++++ 19 files changed, 1016 insertions(+) create mode 100644 tools/archetype/Readme.adoc create mode 100644 tools/archetype/pom.xml create mode 100644 tools/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/src/main/yang/__rootArtifactId__.yang create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/Readme.adoc create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/CrudService.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ElementCrudService.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/Module.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ModuleConfiguration.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/init/ConfigDataInitializer.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ElementStateCustomizer.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ModuleStateReaderFactory.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ElementCustomizer.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ModuleWriterFactory.java create mode 100644 tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/resources/honeycomb-minimal-resources/config/__rootArtifactId__.json create mode 100644 tools/archetype/src/main/resources/archetype-resources/pom.xml create mode 100644 tools/pom.xml (limited to 'tools') diff --git a/tools/archetype/Readme.adoc b/tools/archetype/Readme.adoc new file mode 100644 index 000000000..24040b89a --- /dev/null +++ b/tools/archetype/Readme.adoc @@ -0,0 +1,13 @@ +Honeycomb Plugin Archetype + + This is archetype for creating plugins for Honeycomb platform + +How to use it : + + archetype:generate -DarchetypeGroupId=io.fd.honeycomb.tools -DarchetypeArtifactId=honeycomb-plugin-archetype -DarchetypeVersion=1.0.0-SNAPSHOT + +This will generate main aggregator project containing two sub-projects + + -api - project that should contain yang model files for restconf/netconf DTO classes + -impl - implementation project that should contain plugin translation code + wiring + diff --git a/tools/archetype/pom.xml b/tools/archetype/pom.xml new file mode 100644 index 000000000..e49e031c9 --- /dev/null +++ b/tools/archetype/pom.xml @@ -0,0 +1,17 @@ + + + + honeycomb-tools + io.fd.honeycomb.tools + 1.0.0-SNAPSHOT + + 4.0.0 + + io.fd.honeycomb.tools + honeycomb-plugin-archetype + 1.0.0-SNAPSHOT + jar + + \ No newline at end of file diff --git a/tools/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml b/tools/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml new file mode 100644 index 000000000..c35327187 --- /dev/null +++ b/tools/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml @@ -0,0 +1,53 @@ + + + + + 1.0.0-SNAPSHOT + + + + + + + + src/main/java + + **/*.java + + + + src/main/yang + + **/*.yang + + + + + + + + + + **/*.adoc + + + + src/main/java + + **/*.java + + + + src/test/java + + **/*.java + + + + + + \ No newline at end of file diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml new file mode 100644 index 000000000..a88775d8a --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/pom.xml @@ -0,0 +1,62 @@ + + + + io.fd.honeycomb.common + api-parent + 1.0.0-SNAPSHOT + + + 4.0.0 + ${groupId} + ${rootArtifactId}-api + ${version} + bundle + + + + + org.opendaylight.mdsal.model + mdsal-model-artifacts + 0.8.2-Beryllium-SR2 + pom + import + + + + + + + org.opendaylight.mdsal.model + iana-if-type-2014-05-08 + + + org.opendaylight.mdsal.model + ietf-yang-types-20130715 + + + org.opendaylight.mdsal.model + ietf-interfaces + + + org.opendaylight.mdsal.model + ietf-inet-types-2013-07-15 + + + org.opendaylight.mdsal.model + yang-ext + + + diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/src/main/yang/__rootArtifactId__.yang b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/src/main/yang/__rootArtifactId__.yang new file mode 100644 index 000000000..d5852ebeb --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-api/src/main/yang/__rootArtifactId__.yang @@ -0,0 +1,49 @@ +module ${rootArtifactId} { + + yang-version 1; + namespace "urn:opendaylight:params:xml:ns:yang:${rootArtifactId}"; + prefix "${rootArtifactId}"; + + description + "This YANG module defines the generic configuration and + operational data for ${rootArtifactId} in VPP"; + + revision "2016-09-18" { + description "Initial revision of ${rootArtifactId} model"; + } + + container ${rootArtifactId} { + uses ${rootArtifactId}-params; + description "Configuration data of ${rootArtifactId} in Honeycomb"; + + // READ + // curl -u admin:admin http://localhost:8181/restconf/config/${rootArtifactId}:${rootArtifactId} + + // WRITE + // curl http://localhost:8181/restconf/operational/${rootArtifactId}:${rootArtifactId} + + } + + container ${rootArtifactId}-state { + config false; + uses ${rootArtifactId}-params; + description "Operational data of ${rootArtifactId} persisted in VPP"; + + // READ + // curl -u admin:admin http://localhost:8181/restconf/operational/${rootArtifactId}:${rootArtifactId}-state + } + + grouping ${rootArtifactId}-params { + list element { + + key id; + leaf id { + type uint32; + } + + leaf description { + type string; + } + } + } +} \ No newline at end of file diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/Readme.adoc b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/Readme.adoc new file mode 100644 index 000000000..8b4288e55 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/Readme.adoc @@ -0,0 +1,3 @@ +--Documentation for ${rootArtifactId} -- + +TODO Replace with general description whats the purpose of ${rootArtifactId} and how it works diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml new file mode 100644 index 000000000..faaba62a8 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/pom.xml @@ -0,0 +1,75 @@ + + + + io.fd.honeycomb.common + impl-parent + 1.0.0-SNAPSHOT + + + 4.0.0 + ${groupId} + ${rootArtifactId}-impl + ${version} + bundle + + + 1.0.0-SNAPSHOT + + + + + ${project.groupId} + ${rootArtifactId}-api + ${project.version} + + + + + io.fd.honeycomb + translate-api + ${honeycomb.infra.version} + + + + io.fd.honeycomb + translate-spi + ${honeycomb.infra.version} + + + + io.fd.honeycomb + cfg-init + ${honeycomb.infra.version} + + + + + com.google.inject + guice + ${guice.version} + + + net.jmob + guice.conf + ${guice.config.version} + + + com.google.inject.extensions + guice-multibindings + ${guice.version} + + + diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/CrudService.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/CrudService.java new file mode 100644 index 000000000..f5b6614d1 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/CrudService.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +package ${package}; + +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Example of an aggregated access interface. + *

+ * Shared by all the customizers hiding the ugly details of our data management. + * + * TODO update javadoc + */ +public interface CrudService { + + /** + * Perform write of provided data. + */ + void writeData(@Nonnull final InstanceIdentifier identifier, @Nonnull final T data) + throws WriteFailedException; + + + /** + * Perform delete of existing data. + */ + void deleteData(@Nonnull final InstanceIdentifier identifier, @Nonnull final T data) + throws WriteFailedException; + + /** + * Perform update of existing data. + */ + void updateData(@Nonnull final InstanceIdentifier identifier, @Nonnull final T dataOld, + @Nonnull final T dataNew) + throws WriteFailedException; + + /** + * Read data identified by provided identifier. + */ + T readSpecific(@Nonnull final InstanceIdentifier identifier) throws ReadFailedException; + + /** + * Read all nodes of type {@link T}. + */ + List readAll() throws ReadFailedException; +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ElementCrudService.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ElementCrudService.java new file mode 100644 index 000000000..33f9ad9dc --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ElementCrudService.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( ccase $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.substring(0,1).toUpperCase()$word.substring(1)#end +#end +#set( $classNamePrefix = "#ccase( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}; + +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}State; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.ElementBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.ElementKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Simple example of class handling Crud operations for plugin. + *

+ * No real handling, serves just as an illustration. + * + * TODO update javadoc + */ +final class ElementCrudService implements CrudService { + + private static final Logger LOG = LoggerFactory.getLogger(ElementCrudService.class); + + @Override + public void writeData(@Nonnull final InstanceIdentifier identifier, @Nonnull final Element data) + throws WriteFailedException { + if (data != null) { + + // identifier.firstKeyOf(SomeClassUpperInHierarchy.class) can be used to identify + // relationships such as to which parent these data are related to + + // Performs any logic needed for persisting such data + LOG.info("Writing path[{}] / data [{}]", identifier, data); + } else { + throw new WriteFailedException.CreateFailedException(identifier, data, + new NullPointerException("Provided data are null")); + } + } + + @Override + public void deleteData(@Nonnull final InstanceIdentifier identifier, @Nonnull final Element data) + throws WriteFailedException { + if (data != null) { + + // identifier.firstKeyOf(SomeClassUpperInHierarchy.class) can be used to identify + // relationships such as to which parent these data are related to + + // Performs any logic needed for persisting such data + LOG.info("Removing path[{}] / data [{}]", identifier, data); + } else { + throw new WriteFailedException.DeleteFailedException(identifier, + new NullPointerException("Provided data are null")); + } + } + + @Override + public void updateData(@Nonnull final InstanceIdentifier identifier, @Nonnull final Element dataOld, + @Nonnull final Element dataNew) throws WriteFailedException { + if (dataOld != null && dataNew != null) { + + // identifier.firstKeyOf(SomeClassUpperInHierarchy.class) can be used to identify + // relationships such as to which parent these data are related to + + // Performs any logic needed for persisting such data + LOG.info("Update path[{}] from [{}] to [{}]", identifier, dataOld, dataNew); + } else { + throw new WriteFailedException.DeleteFailedException(identifier, + new NullPointerException("Provided data are null")); + } + } + + @Override + public Element readSpecific(@Nonnull final InstanceIdentifier identifier) throws ReadFailedException { + + // read key specified in path identifier + final ElementKey key = identifier.firstKeyOf(Element.class); + + // load data by this key + // *Key class will always contain key of entity, in this case long value + + return new ElementBuilder() + .setId(key.getId()) + .setKey(key) + .setDescription("This is a example of loaded data") + .build(); + } + + @Override + public List readAll() throws ReadFailedException { + // read all data under parent node,in this case {@link ModuleState} + return Collections.singletonList( + readSpecific(InstanceIdentifier.create(${classNamePrefix}State.class).child(Element.class, new ElementKey(10L)))); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/Module.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/Module.java new file mode 100644 index 000000000..41373cedc --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/Module.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}; + +import static ${package}.ModuleConfiguration.ELEMENT_SERVICE_NAME; + +import com.google.inject.AbstractModule; +import com.google.inject.TypeLiteral; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; +import ${package}.init.ConfigDataInitializer; +import ${package}.read.ModuleStateReaderFactory; +import ${package}.write.ModuleWriterFactory; +import io.fd.honeycomb.data.init.DataTreeInitializer; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import net.jmob.guice.conf.core.ConfigurationModule; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; + +/** + * Module class instantiating ${rootArtifactId} plugin components. + */ +public final class Module extends AbstractModule { + + // TODO This initiates all the plugin components, but it still needs to be registered/wired into an integration + // module producing runnable distributions. There is one such distribution in honeycomb project: + // vpp-integration/minimal-distribution + // In order to integrate this plugin with the distribution: + // 1. Add a dependency on this maven module to the the distribution's pom.xml + // 2. Add an instance of this module into the distribution in its Main class + + @Override + protected void configure() { + // requests injection of properties + install(ConfigurationModule.create()); + requestInjection(ModuleConfiguration.class); + + // creates binding for interface implementation by name + bind(new TypeLiteral>(){}) + .annotatedWith(Names.named(ELEMENT_SERVICE_NAME)) + .to(ElementCrudService.class); + + // creates reader factory binding + // can hold multiple binding for separate yang modules + final Multibinder readerFactoryBinder = Multibinder.newSetBinder(binder(), ReaderFactory.class); + readerFactoryBinder.addBinding().to(ModuleStateReaderFactory.class); + + // create writer factory binding + // can hold multiple binding for separate yang modules + final Multibinder writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(ModuleWriterFactory.class); + + // create initializer binding + // can hold multiple binding for separate yang modules + final Multibinder initializerBinder = + Multibinder.newSetBinder(binder(), DataTreeInitializer.class); + initializerBinder.addBinding().to(ConfigDataInitializer.class); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ModuleConfiguration.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ModuleConfiguration.java new file mode 100644 index 000000000..52a317b3b --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/ModuleConfiguration.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +package ${package}; + +import net.jmob.guice.conf.core.BindConfig; +import net.jmob.guice.conf.core.InjectConfig; +import net.jmob.guice.conf.core.Syntax; + +/** + * Class containing static configuration for ${rootArtifactId} module,
+ * either loaded from property file ${rootArtifactId}.json from classpath. + *

+ * Further documentation for the configuration injection can be found at: + * https://github.com/yyvess/gconf + */ +@BindConfig(value = "${rootArtifactId}", syntax = Syntax.JSON) +public final class ModuleConfiguration { + + // TODO change the sample property to real plugin configuration + // If there is no such configuration, remove this, ${rootArtifactId}.json resource and its wiring from Module class + + /** + * Sample property that's injected from external json configuration file. + */ + @InjectConfig("sample-prop") + public String sampleProp; + + /** + * Constant name used to identify ${rootArtifactId} plugin specific components during dependency injection. + */ + public static final String ELEMENT_SERVICE_NAME = "element-service"; +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/init/ConfigDataInitializer.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/init/ConfigDataInitializer.java new file mode 100644 index 000000000..2393a125a --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/init/ConfigDataInitializer.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( ccase $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.substring(0,1).toUpperCase()$word.substring(1)#end +#end +#set( $classNamePrefix = "#ccase( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}.init; + +import io.fd.honeycomb.data.init.AbstractDataTreeConverter; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import javax.annotation.Nonnull; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}Builder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}State; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Initialize configuration data based on operational data. + *

+ * Very useful when a plugin is initiated but the underlying layer already contains some operation state. + * Deriving the configuration from existing operational state enables reconciliation in case when Honeycomb's persistence + * is not available to do the work for us. + */ +public final class ConfigDataInitializer extends AbstractDataTreeConverter<${classNamePrefix}State, ${classNamePrefix}> { + + @Inject + public ConfigDataInitializer(@Named("honeycomb-initializer") @Nonnull final DataBroker bindingDataBroker) { + super(bindingDataBroker, InstanceIdentifier.create(${classNamePrefix}State.class), InstanceIdentifier.create(${classNamePrefix}.class)); + } + + @Override + public ${classNamePrefix} convert(final ${classNamePrefix}State operationalData) { + // Transfer all the operational data into configuration + return new ${classNamePrefix}Builder() + .setElement(operationalData.getElement()) + .build(); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ElementStateCustomizer.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ElementStateCustomizer.java new file mode 100644 index 000000000..8f1c3a79d --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ElementStateCustomizer.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( ccase $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.substring(0,1).toUpperCase()$word.substring(1)#end +#end +#set( $classNamePrefix = "#ccase( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}.read; + +import ${package}.CrudService; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}StateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.ElementBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.ElementKey; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Reader for {@link Element} list node from our YANG model. + */ +public final class ElementStateCustomizer implements + ListReaderCustomizer { + + private final CrudService crudService; + + public ElementStateCustomizer(final CrudService crudService) { + this.crudService = crudService; + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) + throws ReadFailedException { + // perform read operation and extract keys from data + return crudService.readAll() + .stream() + .map(a -> new ElementKey(a.getId())) + .collect(Collectors.toList()); + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + // merge children data to parent builder + // used by infrastructure to merge data loaded in separated customizers + ((${classNamePrefix}StateBuilder) builder).setElement(readData); + } + + @Nonnull + @Override + public ElementBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + // return new builder for this data node + return new ElementBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final ElementBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + // this stage is used after reading all ids by getAllIds,to read specific details about data + + // perform read of details of data specified by key of Element in id + final Element data = crudService.readSpecific(id); + + // and sets it to builder + builder.setId(data.getId()); + builder.setKey(data.getKey()); + builder.setDescription(data.getDescription()); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ModuleStateReaderFactory.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ModuleStateReaderFactory.java new file mode 100644 index 000000000..9df03aed2 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/read/ModuleStateReaderFactory.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( ccase $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.substring(0,1).toUpperCase()$word.substring(1)#end +#end +#set( $classNamePrefix = "#ccase( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}.read; + +import static ${package}.ModuleConfiguration.ELEMENT_SERVICE_NAME; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import ${package}.CrudService; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}State; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}StateBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Factory producing readers for ${rootArtifactId} plugin's data. + */ +public final class ModuleStateReaderFactory implements ReaderFactory { + + public static final InstanceIdentifier<${classNamePrefix}State> ROOT_STATE_CONTAINER_ID = + InstanceIdentifier.create(${classNamePrefix}State.class); + + /** + * Injected crud service to be passed to customizers instantiated in this factory. + */ + @Inject + @Named(ELEMENT_SERVICE_NAME) + private CrudService crudService; + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + + // register reader that only delegate read's to its children + registry.addStructuralReader(ROOT_STATE_CONTAINER_ID, ${classNamePrefix}StateBuilder.class); + + // just adds reader to the structure + // use addAfter/addBefore if you want to add specific order to readers on the same level of tree + // use subtreeAdd if you want to handle multiple nodes in single customizer/subtreeAddAfter/subtreeAddBefore if you also want to add order + // be aware that instance identifier passes to subtreeAdd/subtreeAddAfter/subtreeAddBefore should define subtree, + // therefore it should be relative from handled node down - InstanceIdentifier.create(HandledNode), not parent.child(HandledNode.class) + registry.add( + new GenericListReader<>(ROOT_STATE_CONTAINER_ID.child(Element.class), + new ElementStateCustomizer(crudService))); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ElementCustomizer.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ElementCustomizer.java new file mode 100644 index 000000000..62b0c4271 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ElementCustomizer.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}.write; + +import ${package}.CrudService; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.ElementKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Writer for {@link Element} list node from our YANG model. + */ +public final class ElementCustomizer implements ListWriterCustomizer { + + private final CrudService crudService; + + public ElementCustomizer(@Nonnull final CrudService crudService) { + this.crudService = crudService; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Element dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + //perform write of data,or throw exception + //invoked by PUT operation,if provided data doesn't exist in Config data + crudService.writeData(id, dataAfter); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Element dataBefore, + @Nonnull final Element dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + //perform update of data,or throw exception + //invoked by PUT operation,if provided data does exist in Config data + crudService.updateData(id, dataBefore, dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final Element dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + //perform delete of data,or throw exception + //invoked by DELETE operation + crudService.deleteData(id, dataBefore); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ModuleWriterFactory.java b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ModuleWriterFactory.java new file mode 100644 index 000000000..2f1d0a90e --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/java/write/ModuleWriterFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed 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. + */ + +#macro( ccase $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.substring(0,1).toUpperCase()$word.substring(1)#end +#end +#set( $classNamePrefix = "#ccase( $rootArtifactId )" ) +#macro( dotted $str ) +#foreach( $word in $rootArtifactId.split('-') )$word.#end +#end +#set( $packageName = "#dotted( $rootArtifactId )" ) +package ${package}.write; + +import static ${package}.ModuleConfiguration.ELEMENT_SERVICE_NAME; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import ${package}.CrudService; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${classNamePrefix}; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.${packageName}rev160918.${packageName}params.Element; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Factory producing writers for ${rootArtifactId} plugin's data. + */ +public final class ModuleWriterFactory implements WriterFactory { + + private static final InstanceIdentifier<${classNamePrefix}> ROOT_CONTAINER_ID = InstanceIdentifier.create(${classNamePrefix}.class); + + /** + * Injected crud service to be passed to customizers instantiated in this factory. + */ + @Inject + @Named(ELEMENT_SERVICE_NAME) + private CrudService crudService; + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + + //adds writer for child node + //no need to add writers for empty nodes + registry.add(new GenericWriter<>(ROOT_CONTAINER_ID.child(Element.class), new ElementCustomizer(crudService))); + } +} diff --git a/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/resources/honeycomb-minimal-resources/config/__rootArtifactId__.json b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/resources/honeycomb-minimal-resources/config/__rootArtifactId__.json new file mode 100644 index 000000000..7ee89c674 --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/__rootArtifactId__-impl/src/main/resources/honeycomb-minimal-resources/config/__rootArtifactId__.json @@ -0,0 +1,3 @@ +{ + "sample-prop": "sample-value" +} \ No newline at end of file diff --git a/tools/archetype/src/main/resources/archetype-resources/pom.xml b/tools/archetype/src/main/resources/archetype-resources/pom.xml new file mode 100644 index 000000000..5445d6e7f --- /dev/null +++ b/tools/archetype/src/main/resources/archetype-resources/pom.xml @@ -0,0 +1,57 @@ + + + + + org.opendaylight.odlparent + odlparent + 1.6.2-Beryllium-SR2 + + + ${groupId} + ${rootArtifactId}-aggregator + ${version} + ${rootArtifactId}-aggregator + pom + 4.0.0 + + 3.1.1 + + + + ${rootArtifactId}-api + ${rootArtifactId}-impl + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-install-plugin + + true + + + + + diff --git a/tools/pom.xml b/tools/pom.xml new file mode 100644 index 000000000..972f5e75a --- /dev/null +++ b/tools/pom.xml @@ -0,0 +1,20 @@ + + + + honeycomb-aggregator + io.fd.honeycomb + 1.0.0-SNAPSHOT + + 4.0.0 + + io.fd.honeycomb.tools + honeycomb-tools + pom + 1.0.0-SNAPSHOT + + archetype + + + \ No newline at end of file -- cgit 1.2.3-korg