diff options
author | Jan Srnicek <jsrnicek@cisco.com> | 2016-08-25 16:27:23 +0200 |
---|---|---|
committer | Maros Marsalek <mmarsale@cisco.com> | 2016-08-30 15:43:49 +0000 |
commit | c961bd752be1fb2eee707cb5c7c44d1bda0894d2 (patch) | |
tree | 780c4f0c9e796f3a8aa4f9116ee83f396de74ccc | |
parent | 23f210d1477a4dd43d939714a2f3c78fa30d466c (diff) |
HONEYCOMB-140 - Honeycomb Plugin Archetype
Change-Id: I6e04fb769e82fb539dbd6a79bb465974796137a4
Signed-off-by: Jan Srnicek <jsrnicek@cisco.com>
23 files changed, 1022 insertions, 5 deletions
diff --git a/common/api-parent/pom.xml b/common/api-parent/pom.xml index ec7f78dcb..329f4decd 100644 --- a/common/api-parent/pom.xml +++ b/common/api-parent/pom.xml @@ -88,7 +88,8 @@ <dependency> <groupId>io.fd.honeycomb.common</groupId> <artifactId>honeycomb-checkstyle</artifactId> - <version>${project.version}</version> + <!-- Hardcoded version to prevent archetype generated projects to use their own project version --> + <version>1.0.0-SNAPSHOT</version> </dependency> <!-- Necessary for logging checks --> <dependency> diff --git a/common/impl-parent/pom.xml b/common/impl-parent/pom.xml index 4cce01f8b..ee5bf7cbd 100644 --- a/common/impl-parent/pom.xml +++ b/common/impl-parent/pom.xml @@ -93,7 +93,8 @@ <dependency> <groupId>io.fd.honeycomb.common</groupId> <artifactId>honeycomb-checkstyle</artifactId> - <version>${project.version}</version> + <!-- Hardcoded version to prevent archetype generated projects to use their own project version --> + <version>1.0.0-SNAPSHOT</version> </dependency> <!-- Necessary for logging checks --> <dependency> @@ -39,6 +39,7 @@ <module>vpp-integration</module> <module>lisp</module> <module>samples</module> + <module>tools</module> </modules> <distributionManagement> diff --git a/samples/interfaces/mapping/pom.xml b/samples/interfaces/mapping/pom.xml index d5f6b07ad..eb1000235 100644 --- a/samples/interfaces/mapping/pom.xml +++ b/samples/interfaces/mapping/pom.xml @@ -16,7 +16,7 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>io.fd.honeycomb.common</groupId> - <artifactId>api-parent</artifactId> + <artifactId>impl-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../../../common/api-parent</relativePath> </parent> @@ -28,8 +28,6 @@ <packaging>bundle</packaging> <properties> - <guice.version>4.1.0</guice.version> - <guice.config.version>1.2.0</guice.config.version> <honeycomb.infra.version>1.0.0-SNAPSHOT</honeycomb.infra.version> </properties> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>honeycomb-tools</artifactId> + <groupId>io.fd.honeycomb.tools</groupId> + <version>1.0.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <groupId>io.fd.honeycomb.tools</groupId> + <artifactId>honeycomb-plugin-archetype</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>jar</packaging> + +</project>
\ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archetype-descriptor + xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd" + name="honeycomb-archetype" + xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <requiredProperties> + <requiredProperty key="version"> + <defaultValue>1.0.0-SNAPSHOT</defaultValue> + </requiredProperty> + </requiredProperties> + + <modules> + <module id="${rootArtifactId}-api" dir="__rootArtifactId__-api" name="${rootArtifactId}-api"> + <fileSets> + <fileSet filtered="true" encoding="UTF-8"> + <directory>src/main/java</directory> + <includes> + <include>**/*.java</include> + </includes> + </fileSet> + <fileSet filtered="true" encoding="UTF-8"> + <directory>src/main/yang</directory> + <includes> + <include>**/*.yang</include> + </includes> + </fileSet> + </fileSets> + </module> + <module id="${rootArtifactId}-impl" dir="__rootArtifactId__-impl" name="${rootArtifactId}-impl"> + <fileSets> + <fileSet filtered="true" encoding="UTF-8"> + <directory></directory> + <includes> + <include>**/*.adoc</include> + </includes> + </fileSet> + <fileSet filtered="true" packaged="true" encoding="UTF-8"> + <directory>src/main/java</directory> + <includes> + <include>**/*.java</include> + </includes> + </fileSet> + <fileSet filtered="true" encoding="UTF-8"> + <directory>src/test/java</directory> + <includes> + <include>**/*.java</include> + </includes> + </fileSet> + </fileSets> + </module> + </modules> +</archetype-descriptor>
\ 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 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. +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>api-parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>${groupId}</groupId> + <artifactId>${rootArtifactId}-api</artifactId> + <version>${version}</version> + <packaging>bundle</packaging> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>mdsal-model-artifacts</artifactId> + <version>0.8.2-Beryllium-SR2</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>iana-if-type-2014-05-08</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-yang-types-20130715</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-interfaces</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-inet-types-2013-07-15</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>yang-ext</artifactId> + </dependency> + </dependencies> +</project> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 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. +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>io.fd.honeycomb.common</groupId> + <artifactId>impl-parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + <groupId>${groupId}</groupId> + <artifactId>${rootArtifactId}-impl</artifactId> + <version>${version}</version> + <packaging>bundle</packaging> + + <properties> + <honeycomb.infra.version>1.0.0-SNAPSHOT</honeycomb.infra.version> + </properties> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>${rootArtifactId}-api</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- Honeycomb infrastructure--> + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-api</artifactId> + <version>${honeycomb.infra.version}</version> + </dependency> + + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>translate-spi</artifactId> + <version>${honeycomb.infra.version}</version> + </dependency> + + <dependency> + <groupId>io.fd.honeycomb</groupId> + <artifactId>cfg-init</artifactId> + <version>${honeycomb.infra.version}</version> + </dependency> + + <!-- DI --> + <dependency> + <groupId>com.google.inject</groupId> + <artifactId>guice</artifactId> + <version>${guice.version}</version> + </dependency> + <dependency> + <groupId>net.jmob</groupId> + <artifactId>guice.conf</artifactId> + <version>${guice.config.version}</version> + </dependency> + <dependency> + <groupId>com.google.inject.extensions</groupId> + <artifactId>guice-multibindings</artifactId> + <version>${guice.version}</version> + </dependency> + </dependencies> +</project> 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. + * <p/> + * Shared by all the customizers hiding the ugly details of our data management. + * + * TODO update javadoc + */ +public interface CrudService<T extends DataObject> { + + /** + * Perform write of provided data. + */ + void writeData(@Nonnull final InstanceIdentifier<T> identifier, @Nonnull final T data) + throws WriteFailedException; + + + /** + * Perform delete of existing data. + */ + void deleteData(@Nonnull final InstanceIdentifier<T> identifier, @Nonnull final T data) + throws WriteFailedException; + + /** + * Perform update of existing data. + */ + void updateData(@Nonnull final InstanceIdentifier<T> identifier, @Nonnull final T dataOld, + @Nonnull final T dataNew) + throws WriteFailedException; + + /** + * Read data identified by provided identifier. + */ + T readSpecific(@Nonnull final InstanceIdentifier<T> identifier) throws ReadFailedException; + + /** + * Read all nodes of type {@link T}. + */ + List<T> 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. + * <p/> + * No real handling, serves just as an illustration. + * + * TODO update javadoc + */ +final class ElementCrudService implements CrudService<Element> { + + private static final Logger LOG = LoggerFactory.getLogger(ElementCrudService.class); + + @Override + public void writeData(@Nonnull final InstanceIdentifier<Element> 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<Element> 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<Element> 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<Element> 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<Element> 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<CrudService<Element>>(){}) + .annotatedWith(Names.named(ELEMENT_SERVICE_NAME)) + .to(ElementCrudService.class); + + // creates reader factory binding + // can hold multiple binding for separate yang modules + final Multibinder<ReaderFactory> 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<WriterFactory> writerFactoryBinder = Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryBinder.addBinding().to(ModuleWriterFactory.class); + + // create initializer binding + // can hold multiple binding for separate yang modules + final Multibinder<DataTreeInitializer> 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,<br> + * either loaded from property file ${rootArtifactId}.json from classpath. + * <p/> + * 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. + * <p/> + * 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<Element, ElementKey, ElementBuilder> { + + private final CrudService<Element> crudService; + + public ElementStateCustomizer(final CrudService<Element> crudService) { + this.crudService = crudService; + } + + @Nonnull + @Override + public List<ElementKey> getAllIds(@Nonnull final InstanceIdentifier<Element> 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<? extends DataObject> builder, @Nonnull final List<Element> 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<Element> id) { + // return new builder for this data node + return new ElementBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier<Element> 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<Element> 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<Element, ElementKey> { + + private final CrudService<Element> crudService; + + public ElementCustomizer(@Nonnull final CrudService<Element> crudService) { + this.crudService = crudService; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Element> 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<Element> 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<Element> 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<Element> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (c) 2015 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. +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <parent> + <groupId>org.opendaylight.odlparent</groupId> + <artifactId>odlparent</artifactId> + <version>1.6.2-Beryllium-SR2</version> + </parent> + + <groupId>${groupId}</groupId> + <artifactId>${rootArtifactId}-aggregator</artifactId> + <version>${version}</version> + <name>${rootArtifactId}-aggregator</name> + <packaging>pom</packaging> + <modelVersion>4.0.0</modelVersion> + <prerequisites> + <maven>3.1.1</maven> + </prerequisites> + + <modules> + <module>${rootArtifactId}-api</module> + <module>${rootArtifactId}-impl</module> + </modules> + + <!-- DO NOT install or deploy the repo root pom as it's only needed to initiate a build --> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> +</project> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>honeycomb-aggregator</artifactId> + <groupId>io.fd.honeycomb</groupId> + <version>1.0.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <groupId>io.fd.honeycomb.tools</groupId> + <artifactId>honeycomb-tools</artifactId> + <packaging>pom</packaging> + <version>1.0.0-SNAPSHOT</version> + <modules> + <module>archetype</module> + </modules> + +</project>
\ No newline at end of file |