DMAAP-83 Initial code import 63/9763/1
authorATT default cloud user <dgl@research.att.com>
Thu, 31 Aug 2017 21:01:21 +0000 (21:01 +0000)
committerATT default cloud user <dgl@research.att.com>
Thu, 31 Aug 2017 21:09:25 +0000 (21:09 +0000)
Change-Id: Ic059aaadde5ea30d98e5968457a5a8ca2db703bf
Signed-off-by: ATT default cloud user <dgl@research.att.com>
91 files changed:
LICENSE.txt [new file with mode: 0644]
README.md [new file with mode: 0644]
pom.xml [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/AafDecrypt.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/AafObject.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/ClearDecrypt.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/DecryptionInterface.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapGrant.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapPerm.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPermissionInterface.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPerms.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPolicy.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/AuthenticationErrorException.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/client/DrProvConnection.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrProvConnection.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrTopicConnection.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnWrapper.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnectionFactory.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBException.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBFieldHandler.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBMap.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBSingleton.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/DatabaseClass.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/LoadSchema.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/aaf/database/TableHandler.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/logging/BaseLoggingClass.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/logging/DmaapbcLogMessageEnum.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/logging/logmsg.properties [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/BrTopic.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/DR_Pub.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/DcaeLocation.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/Dmaap.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/Feed.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/MR_Cluster.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/MirrorMaker.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/ReplicationType.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/ReplicationVector.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/model/Topic.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/Authorization.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/BridgeResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/DcaeLocationResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/server/Main.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DcaeLocationService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/DmaapService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/MR_ClusterService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/MirrorMakerService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/DmaapConfig.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/DmaapTimestamp.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/Graph.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/RandomInteger.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/RandomString.java [new file with mode: 0644]
src/main/java/org/onap/dmaap/dbcapi/util/Singleton.java [new file with mode: 0644]
src/main/resources/log4j.properties [new file with mode: 0644]
src/main/resources/schema_0.sql [new file with mode: 0644]
src/main/resources/schema_1.sql [new file with mode: 0644]
src/main/resources/schema_2.sql [new file with mode: 0644]
src/main/resources/schema_3.sql [new file with mode: 0644]
src/main/resources/schema_4.sql [new file with mode: 0644]
src/main/resources/schema_5.sql [new file with mode: 0644]
src/main/resources/schema_6.sql [new file with mode: 0644]
src/main/resources/schema_7.sql [new file with mode: 0644]
src/main/webapp/HelloJetty.html [new file with mode: 0644]
src/main/webapp/WEB-INF/log4j.xml [new file with mode: 0644]
src/main/webapp/WEB-INF/web.xml [new file with mode: 0644]
src/main/webapp/index.jsp [new file with mode: 0644]

diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644 (file)
index 0000000..b6c623b
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.dmaap
+ * ===================================================================
+ * Copyright Â© 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * 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.
+ * ============LICENSE_END============================================
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ *
+ */
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..d96612c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,187 @@
+DMaaP Bus Controller API
+=======================
+
+Data Movement as a Platform (DMaaP) Bus Controller provides an API for other ONAP infrastructure components to provision DMaaP resources.
+A typical DMaaP resource is a Data Router Feed or a Message Router Topic, and their associated publishers and subscribers.
+Other infrastucture resources such as DR Nodes and MR Clusters are also provisioned through this API.
+
+### Build Instructions for a Continuous Integration environment using Jenkins
+
+When this component is included in a Continuous Integration environment, such as structured by the Linux Foundation, the artifacts can be created and deployed via Jenkins.  The following maven targets are currently supported in the Build step:
+```
+clean install
+javadoc:javadoc
+sonar:sonar
+```
+
+### Build Instructions for external developers
+
+This project is organized as a mvn project for a jar package.
+After cloning from this git repo:
+
+```
+mvn clean install javadoc:javadoc
+```
+
+### Configurable Parameters
+
+Behavior of the API is controlled by settings in a properties file (typically etc/dmaapbc.properties).
+The following describes these properties:
+
+```
+
+#
+#      Configuration parameters fixed at startup for the DMaaP Bus Controller
+#
+#
+#      URI to retrieve dynamic DR configuration
+#
+ProvisioningURI:       /internal/prov
+#
+#      Allow http access to API 
+#
+HttpAllowed:   true
+#
+#      The port number for http as seen within the server
+#
+IntHttpPort:   8080
+#
+#      The port number for https as seen within the server
+#   Set to 0 if no certificate is available yet...
+#
+IntHttpsPort:  8443
+#
+#      The external port number for https taking port mapping into account
+#
+ExtHttpsPort:  443
+#
+#      The type of keystore for https
+#
+KeyStoreType:  jks
+#
+#      The path to the keystore for https
+#
+KeyStoreFile:  etc/keystore
+#
+#      The password for the https keystore
+#
+KeyStorePassword:      changeit
+#
+#      The password for the private key in the https keystore
+#
+KeyPassword:   changeit
+#
+#      The type of truststore for https
+#
+TrustStoreType:        jks
+#
+#      The path to the truststore for https
+#
+TrustStoreFile:        /opt/app/java/jdk/jdk180/jre/security/cacerts
+#
+#      The password for the https truststore
+#
+TrustStorePassword:    changeit
+#
+#      The path to the file used to trigger an orderly shutdown
+#
+QuiesceFile:   etc/SHUTDOWN
+#
+#      Enable postgress
+#
+UsePGSQL:      true
+#
+#      The host for postgres access
+#
+DB.host:       HostNotSet
+#
+#      For postgres access
+#
+DB.cred:       ValueNotSet
+#
+#      Name of this environment
+#
+DmaapName:     DeploymentEnvName
+#
+#      Name of DR prov server
+#
+DR.provhost:   dcae-drps.domain.notset.com
+#
+#      The Role and credentials of the MirrorMaker Provisioner.  This is used by DMaaP Bus Controller to pub to the provisioning topic
+#   Not part of 1701
+#
+#MM.ProvRole: org.openecomp.dmaapBC.MMprov.prov
+#MM.ProvUserMechId: idNotSet@namespaceNotSet
+#MM.ProvUserPwd: enc:fMxh-hzYZldbtyXumQq9aJU08SslhbM6mXtt
+#
+#      The Role of the MirrorMaker Agent. This is used by MM to sub to provisioning topic
+#
+MM.AgentRole: org.openecomp.dmaapBC.MMagent.agent
+#################
+# AAF Properties:
+#
+# regarding password encryption:
+# In the dependencies that Maven retrieves (e.g., under dcae_dmaapbc/target/deps/ is a jar file cadi-core-version.jar.  Generate the key file with:
+#
+# java \u2013jar wherever/cadi-core-*.jar keygen keyfilename
+# chmod 400 keyfilename
+#
+# To encrypt a key:
+#
+# java \u2013jar wherever/cadi-core-*.jar digest password-to-encrypt keyfilename
+#
+# This will generate a string.  Put \u201Cenc:\u201D on the front of the string, and put the result in this properties file.
+#
+# Location of the Codec Keyfile which is used to decrypt passwords in this properties file before they are passed to AAF
+#
+# REF: https://wiki.domain.notset.com/display/cadi/CADI+Deployment
+#
+CredentialCodecKeyfile:        etc/LocalKey
+#
+# URL of AAF environment to use.
+#
+aaf.URL:       https://authentication.simpledemo.openecomp.org:8095/proxy/
+#
+# TopicMgr mechid@namespace
+#
+aaf.TopicMgrUser:      idNotSet@namespaceNotSet
+#
+# TopicMgr password
+# 
+aaf.TopicMgrPassword:  enc:zyRL9zbI0py3rJAjMS0dFOnYfEw_mJhO
+#
+# Bus Controller Namespace Admin  mechid@namespace
+#
+aaf.AdminUser: idNotSet@namespaceNotSet
+#
+# Bus Controller Namespace Admin password
+#
+aaf.AdminPassword:     enc:YEaHwOJrwhDY8a6usetlhbB9mEjUq9m
+#
+# endof AAF Properties
+#################
+#################
+# PolicyEngine Properties
+#
+# Flag to turn on/off Authentication
+UsePE: false
+#
+# Argument to decisionAttributes.put("AAF_ENVIRONMENT", X); 
+# where X is:  TEST= UAT, PROD = PROD, DEVL = TEST
+#
+PeAafEnvironment: DEVL
+#
+# Name of PolicyEngineApi properties file
+PolicyEngineProperties: config/PolicyEngineApi.properties
+#
+# Namespace for URI values for API used to create AAF permissions
+# e.g. if ApiNamespace is X.Y..dmaapBC.api then for URI /topics we create an AAF perm X.Y..dmaapBC.api.topics
+ApiNamespace: org.onap.dmaap.dbcapi
+#
+# endof PolicyEngineProperties
+#################
+
+```
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..7807e70
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,334 @@
+<?xml version="1.0"?>
+<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/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.onap.dmaap.dbcapi</groupId>
+  <artifactId>dbcapi</artifactId>
+  <version>${artifact.version}</version>
+  <name>dbcapi</name>
+  <distributionManagement>
+    <repository>
+      <id>ecomp-releases</id>
+      <name>Open eCOMP Release Repository</name>
+      <url>${nexusproxy}/${releases.path}</url>
+    </repository>
+    <snapshotRepository>
+      <id>ecomp-snapshots</id>
+      <name>Open eCOMP Snapshot Repository</name>
+       <url>${nexusproxy}/${snapshots.path}</url>
+    </snapshotRepository>
+    <site>
+      <id>ecomp-site</id>
+      <url>dav:${nexusproxy}/content/sites/site/org/onap/dmaap/dbcapi/${project.artifactId}/${project.version}/</url>
+    </site>
+  </distributionManagement>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>central</id>
+      <url>http://repo1.maven.org/maven2</url>
+    </pluginRepository>
+  </pluginRepositories>
+  <build>
+    <finalName>dbcapi</finalName>
+    <resources>
+               <resource>
+                       <directory>src/main/java/org/onap/dmaap/dbcapi/logging</directory>
+               </resource>
+               <resource>
+                       <directory>src/main/resources</directory>
+               </resource>
+       </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.5.1</version>
+        <inherited>true</inherited>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <version>2.8</version> <!-- This version supports the "deployAtEnd" parameter -->
+        <configuration>
+          <skip/>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-site-plugin</artifactId>
+        <version>3.6</version>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-webdav-jackrabbit</artifactId>
+            <version>2.10</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/deps</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- blackduck maven plugin -->
+      <!--plugin>
+        <groupId>com.blackducksoftware.integration</groupId>
+        <artifactId>hub-maven-plugin</artifactId>
+        <version>1.0.4</version>
+        <inherited>false</inherited>
+        <configuration>
+          <target>${project.basedir}</target>
+        </configuration>
+        <executions>
+          <execution>
+            <id>create-bdio-file</id>
+            <phase>package</phase>
+            <goals>
+              <goal>createHubOutput</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin-->
+
+      <plugin>
+        <groupId>org.sonatype.plugins</groupId>
+        <artifactId>nexus-staging-maven-plugin</artifactId>
+        <version>1.6.7</version>
+        <extensions>true</extensions>
+        <configuration>
+          <serverId>ecomp-staging</serverId>
+          <nexusUrl>${nexusproxy}</nexusUrl>
+          <stagingProfileId>176c31dfe190a</stagingProfileId>
+        </configuration>
+      </plugin>
+<!--  reference: https://tech.homeaway.com/development/2016/06/02/generating-swagger-spec.html 
+       <plugin>
+    <groupId>com.github.kongchen</groupId>
+    <artifactId>swagger-maven-plugin</artifactId>
+    <version>3.1.5</version>
+    <configuration>
+        <apiSources>
+            <apiSource>
+                <springmvc>false</springmvc>
+                <locations>
+                       <location>org.onap.dmaap.dbcapi.resources</location>
+                </locations>
+                <schemes>
+                   <scheme>http</scheme>
+                  <scheme>https</scheme>
+                </schemes>
+                <host>www.[host]:[port]</host>
+                <basePath>/webapi</basePath>
+                <info>
+                    <title>DMaaP Bus Controller REST API</title>
+                    <version>1.1.0</version>
+                    <description>
+provides an API for OpenDCAE components which need to provision underlying DMaaP technologies (Data Router and Message Router). Primary clients for this API are anticipated to be the OpenDCAE Controller, OpenDCAE Orchestrator, OpenDCAE Inventory and the ECOMP Portal.
+
+Objects managed by DMaaP are deployed in a dcaeLocation which is a unique identifier for an OpenStack tenant for a dcaeLayer, opendcae-central (aka ecomp) or opendcae-local-ntc (aka edge).
+
+A dcaeEnvironment (e.g. FTL or prod) has a single DMaaP. A DMaaP is managed by a one or more stateless DMaaP Bus Controller(s), though Bus Controller relies on PGaaS for persistence. Each DMaaP has a single instance of Data Router, which has 1 or more DR_Nodes deployed at each dcaeLocation. DR Clients of type DR_Pub generally publish to a DR_Node that is local to its dcaeLocation. Routing for a Feed is determined by the dcaelocation of its DR_Sub clients.
+
+A DMaaP may have many Message Router instances. Each instance is deployed as an MR_Cluster. One MR_Cluster is deployed at each dcaeLocation. MR_Clients generally communicate to the MR_Cluster at the same dcaeLocation. Replication of messages between MR_Clusters is accomplished by MR Bridge, which is provioned by DMaaP Bus Controller based on Topic attributes.
+
+Therefore, the role of DMaaP Bus Controller is to support other DCAE infrastructure components to dynamically provision DMaaP services on behalf of DMaaP clients, and to assist in any management or discovery activity of its clients.
+
+A convention of this API is to return JSON responses per OpenStack style.
+                    </description>
+                    <termsOfService>
+                        http://www.apache.org/licenses/LICENSE-2.0
+                    </termsOfService>
+                    <contact>
+                        <url>http://www.onap.org</url>
+                    </contact>
+                    <license>
+                        <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+                        <name>Licensed under the Apache License, Version 2.0</name>
+                    </license>
+                </info>
+                <swaggerDirectory>target/generated-sources/</swaggerDirectory>
+            </apiSource>
+        </apiSources>
+    </configuration>
+    <executions>
+        <execution>
+            <phase>compile</phase>
+            <goals>
+                <goal>generate</goal>
+            </goals>
+        </execution>
+    </executions>
+  </plugin>
+-->
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <versionRange>[2.10,)</versionRange>
+                    <goals>
+                      <goal>copy-dependencies</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore/>
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.glassfish.jersey</groupId>
+        <artifactId>jersey-bom</artifactId>
+        <version>${jersey.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+        <dependency>
+        <groupId>io.swagger</groupId>
+        <artifactId>swagger-core</artifactId>
+        <version>1.5.13</version>
+      </dependency>
+      <dependency>
+        <groupId>io.swagger</groupId>
+        <artifactId>swagger-jersey2-jaxrs</artifactId>
+        <version>1.5.13</version>
+      </dependency>
+       <dependency>
+        <groupId>io.swagger</groupId>
+        <artifactId>swagger-annotations</artifactId>
+        <version>1.5.13</version>
+      </dependency>   
+    <dependency>
+      <groupId>org.glassfish.jersey.containers</groupId>
+      <artifactId>jersey-container-servlet-core</artifactId>
+      <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
+      <!-- artifactId>jersey-container-servlet</artifactId -->
+    </dependency>
+    <dependency>
+      <groupId>org.glassfish.jersey.media</groupId>
+      <artifactId>jersey-media-moxy</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.17</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${jettyVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlet</artifactId>
+      <version>${jettyVersion}</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-servlets</artifactId>
+      <version>${jettyVersion}</version>
+      <scope>compile</scope>
+    </dependency>
+    <!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
+    <dependency>
+      <groupId>com.googlecode.json-simple</groupId>
+      <artifactId>json-simple</artifactId>
+      <version>1.1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.6</version>
+    </dependency>
+    <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
+    <dependency>
+      <groupId>org.postgresql</groupId>
+      <artifactId>postgresql</artifactId>
+      <version>9.4.1208.jre7</version>
+    </dependency>
+    <dependency>
+       <groupId>com.att.eelf</groupId> 
+       <artifactId>eelf-core</artifactId> 
+       <version>${eelf.version}</version> 
+    </dependency>
+    <dependency>
+       <groupId>org.slf4j</groupId> 
+       <artifactId>slf4j-api</artifactId> 
+       <version>1.7.22</version> 
+    </dependency>
+  </dependencies>
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.10.4</version>
+        <configuration>
+          <failOnError>false</failOnError>
+          <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>
+          <docletArtifact>
+            <groupId>org.umlgraph</groupId>
+            <artifactId>umlgraph</artifactId>
+            <version>5.6</version>
+          </docletArtifact>
+          <additionalparam>-views</additionalparam>
+          <useStandardDocletOptions>true</useStandardDocletOptions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+  <properties>
+    <jersey.version>2.16</jersey.version>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <jettyVersion>9.3.7.v20160115</jettyVersion>
+    <eelf.version>0.0.1</eelf.version>
+    <artifact.version>1.0.0-SNAPSHOT</artifact.version>
+    <nexusproxy>https://nexus.onap.org</nexusproxy>
+    <snapshots.path>content/repositories/snapshots/</snapshots.path>
+    <releases.path>content/repositories/releases/</releases.path>
+  </properties>
+  <description>Data Movement as a Platform (DMaaP) Bus Controller provides a REST API for other DCAE infrastructure components to provision DMaaP resources.  A DMaaP resource is a Data Router Feed or a Message Router Topic, and their associated publishers and subscribers.</description>
+</project>
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafConnection.java
new file mode 100644 (file)
index 0000000..b7c02dd
--- /dev/null
@@ -0,0 +1,271 @@
+/*-
+ * ============LICENSE_START=======================================================
+  * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+
+
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.service.DmaapService;
+
+
+public class AafConnection extends BaseLoggingClass {
+
+
+          
+   
+
+       private String aafCred;
+
+       
+       private HttpsURLConnection uc;
+
+
+       public AafConnection( String cred ) {
+               aafCred = cred;
+       }
+       
+
+       private boolean makeConnection( String pURL ) {
+       
+               try {
+                       URL u = new URL( pURL );
+                       uc = (HttpsURLConnection) u.openConnection();
+                       uc.setInstanceFollowRedirects(false);
+                       logger.info( "successful connect to " + pURL );
+                       return(true);
+               } catch (Exception e) {
+               errorLogger.error(DmaapbcLogMessageEnum.HTTP_CONNECTION_ERROR,  pURL, e.getMessage() );
+            e.printStackTrace();
+            return(false);
+        }
+
+       }
+       
+       static String bodyToString( InputStream is ) {
+               StringBuilder sb = new StringBuilder();
+               BufferedReader br = new BufferedReader( new InputStreamReader(is));
+               String line;
+               try {
+                       while ((line = br.readLine()) != null ) {
+                               sb.append( line );
+                       }
+               } catch (IOException ex ) {
+                       errorLogger.error( DmaapbcLogMessageEnum.IO_EXCEPTION,  ex.getMessage());
+               }
+                       
+               return sb.toString();
+       }
+       
+
+
+       public int postAaf( AafObject obj, String pURL ) {
+               logger.info( "entry: postAaf() to  " + pURL  );
+               String auth =  "Basic " + Base64.encodeBase64String(aafCred.getBytes());
+               int rc = -1;
+
+               
+               if ( ! makeConnection( pURL ) ) {
+                       return rc;
+               };
+               
+
+               byte[] postData = obj.getBytes();
+               //logger.info( "post fields=" + postData );  //byte isn't very readable
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+                       if (auth != null) {
+                               uc.setRequestProperty("Authorization", auth);
+               }
+                       uc.setRequestMethod("POST");
+                       uc.setRequestProperty("Content-Type", "application/json");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            } catch ( SSLHandshakeException she ) {
+                       errorLogger.error( DmaapbcLogMessageEnum.SSL_HANDSHAKE_ERROR, pURL);
+            } 
+                       try {
+                               rc = uc.getResponseCode();
+                       } catch ( SSLHandshakeException she ) {
+                               errorLogger.error( DmaapbcLogMessageEnum.SSL_HANDSHAKE_ERROR, pURL);
+               rc = 500;
+               return rc;
+            }
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if ( rc >= 200 && rc < 300 ) {
+               responseBody = bodyToString( uc.getInputStream() );
+               logger.info( "responseBody=" + responseBody );
+            } else {
+                       logger.warn( "Unsuccessful response: " + responsemessage );
+            } 
+            
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        }
+               finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               //return responseBody;
+       
+               return rc;
+               
+       }
+       
+       public int delAaf(AafObject obj, String pURL) {
+               logger.info( "entry: delAaf() to  " + pURL  );
+               String auth =  "Basic " + Base64.encodeBase64String(aafCred.getBytes());
+               int rc = -1;
+
+               
+               if ( ! makeConnection( pURL ) ) {
+                       return rc;
+               };
+               
+
+               byte[] postData = obj.getBytes();
+               //logger.info( "post fields=" + postData );  //byte isn't very readable
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+                       if (auth != null) {
+                               uc.setRequestProperty("Authorization", auth);
+               }
+                       uc.setRequestMethod("DELETE");
+                       uc.setRequestProperty("Content-Type", "application/json");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            } catch ( SSLHandshakeException she ) {
+               errorLogger.error( DmaapbcLogMessageEnum.SSL_HANDSHAKE_ERROR, pURL);
+            }
+                       try {
+                               rc = uc.getResponseCode();
+                       } catch ( SSLHandshakeException she ) {
+                               errorLogger.error( DmaapbcLogMessageEnum.SSL_HANDSHAKE_ERROR, pURL);
+               rc = 500;
+               return rc;
+            }
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if ( rc >= 200 && rc < 300 ) {
+               responseBody = bodyToString( uc.getInputStream() );
+               logger.info( "responseBody=" + responseBody );
+            } else {
+                       logger.warn( "Unsuccessful response: " + responsemessage );
+            } 
+            
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        }
+               //return responseBody;
+       
+               return rc;
+               
+       }
+       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafDecrypt.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafDecrypt.java
new file mode 100644 (file)
index 0000000..c478752
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.aaf;
+
+import java.io.IOException;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class AafDecrypt extends BaseLoggingClass  {
+       String dClass = null;
+       DecryptionInterface dec = null;
+       
+       public AafDecrypt() {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               dClass = p.getProperty( "AafDecryption.Class", "org.openecomp.dmaapbc.aaf.ClearDecrypt");
+               try {
+                       dec = (DecryptionInterface) (Class.forName(dClass).newInstance());      
+                       dec.init( p.getProperty("CredentialCodecKeyfile", "LocalKey"));
+               } catch (Exception ee ) {
+                       errorLogger.error(DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, "attempting to instantiate " + dClass  );         
+               }       
+       }
+       
+       public String decrypt( String encPwd ) {
+       
+               String pwd = "notDecrypted";
+               try {           
+                       pwd = dec.decrypt( encPwd );
+               } catch( IOException io ) {
+                       errorLogger.error(DmaapbcLogMessageEnum.DECRYPT_IO_ERROR, dClass, encPwd );
+               } 
+               
+               return pwd;
+       
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafObject.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafObject.java
new file mode 100644 (file)
index 0000000..07f171a
--- /dev/null
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import java.nio.charset.StandardCharsets;
+
+public abstract class AafObject {
+
+       abstract String toJSON();
+       
+       public byte[] getBytes() {
+               return toJSON().getBytes(StandardCharsets.UTF_8);
+       }
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/AafService.java
new file mode 100644 (file)
index 0000000..727ec19
--- /dev/null
@@ -0,0 +1,180 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class AafService extends BaseLoggingClass {
+       public enum ServiceType {
+               AAF_Admin,
+               AAF_TopicMgr
+       }
+       
+       private AafConnection aaf;
+       private ServiceType ctype;
+       private String aafURL ;
+       
+       private String getCred( boolean wPwd ) {
+               String mechIdProperty = null;
+               String pwdProperty = null;
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               AafDecrypt decryptor = new AafDecrypt();
+
+               if ( ctype == ServiceType.AAF_Admin ) {
+                        mechIdProperty = "aaf.AdminUser";
+                        pwdProperty = "aaf.AdminPassword";
+               } else if ( ctype == ServiceType.AAF_TopicMgr ){        
+                        mechIdProperty = "aaf.TopicMgrUser";
+                        pwdProperty = "aaf.TopicMgrPassword";
+               } else {
+                       logger.error( "Unexpected case for AAF credential type: " + ctype );
+                       return null;
+               }
+               String user = p.getProperty( mechIdProperty, "noMechId@domain.netset.com" );
+               //String dClass = p.getProperty( "AafDecryption.Class", "org.openecomp.dmaapbc.aaf.ClearDecrypt");
+               String pwd = "";
+               String encPwd = p.getProperty( pwdProperty, "notSet" );
+               //DecryptionInterface dec = null;
+               //try {
+               //      dec = (DecryptionInterface) (Class.forName(dClass).newInstance());      
+               //      dec.init( p.getProperty("CredentialCodecKeyfile", "LocalKey"));
+               //} catch (Exception ee ) {
+               //      errorLogger.error(DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, "attempting to use " + dClass + " to decrypt " + encPwd );                
+               //}     
+               //try {         
+               //      pwd = dec.decrypt( encPwd );
+               //} catch( IOException io ) {
+               //      errorLogger.error(DmaapbcLogMessageEnum.DECRYPT_IO_ERROR, dClass, encPwd );
+               //} 
+               
+               pwd = decryptor.decrypt(encPwd);
+               
+               if ( wPwd ) {
+                       return user + ":" + pwd;
+               } else {
+                       return user;
+               }
+               
+               
+       }
+       
+       public AafService(ServiceType t ) {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               aafURL = p.getProperty( "aaf.URL", "https://authentication.domain.netset.com:8095/proxy/");
+               initAafService( t );
+       }
+       public AafService( ServiceType t, String url ) {
+               aafURL = url;
+               initAafService( t );
+       }
+               
+       private void initAafService( ServiceType t ) {
+               ctype = t;
+               aaf = new AafConnection( getCred( true ) );
+       }
+       
+       public int addPerm(DmaapPerm perm) {
+
+               int rc = -1;
+               logger.info( "entry: addPerm() "  );
+               String pURL = aafURL + "authz/perm";
+               rc = aaf.postAaf( perm, pURL );
+        switch( rc ) {
+       case 401:
+       case 403:
+                       errorLogger.error(DmaapbcLogMessageEnum.AAF_CREDENTIAL_ERROR,  getCred( false ) );
+               System.exit(1);
+       case 409:
+               logger.warn( "Perm already exists. Possible conflict.");
+               break;
+               
+       case 201:
+               logger.info( "expected response" );
+               break;
+               default :
+               logger.error( "Unexpected response: " + rc );
+               break;
+        }
+               
+               return rc;
+       }
+       public int addGrant(DmaapGrant grant ) {
+
+               int rc = -1;
+               logger.info( "entry: addGrant() "  );
+
+               String pURL = aafURL + "authz/role/perm";
+               rc = aaf.postAaf( grant, pURL );
+        switch( rc ) {
+       case 401:
+       case 403:
+                       errorLogger.error(DmaapbcLogMessageEnum.AAF_CREDENTIAL_ERROR,  getCred( false ) );
+               System.exit(1);
+               break;
+
+       case 409:
+               logger.warn( "Perm already exists. Possible conflict.");
+               break;
+               
+       case 201:
+               logger.info( "expected response" );
+               break;
+               default :
+               logger.error( "Unexpected response: " + rc );
+               break;
+        }
+               
+               return rc;
+       }
+
+       public int delGrant( DmaapGrant grant ) {
+               int rc = -1;
+               logger.info( "entry: delGrant() "  );
+
+               String pURL = aafURL + "authz/role/:" + grant.getRole() + "/perm";
+               rc = aaf.delAaf( grant, pURL );
+        switch( rc ) {
+       case 401:
+               case 403:
+               errorLogger.error(DmaapbcLogMessageEnum.AAF_CREDENTIAL_ERROR,  getCred( false ) );
+               System.exit(1);
+               break;
+       case 404:
+               logger.warn( "Perm not found...ignore");
+               break;
+               
+       case 200:
+               logger.info( "expected response" );
+               break;
+               default :
+               logger.error( "Unexpected response: " + rc );
+               break;
+        }
+               
+               return rc;
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/ClearDecrypt.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/ClearDecrypt.java
new file mode 100644 (file)
index 0000000..fe3e3e7
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import java.io.IOException;
+
+public class ClearDecrypt implements DecryptionInterface {
+
+       @Override
+       public String decrypt(String enc) throws IOException {
+               return enc;
+       }
+
+       @Override
+       public String valueOf(String s) {
+               return s;
+       }
+
+       @Override
+       public boolean init(String codecFname) {
+               return false;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/DecryptionInterface.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/DecryptionInterface.java
new file mode 100644 (file)
index 0000000..eda6465
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import java.io.IOException;
+
+public interface DecryptionInterface {
+       public boolean init( String codecFname );
+       public String decrypt(String enc) throws IOException;
+       public String valueOf( String s);
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapGrant.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapGrant.java
new file mode 100644 (file)
index 0000000..90668be
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import org.apache.log4j.Logger;
+
+public class DmaapGrant extends AafObject {
+       static final Logger logger = Logger.getLogger(DmaapGrant.class);
+       
+       private DmaapPerm       perm;
+       private String  role;
+
+       public DmaapGrant(){
+               
+       }
+       
+       public DmaapGrant( DmaapPerm p, String r ) {
+               this.perm = p;
+               this.role = r;
+       }
+
+       public DmaapPerm getPerm() {
+               return perm;
+       }
+
+       public void setPerm(DmaapPerm perm) {
+               this.perm = perm;
+       }
+
+       public String getRole() {
+               return role;
+       }
+
+       public void setRole(String role) {
+               this.role = role;
+       }
+
+       public String toJSON() {
+
+               String postJSON = String.format(" { \"perm\":  %s, \"role\": \"%s\"}", 
+                               this.perm.toJSON(), 
+                               this.getRole() );
+               logger.info( "returning JSON: " + postJSON);
+                       
+               return postJSON;
+       }
+       
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapPerm.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/DmaapPerm.java
new file mode 100644 (file)
index 0000000..1893a71
--- /dev/null
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf;
+
+import org.apache.log4j.Logger;
+
+
+public class DmaapPerm extends AafObject  {
+       static final Logger logger = Logger.getLogger(DmaapPerm.class);
+       
+       private String  permission;
+       private String  ptype;
+       private String  action;
+       
+       public DmaapPerm(String permission, String ptype, String action) {
+               super();
+               this.permission = permission;
+               this.ptype = ptype;
+               this.action = action;
+       }
+       public String getPermission() {
+               return permission;
+       }
+       public void setPermission(String permission) {
+               this.permission = permission;
+       }
+       public String getPtype() {
+               return ptype;
+       }
+       public void setPtype(String ptype) {
+               this.ptype = ptype;
+       }
+       public String getAction() {
+               return action;
+       }
+       public void setAction(String action) {
+               this.action = action;
+       }
+       public String toJSON() {
+
+               String postJSON = String.format(" { \"type\": \"%s\", \"instance\": \"%s\", \"action\": \"%s\"}", 
+                               this.getPermission(), 
+                               this.getPtype(),
+                               this.getAction() );
+               logger.info( "returning JSON: " + postJSON);
+                       
+               return postJSON;
+       }
+       
+       
+       
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPermissionInterface.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPermissionInterface.java
new file mode 100644 (file)
index 0000000..acc5da9
--- /dev/null
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.authentication;
+
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+
+public interface ApiPermissionInterface {
+       public void check( String mechid, String pwd, DmaapPerm p ) throws AuthenticationErrorException;
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPerms.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPerms.java
new file mode 100644 (file)
index 0000000..478b772
--- /dev/null
@@ -0,0 +1,167 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.authentication;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.aaf.AafService;
+import org.onap.dmaap.dbcapi.aaf.DmaapGrant;
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.service.DmaapService;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public  class ApiPerms extends BaseLoggingClass {
+       
+       private static class PermissionMap {
+               static final EELFLogger logger = EELFManager.getInstance().getLogger( PermissionMap.class );
+               static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+               String uri;
+               String action;
+               String[] roles;
+               
+               public String getUri() {
+                       return uri;
+               }
+               public void setUri(String uri) {
+                       this.uri = uri;
+               }
+               public String getAction() {
+                       return action;
+               }
+               public void setAction(String action) {
+                       this.action = action;
+               }
+
+               public String[] getRoles() {
+                       return roles;
+               }
+               public void setRoles(String[] roles) {
+                       this.roles = roles;
+               }
+
+               private PermissionMap( String u, String a, String[] r ) {
+                       this.setUri(u);
+                       this.setAction(a);
+                       this.setRoles(r);
+               }
+               
+               static public void initMap( PermissionMap[] pmap, String instance ) {
+
+                       DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+                       String api = p.getProperty("ApiNamespace", "apiNamespace.not.set");
+                       
+                       // this is needed because PE AAF may be a different instance than AAF used by MR
+                       String peEnv = p.getProperty("PeAafEnvironment", "notSet");
+                       String url = p.getProperty( new String( "PeAafUrl." + peEnv ), "URL.not.set" );
+                       logger.info( "PeAafEnvironment=" + peEnv + " using URL " + url);
+                       AafService aaf = new AafService(ServiceType.AAF_Admin, url );
+                       
+                       for ( int i = 0; i < pmap.length ; i++ ) {
+                               String uri = new String( api + "." + pmap[i].getUri());
+                               DmaapPerm perm = new DmaapPerm( uri, instance, pmap[i].getAction() );
+                               int rc = aaf.addPerm( perm );
+                               if ( rc != 201 &&  rc != 409 ) {
+                                       errorLogger.error( DmaapbcLogMessageEnum.AAF_UNEXPECTED_RESPONSE,  Integer.toString(rc), "add perm",  perm.toString() );
+
+                               }
+                               for( String r: pmap[i].getRoles()) {
+                                       String fr = new String( api + "." + r );
+                                       logger.debug( "i:" + i + " granting perm " + perm.toString()+ " to role=" + fr );
+                                       DmaapGrant grant = new DmaapGrant( perm, fr );
+                                       rc = aaf.addGrant( grant );
+                                       if ( rc != 201 && rc != 409 ) {
+                                               errorLogger.error( DmaapbcLogMessageEnum.AAF_UNEXPECTED_RESPONSE,  Integer.toString(rc), "grant perm",  perm.toString() );
+                                       }
+                               }
+                               
+                       }
+               }
+       }
+       
+       static PermissionMap[] bootMap = {
+               new PermissionMap( "dmaap", "GET", new String[] { "Controller" }),
+               new PermissionMap( "dmaap", "POST", new String[] { "Controller" }),     
+               new PermissionMap( "dmaap", "PUT", new String[] { "Controller" }),
+               new PermissionMap( "dmaap", "DELETE", new String[] { "Controller" })
+       
+       };
+
+       static PermissionMap[] envMap = {
+               new PermissionMap( "dmaap", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "dmaap", "POST", new String[] { "Controller" } ),            
+               new PermissionMap( "dmaap", "PUT", new String[] { "Controller" }),
+               new PermissionMap( "dmaap", "DELETE", new String[] { "Controller" }),
+               new PermissionMap( "bridge", "GET", new String[] {  "Metrics" }),
+               //new PermissionMap( "bridge", "POST", new String[] { "Metrics" } ),            
+               //new PermissionMap( "bridge", "PUT", new String[] { "Metrics" }),
+               //new PermissionMap( "bridge", "DELETE", new String[] { "Metrics" }),
+               new PermissionMap( "dcaeLocations", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "dcaeLocations", "POST", new String[] { "Controller" } ),            
+               new PermissionMap( "dcaeLocations", "PUT", new String[] { "Controller" }),
+               new PermissionMap( "dcaeLocations", "DELETE", new String[] { "Controller" }),
+               new PermissionMap( "dr_nodes", "GET", new String[] { "Controller", "Orchestrator", "Inventory",  "PortalUser" }),
+               new PermissionMap( "dr_nodes", "POST", new String[] { "Controller" } ),         
+               new PermissionMap( "dr_nodes", "PUT", new String[] { "Controller" }),
+               new PermissionMap( "dr_nodes", "DELETE", new String[] { "Controller" }),
+               new PermissionMap( "dr_pubs", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "dr_pubs", "POST", new String[] { "Controller", "Orchestrator","PortalUser" } ),             
+               new PermissionMap( "dr_pubs", "PUT", new String[] { "Controller", "Orchestrator","PortalUser" }),
+               new PermissionMap( "dr_pubs", "DELETE", new String[] { "Controller", "Orchestrator","PortalUser" }),
+               new PermissionMap( "dr_subs", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "dr_subs", "POST", new String[] { "Controller", "Orchestrator","PortalUser" } ),             
+               new PermissionMap( "dr_subs", "PUT", new String[] { "Controller", "Orchestrator","PortalUser" }),
+               new PermissionMap( "dr_subs", "DELETE", new String[] { "Controller", "Orchestrator","PortalUser" }),
+               new PermissionMap( "feeds", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "feeds", "POST", new String[] { "Controller", "Orchestrator","PortalUser" } ),               
+               new PermissionMap( "feeds", "PUT", new String[] { "Controller", "Orchestrator", "PortalUser" }),
+               new PermissionMap( "feeds", "DELETE", new String[] { "Controller", "PortalUser" }),
+               new PermissionMap( "mr_clients", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "mr_clients", "POST", new String[] { "Controller","Orchestrator", "PortalUser" } ),          
+               new PermissionMap( "mr_clients", "PUT", new String[] { "Controller", "Orchestrator","PortalUser" }),
+               new PermissionMap( "mr_clients", "DELETE", new String[] { "Controller","Orchestrator", "PortalUser" }),
+               new PermissionMap( "mr_clusters", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "mr_clusters", "POST", new String[] { "Controller" } ),              
+               new PermissionMap( "mr_clusters", "PUT", new String[] { "Controller" }),
+               new PermissionMap( "mr_clusters", "DELETE", new String[] { "Controller" }),
+               new PermissionMap( "topics", "GET", new String[] { "Controller", "Orchestrator", "Inventory", "Metrics", "PortalUser" }),
+               new PermissionMap( "topics", "POST", new String[] { "Controller", "Orchestrator" } ),           
+               new PermissionMap( "topics", "PUT", new String[] { "Controller", "Orchestrator" }),
+               new PermissionMap( "topics", "DELETE", new String[] { "Controller", "Orchestrator" })
+       };
+       
+       public void setBootMap() {
+               String instance = "boot";
+               PermissionMap.initMap( bootMap, instance );
+       }
+       
+       public void setEnvMap() {
+               Dmaap dmaap = new DmaapService().getDmaap();
+               String dmaap_name = dmaap.getDmaapName();
+               PermissionMap.initMap( envMap, dmaap_name );
+       }
+       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPolicy.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/ApiPolicy.java
new file mode 100644 (file)
index 0000000..a86f83f
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.aaf.authentication;
+
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class ApiPolicy extends BaseLoggingClass {
+       static String allow = "allow";
+       String dClass = null;
+       ApiPermissionInterface perm = null;
+       
+       public ApiPolicy() {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               dClass = p.getProperty( "ApiPermission.Class", allow );
+               logger.info( "ApiPolicy implements " + dClass);
+               if ( dClass.equalsIgnoreCase( allow )) {
+                       return;
+               }
+
+               try {
+                       perm = (ApiPermissionInterface) (Class.forName(dClass).newInstance());  
+               } catch (Exception ee ) {
+                       errorLogger.error(DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, "attempting to instantiate " + dClass  );         
+                       errorLogger.error( "trace is: " + ee );
+               }       
+       }
+       
+       public void check( String mechid, String pwd, DmaapPerm p ) throws AuthenticationErrorException {
+               if ( dClass.equalsIgnoreCase( allow )) {
+                       return;
+               }
+               
+               // execute check of loaded class
+               perm.check( mechid, pwd, p );
+       
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/AuthenticationErrorException.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/authentication/AuthenticationErrorException.java
new file mode 100644 (file)
index 0000000..c740eac
--- /dev/null
@@ -0,0 +1,29 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.authentication;
+
+public class AuthenticationErrorException extends Exception {
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/client/DrProvConnection.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/client/DrProvConnection.java
new file mode 100644 (file)
index 0000000..2d2ca8f
--- /dev/null
@@ -0,0 +1,797 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.ProtocolException;
+import java.net.SocketException;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.DR_Sub;
+import org.onap.dmaap.dbcapi.model.Feed;
+import org.onap.dmaap.dbcapi.service.DmaapService;
+import org.onap.dmaap.dbcapi.util.RandomInteger;
+
+
+
+public class DrProvConnection extends BaseLoggingClass {
+          
+   
+       private String provURL;
+       
+       private HttpsURLConnection uc;
+
+
+       public DrProvConnection() {
+               provURL = new DmaapService().getDmaap().getDrProvUrl();
+               if ( provURL.length() < 1 ) {
+                       errorLogger.error( DmaapbcLogMessageEnum.PREREQ_DMAAP_OBJECT, "getDrProvUrl");
+               }
+                       
+       }
+       
+       public boolean makeFeedConnection() {
+               return makeConnection( provURL );
+       }
+       public boolean makeFeedConnection(String feedId) {
+               return makeConnection( provURL + "/feed/" + feedId );   
+       }
+       public boolean makeSubPostConnection( String subURL ) {
+               String[] parts = subURL.split("/");
+               String revisedURL = provURL + "/" + parts[3] + "/" + parts[4];
+               logger.info( "mapping " + subURL + " to " + revisedURL );
+               return makeConnection( revisedURL );
+       }
+       public boolean makeSubPutConnection( String subId ) {
+               String revisedURL = provURL + "/subs/" + subId;
+               logger.info( "mapping " + subId + " to " + revisedURL );
+               return makeConnection( revisedURL );
+       }
+
+       public boolean makeIngressConnection( String feed, String user, String subnet, String nodep ) {
+               String uri = String.format("/internal/route/ingress/?feed=%s&user=%s&subnet=%s&nodepatt=%s", 
+                                       feed, user, subnet, nodep );
+               return makeConnection( provURL + uri );
+       }
+       public boolean makeEgressConnection( String sub, String nodep ) {
+               String uri = String.format("/internal/route/egress/?sub=%s&node=%s", 
+                                       sub,  nodep );
+               return makeConnection( provURL + uri );
+       }
+       public boolean makeNodesConnection( String varName ) {
+               
+               String uri = String.format("/internal/api/%s", varName);
+               return makeConnection( provURL + uri );
+       }
+       
+       public boolean makeNodesConnection( String varName, String val ) {
+
+               if ( val == null ) {
+                       return false;
+               } 
+               String cv = val.replaceAll("\\|", "%7C");
+               String uri = String.format( "/internal/api/%s?val=%s", varName, cv );
+
+               return makeConnection( provURL + uri );
+       }
+       
+       private boolean makeConnection( String pURL ) {
+       
+               try {
+                       URL u = new URL( pURL );
+                       uc = (HttpsURLConnection) u.openConnection();
+                       uc.setInstanceFollowRedirects(false);
+                       logger.info( "successful connect to " + pURL );
+                       return(true);
+               } catch (Exception e) {
+                       errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_ERROR,  pURL, e.getMessage() );
+            e.printStackTrace();
+            return(false);
+        }
+
+       }
+       
+       private String bodyToString( InputStream is ) {
+               logger.info( "is=" + is );
+               StringBuilder sb = new StringBuilder();
+               BufferedReader br = new BufferedReader( new InputStreamReader(is));
+               String line;
+               try {
+                       while ((line = br.readLine()) != null ) {
+                               sb.append( line );
+                       }
+               } catch (IOException ex ) {
+                       errorLogger.error( DmaapbcLogMessageEnum.IO_EXCEPTION, ex.getMessage());
+               }
+                       
+               return sb.toString();
+       }
+       
+
+       public  String doPostFeed( Feed postFeed, ApiError err ) {
+
+               byte[] postData = postFeed.getBytes();
+               logger.info( "post fields=" + postData.toString() );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+                       logger.info( "uc=" + uc );
+                       uc.setRequestMethod("POST");
+                       uc.setRequestProperty("Content-Type", "application/vnd.att-dr.feed");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", postFeed.getOwner() );
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc == 201 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else {
+               err.setCode( rc );
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (ConnectException ce) {
+                       errorLogger.error(DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() );
+            err.setCode( 500 );
+               err.setMessage("Backend connection refused");
+               } catch (SocketException se) {
+                       errorLogger.error( DmaapbcLogMessageEnum.SOCKET_EXCEPTION, se.getMessage(), "response from prov server" );
+                       err.setCode( 500 );
+                       err.setMessage( "Unable to read response from DR");
+        } catch (Exception e) {
+            logger.warn("Unable to read response  " );
+            e.printStackTrace();
+            try {
+                   err.setCode( uc.getResponseCode());
+                   err.setMessage(uc.getResponseMessage());
+            } catch (Exception e2) {
+               err.setCode( 500 );
+               err.setMessage("Unable to determine response message");
+            }
+        } 
+               finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return responseBody;
+
+       }
+
+       
+       // the POST for /internal/route/ingress doesn't return any data, so needs a different function
+       // the POST for /internal/route/egress doesn't return any data, so needs a different function   
+       public int doXgressPost( ApiError err ) {
+               
+               String responsemessage = null;
+               int rc = -1;
+
+               try {
+                       uc.setRequestMethod("POST");
+//                     uc.setRequestProperty("Content-Type", "application/vnd.att-dr.feed");
+//                     uc.setRequestProperty( "charset", "utf-8");
+//                     uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", postFeed.getOwner() );
+//                     uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+//                     uc.setUseCaches(false);
+//                     uc.setDoOutput(true);   
+                       OutputStream os = null;
+       
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+
+            if (rc < 200 || rc >= 300 ) {
+               err.setCode( rc );
+               err.setMessage(responsemessage);
+            }
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        }              finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+       
+               return rc;
+
+       }
+       
+       public String doPostDr_Sub( DR_Sub postSub, ApiError err ) {
+               logger.info( "entry: doPostDr_Sub() "  );
+               byte[] postData = postSub.getBytes();
+               logger.info( "post fields=" + postData );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+       
+                       uc.setRequestMethod("POST");
+               
+                       uc.setRequestProperty("Content-Type", "application/vnd.att-dr.subscription");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", "DGL" );
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc == 201 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else {
+               err.setCode(rc);
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        }              finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return responseBody;
+
+       }
+       
+
+       public String doPutFeed(Feed putFeed, ApiError err) {
+               byte[] postData = putFeed.getBytes();
+               logger.info( "post fields=" + postData.toString() );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+                       logger.info( "uc=" + uc );
+                       uc.setRequestMethod("PUT");
+                       uc.setRequestProperty("Content-Type", "application/vnd.att-dr.feed");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", putFeed.getOwner() );
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc >= 200 && rc < 300 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else if ( rc == 404 ) {
+               err.setCode( rc );
+               err.setFields( "feedid");
+               String message =  "FeedId " + putFeed.getFeedId() + " not found on DR to update.  Out-of-sync condition?";
+               err.setMessage( message );
+               errorLogger.error( DmaapbcLogMessageEnum.PROV_OUT_OF_SYNC, "Feed", putFeed.getFeedId() );
+               
+            } else {
+               err.setCode( rc );
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (ConnectException ce) {
+                       errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() );
+            err.setCode( 500 );
+               err.setMessage("Backend connection refused");
+               } catch (SocketException se) {
+                       errorLogger.error( DmaapbcLogMessageEnum.SOCKET_EXCEPTION, se.getMessage(), "response from Prov server" );
+                       err.setCode( 500 );
+                       err.setMessage( "Unable to read response from DR");
+        } catch (Exception e) {
+            logger.warn("Unable to read response  " );
+            e.printStackTrace();
+            try {
+                   err.setCode( uc.getResponseCode());
+                   err.setMessage(uc.getResponseMessage());
+            } catch (Exception e2) {
+               err.setCode( 500 );
+               err.setMessage("Unable to determine response message");
+            }
+        }              finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return responseBody;
+       }
+       public String doPutDr_Sub(DR_Sub postSub, ApiError err) {
+               logger.info( "entry: doPutDr_Sub() "  );
+               byte[] postData = postSub.getBytes();
+               logger.info( "post fields=" + postData );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+       
+                       uc.setRequestMethod("PUT");
+               
+                       uc.setRequestProperty("Content-Type", "application/vnd.att-dr.subscription");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", "DGL" );
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc == 200 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else {
+               err.setCode(rc);
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (ConnectException ce) {
+            errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() );
+            err.setCode( 500 );
+               err.setMessage("Backend connection refused");
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        } finally {
+               uc.disconnect();
+        }
+               return responseBody;
+
+       }
+       
+       public String doGetNodes( ApiError err ) {
+               logger.info( "entry: doGetNodes() "  );
+               //byte[] postData = postSub.getBytes();
+               //logger.info( "get fields=" + postData );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+       
+                       uc.setRequestMethod("GET");
+               
+                       //uc.setRequestProperty("Content-Type", "application/vnd.att-dr.subscription");
+                       //uc.setRequestProperty( "charset", "utf-8");
+                       //uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", "DGL" );
+                       //uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       //uc.setUseCaches(false);
+                       //uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 //os = uc.getOutputStream();
+                 //os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            } 
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+               err.setCode(rc);  // may not really be an error, but we save rc
+            if (rc == 200 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+            } else {
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (ConnectException ce) {
+            errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() );
+            err.setCode( 500 );
+               err.setMessage("Backend connection refused");
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        } finally {
+               uc.disconnect();
+        }
+               return responseBody;
+
+       }
+       public String doPutNodes( ApiError err ) {
+               logger.info( "entry: doPutNodes() "  );
+               //byte[] postData = nodeList.getBytes();
+               //logger.info( "get fields=" + postData );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+       
+                       uc.setRequestMethod("PUT");
+               
+                       //uc.setRequestProperty("Content-Type", "application/vnd.att-dr.subscription");
+                       //uc.setRequestProperty( "charset", "utf-8");
+                       //uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", "DGL" );
+                       //uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       //uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 //os = uc.getOutputStream();
+                 //os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+               err.setCode(rc);
+            if (rc == 200 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else {
+  
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        } finally {
+               uc.disconnect();
+        }
+               return responseBody;
+
+       }
+       
+       public String doDeleteFeed(Feed putFeed, ApiError err) {
+               //byte[] postData = putFeed.getBytes();
+               //logger.info( "post fields=" + postData.toString() );
+               String responsemessage = null;
+               String responseBody = null;
+
+               try {
+                       logger.info( "uc=" + uc );
+                       uc.setRequestMethod("DELETE");
+                       uc.setRequestProperty("Content-Type", "application/vnd.att-dr.feed");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "X-ATT-DR-ON-BEHALF-OF", putFeed.getOwner() );
+                       //uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+                       int rc = -1;
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 //os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc >= 200 && rc < 300 ) {
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+
+            } else if ( rc == 404 ) {
+               err.setCode( rc );
+               err.setFields( "feedid");
+               String message =  "FeedId " + putFeed.getFeedId() + " not found on DR to update.  Out-of-sync condition?";
+               err.setMessage( message );
+               errorLogger.error( DmaapbcLogMessageEnum.PROV_OUT_OF_SYNC, "Feed", putFeed.getFeedId() );
+               
+            } else {
+               err.setCode( rc );
+               err.setMessage(responsemessage);
+            }
+            
+               } catch (ConnectException ce) {
+                       errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, ce.getMessage() );
+            err.setCode( 500 );
+               err.setMessage("Backend connection refused");
+               } catch (SocketException se) {
+                       errorLogger.error( DmaapbcLogMessageEnum.SOCKET_EXCEPTION, se.getMessage(), "response from Prov server" );
+                       err.setCode( 500 );
+                       err.setMessage( "Unable to read response from DR");
+        } catch (Exception e) {
+            logger.warn("Unable to read response  " );
+            e.printStackTrace();
+            try {
+                   err.setCode( uc.getResponseCode());
+                   err.setMessage(uc.getResponseMessage());
+            } catch (Exception e2) {
+               err.setCode( 500 );
+               err.setMessage("Unable to determine response message");
+            }
+        }              finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return responseBody;
+       }
+       
+       /*
+        public static void main( String[] args ) throws Exception {
+               PropertyConfigurator.configure("log4j.properties");
+               logger.info("Started.");
+               
+               RandomInteger ri = new RandomInteger(10000);
+                       //String postJSON = String.format("{\"name\": \"dgl feed %d\", \"version\": \"v1.0\", \"description\": \"dgl feed N for testing\", \"authorization\": { \"classification\": \"unclassified\", \"endpoint_addrs\": [],\"endpoint_ids\": [{\"password\": \"test\",\"id\": \"test\"}]}}", ri.next()) ;
+                       int i = ri.next();
+                       Feed tst = new Feed( "dgl feed " + i,
+                                                               "v1.0",
+                                                               "dgl feed " + i + "for testing",
+                                                               "TEST",
+                                                               "unclassified"
+                                       );
+                       ArrayList<DR_Pub> pubs = new ArrayList<DR_Pub>();
+                       pubs.add( new DR_Pub( "centralLocation" ) ); 
+                       tst.setPubs(pubs);
+
+               boolean rc;
+               DrProvConnection context = new DrProvConnection();
+               rc = context.makeFeedConnection();
+               logger.info( "makeFeedConnection returns " + rc);
+               ApiError err = new ApiError();
+               if ( rc ) {
+                       String tmp  = context.doPostFeed( tst, err );
+                       logger.info( "doPostFeed returns " + tmp);
+               }
+    
+        }
+ */
+       
+               
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrProvConnection.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrProvConnection.java
new file mode 100644 (file)
index 0000000..420f10e
--- /dev/null
@@ -0,0 +1,218 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.ProtocolException;
+import java.net.URL;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.aaf.AafDecrypt;
+import org.onap.dmaap.dbcapi.aaf.AafService;
+import org.onap.dmaap.dbcapi.aaf.DecryptionInterface;
+import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class MrProvConnection extends BaseLoggingClass{
+           
+       private String provURL;
+       
+       private HttpsURLConnection uc;
+
+       
+       private String topicMgrCred;
+       
+       private String getCred( ) {
+               String mechIdProperty = "aaf.TopicMgrUser";
+               String pwdProperty = "aaf.TopicMgrPassword";
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+
+               String user = p.getProperty( mechIdProperty, "noMechId@domain.netset.com" );
+
+               String pwd = "";
+               String encPwd = p.getProperty( pwdProperty, "notSet" );
+
+               AafDecrypt decryptor = new AafDecrypt();
+               pwd = decryptor.decrypt(encPwd);
+       
+               return user + ":" + pwd;
+               
+               
+               
+       }
+       
+       
+       public MrProvConnection( ) {
+               topicMgrCred =  getCred();
+
+       }
+       
+       public boolean makeTopicConnection( MR_Cluster cluster ) {
+               logger.info( "connect to cluster: " + cluster.getDcaeLocationName());
+       
+
+               provURL = cluster.getTopicProtocol() + "://" + cluster.getFqdn() + ":" + cluster.getTopicPort() + "/topics/create";
+
+               return makeConnection( provURL );
+       }
+
+       private boolean makeConnection( String pURL ) {
+               logger.info( "makeConnection to " + pURL );
+       
+               try {
+                       URL u = new URL( pURL );
+                       uc = (HttpsURLConnection) u.openConnection();
+                       uc.setInstanceFollowRedirects(false);
+                       logger.info( "open connect to " + pURL );
+                       return(true);
+               } catch( UnknownHostException uhe ){
+               logger.error( "Caught UnknownHostException for " + pURL);
+               return(false);
+        } catch (Exception e) {
+            logger.error("Unexpected error during openConnection of " + pURL );
+            e.printStackTrace();
+            return(false);
+        } 
+
+       }
+       
+       static String bodyToString( InputStream is ) {
+               StringBuilder sb = new StringBuilder();
+               BufferedReader br = new BufferedReader( new InputStreamReader(is));
+               String line;
+               try {
+                       while ((line = br.readLine()) != null ) {
+                               sb.append( line );
+                       }
+               } catch (IOException ex ) {
+                       errorLogger.error( "IOexception:" + ex);
+               }
+                       
+               return sb.toString();
+       }
+       
+       public String doPostTopic( Topic postTopic, ApiError err ) {
+               String auth =  "Basic " + Base64.encodeBase64String(topicMgrCred.getBytes());
+
+
+               String responsemessage = null;
+               int rc = -1;
+
+
+               try {
+                       byte[] postData = postTopic.getBytes();
+                       logger.info( "post fields=" + postData.toString() );
+                       uc.setRequestProperty("Authorization", auth);
+                       logger.info( "Authenticating with " + auth );
+                       uc.setRequestMethod("POST");
+                       uc.setRequestProperty("Content-Type", "application/json");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            } catch ( UnknownHostException uhe ) {
+               errorLogger.error( DmaapbcLogMessageEnum.UNKNOWN_HOST_EXCEPTION , "Unknown Host Exception" , provURL );
+               err.setCode(500);
+               err.setMessage("Unknown Host Exception");
+               err.setFields( uc.getURL().getHost());
+               return new String( "500: " + uhe.getMessage());
+            }catch ( ConnectException ce ) {
+               errorLogger.error( DmaapbcLogMessageEnum.HTTP_CONNECTION_EXCEPTION, provURL, "HTTP Connection Exception"  );
+               err.setCode(500);
+               err.setMessage("HTTP Connection Exception");
+               err.setFields( uc.getURL().getHost());
+               return new String( "500: " + ce.getMessage());
+            }
+                       rc = uc.getResponseCode();
+                       logger.info( "http response code:" + rc );
+                       err.setCode(rc);
+            responsemessage = uc.getResponseMessage();
+            logger.info( "responsemessage=" + responsemessage );
+            err.setMessage(responsemessage);
+
+
+            if (responsemessage == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         responsemessage = h0.substring(j + 1);
+                     }
+                 }
+            }
+            if (rc >= 200 && rc < 300 ) {
+                       String responseBody = null;
+                       responseBody = bodyToString( uc.getInputStream() );
+                       logger.info( "responseBody=" + responseBody );
+                       return responseBody;
+
+            } 
+            
+               } catch (Exception e) {
+            System.err.println("Unable to read response  " );
+            e.printStackTrace();
+        }
+               finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return new String( rc +": " + responsemessage );
+
+       }
+       
+
+
+               
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrTopicConnection.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/client/MrTopicConnection.java
new file mode 100644 (file)
index 0000000..0b49379
--- /dev/null
@@ -0,0 +1,176 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.client;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ProtocolException;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLException;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+
+public class MrTopicConnection extends BaseLoggingClass  {
+       private String topicURL;
+       
+       private HttpsURLConnection uc;
+
+       
+       private  String mmProvCred; 
+       
+
+
+       public MrTopicConnection(String user, String pwd ) {
+               mmProvCred = new String( user + ":" + pwd );
+
+       }
+       
+       public boolean makeTopicConnection( MR_Cluster cluster, String topic, String overrideFqdn ) {
+               String fqdn = overrideFqdn != null ? overrideFqdn : cluster.getFqdn();
+               logger.info( "connect to cluster: " + fqdn + " for topic: " + topic );
+       
+
+               topicURL = cluster.getTopicProtocol() + "://" + fqdn + ":" + cluster.getTopicPort() + "/events/" + topic ;
+
+               return makeConnection( topicURL );
+       }
+
+       private boolean makeConnection( String pURL ) {
+               logger.info( "makeConnection to " + pURL );
+       
+               try {
+                       URL u = new URL( pURL );
+                       uc = (HttpsURLConnection) u.openConnection();
+                       uc.setInstanceFollowRedirects(false);
+                       logger.info( "open connection to " + pURL );
+                       return(true);
+               } catch (Exception e) {
+            logger.error("Unexpected error during openConnection of " + pURL );
+            e.printStackTrace();
+            return(false);
+        }
+
+       }
+       
+       static String bodyToString( InputStream is ) {
+               StringBuilder sb = new StringBuilder();
+               BufferedReader br = new BufferedReader( new InputStreamReader(is));
+               String line;
+               try {
+                       while ((line = br.readLine()) != null ) {
+                               sb.append( line );
+                       }
+               } catch (IOException ex ) {
+                       errorLogger.error( "IOexception:" + ex);
+               }
+                       
+               return sb.toString();
+       }
+       
+       public ApiError doPostMessage( String postMessage ) {
+               ApiError response = new ApiError();
+               String auth =  "Basic " + Base64.encodeBase64String(mmProvCred.getBytes());
+
+
+
+               try {
+                       byte[] postData = postMessage.getBytes();
+                       logger.info( "post fields=" + postMessage );
+                       uc.setRequestProperty("Authorization", auth);
+                       logger.info( "Authenticating with " + auth );
+                       uc.setRequestMethod("POST");
+                       uc.setRequestProperty("Content-Type", "application/json");
+                       uc.setRequestProperty( "charset", "utf-8");
+                       uc.setRequestProperty( "Content-Length", Integer.toString( postData.length ));
+                       uc.setUseCaches(false);
+                       uc.setDoOutput(true);
+                       OutputStream os = null;
+
+                       
+                       try {
+                 uc.connect();
+                 os = uc.getOutputStream();
+                 os.write( postData );
+
+            } catch (ProtocolException pe) {
+                 // Rcvd error instead of 100-Continue
+                 try {
+                     // work around glitch in Java 1.7.0.21 and likely others
+                     // without this, Java will connect multiple times to the server to run the same request
+                     uc.setDoOutput(false);
+                 } catch (Exception e) {
+                 }
+            }  catch ( SSLException se ) {
+                       response.setCode(500);
+                       response.setMessage( se.getMessage());
+                       return response;
+               
+            }
+                       response.setCode( uc.getResponseCode());
+                       logger.info( "http response code:" + response.getCode());
+            response.setMessage( uc.getResponseMessage() ); 
+            logger.info( "response message=" + response.getMessage() );
+
+
+            if ( response.getMessage() == null) {
+                 // work around for glitch in Java 1.7.0.21 and likely others
+                 // When Expect: 100 is set and a non-100 response is received, the response message is not set but the response code is
+                 String h0 = uc.getHeaderField(0);
+                 if (h0 != null) {
+                     int i = h0.indexOf(' ');
+                     int j = h0.indexOf(' ', i + 1);
+                     if (i != -1 && j != -1) {
+                         response.setMessage( h0.substring(j + 1) );
+                     }
+                 }
+            }
+            if ( response.is2xx() ) {
+                       response.setFields( bodyToString( uc.getInputStream() ) );
+                       logger.info( "responseBody=" + response.getFields() );
+                       return response;
+
+            } 
+            
+               } catch (Exception e) {
+                       response.setCode(500);
+                       response.setMessage( "Unable to read response");
+                       logger.warn( response.getMessage() );
+            e.printStackTrace();
+        }
+               finally {
+                       try {
+                               uc.disconnect();
+                       } catch ( Exception e ) {}
+               }
+               return response;
+
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnWrapper.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnWrapper.java
new file mode 100644 (file)
index 0000000..019caef
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.sql.*;
+
+
+public abstract class ConnWrapper<T, U>        {
+       protected Connection c;
+       protected PreparedStatement ps;
+       protected ResultSet     rs;
+       protected abstract T run(U u) throws Exception;
+       public T protect(ConnectionFactory cf, U u) throws DBException {
+               try {
+                       try {
+                               return(attempt(cf, u, false));
+                       } catch (SQLException sqle) {
+                               return(attempt(cf, u, true));
+                       }
+               } catch (RuntimeException rte) {
+                       throw rte;
+               } catch (Exception e) {
+                       throw new DBException(e);
+               }
+       }
+       private T attempt(ConnectionFactory cf, U u, boolean fresh) throws Exception {
+               c = null;
+               ps = null;
+               rs = null;
+               try {
+                       c = cf.get(fresh);
+                       T ret = run(u);
+                       cf.release(c);
+                       c = null;
+                       return(ret);
+               } finally {
+                       if (rs != null) { try { rs.close(); } catch (Exception e) {}}
+                       rs = null;
+                       if (ps != null) { try { ps.close(); } catch (Exception e) {}}
+                       ps = null;
+                       if (c != null) { try { c.close(); } catch (Exception e) {}}
+                       c = null;
+               }
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnectionFactory.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/ConnectionFactory.java
new file mode 100644 (file)
index 0000000..64a2959
--- /dev/null
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.sql.*;
+import java.util.*;
+
+import org.apache.log4j.Logger;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class ConnectionFactory {
+        static final EELFLogger logger = EELFManager.getInstance().getLogger( ConnectionFactory.class );
+        static final EELFLogger appLogger = EELFManager.getInstance().getApplicationLogger();
+        static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+        static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+        static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+        static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+        static final EELFLogger serverLogger = EELFManager.getInstance().getServerLogger();
+
+       static {
+               try {
+                       Class.forName("org.postgresql.Driver");
+               } catch (Exception e) {
+                       logger.error("Unable to load postgres driver " + e, e);
+               }
+       }
+       private static ConnectionFactory instance = new ConnectionFactory();
+       private String  host;
+       private String  dbname;
+       private String  dbuser;
+       private String  dbcr;
+       public ConnectionFactory() {
+               Properties p = DmaapConfig.getConfig();
+               host = p.getProperty("DB.host", "dcae-pstg-write-ftl.domain.notset.com");
+               dbname = p.getProperty("DB.name", "dmaap");
+               dbuser = p.getProperty("DB.user", "dmaap_admin");
+               dbcr = p.getProperty("DB.cred", "test234-ftl");
+       }
+       public static ConnectionFactory getDefaultInstance() {
+               return(instance);
+       }
+       private Connection[] pool = new Connection[5];
+       private int     cur;
+       public Connection get(boolean fresh) throws SQLException {
+               if (!fresh) {
+                       synchronized(this) {
+                               if (cur > 0) {
+                                       return(pool[--cur]);
+                               }
+                       }
+               }
+               Properties p = new Properties();
+               p.put("user", dbuser);
+               p.put("password", dbcr);
+               return(DriverManager.getConnection("jdbc:postgresql://" + host + "/" + dbname, p));
+       }
+       public void release(Connection c) {
+               synchronized(this) {
+                       if (cur < pool.length) {
+                               pool[cur++] = c;
+                               return;
+                       }
+               }
+               try { c.close(); } catch (Exception e) {}
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBException.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBException.java
new file mode 100644 (file)
index 0000000..f73e510
--- /dev/null
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+
+public class DBException extends RuntimeException {
+       static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+       public DBException(Exception e) {
+               super(e);
+               errorLogger.error(DmaapbcLogMessageEnum.DB_ACCESS_ERROR,  e.getMessage());
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBFieldHandler.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBFieldHandler.java
new file mode 100644 (file)
index 0000000..52af453
--- /dev/null
@@ -0,0 +1,202 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.lang.reflect.*;
+import java.sql.*;
+import java.util.*;
+
+import org.apache.log4j.Logger;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+
+
+public class DBFieldHandler    {
+       static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+       
+       public static interface SqlOp   {
+               public Object get(ResultSet rs, int index) throws Exception;
+               public void set(PreparedStatement ps, int index, Object value) throws Exception;
+       }
+       private static class    AofString implements SqlOp {
+               public Object get(ResultSet rs, int index) throws Exception {
+                       String val = rs.getString(index);
+                       if (val == null) {
+                               return(null);
+                       }
+                       String[] ret = val.split(",");
+                       for (int i = 0; i < ret.length; i++) {
+                               ret[i] = funesc(ret[i]);
+                       }
+                       return(ret);
+               }
+               public void set(PreparedStatement ps, int index, Object x) throws Exception {
+                       String[] val = (String[])x;
+                       if (val == null) {
+                               ps.setString(index, null);
+                               return;
+                       }
+                       StringBuffer sb = new StringBuffer();
+                       String sep = "";
+                       for (String s: val) {
+                               sb.append(sep).append(fesc(s));
+                               sep = ",";
+                       }
+                       ps.setString(index, sb.toString());
+               }
+       }
+       private static class    EnumSql implements SqlOp {
+               private Class   enclass;
+               public EnumSql(Class enclass) {
+                       this.enclass = enclass;
+               }
+               @SuppressWarnings("unchecked")
+               public Object get(ResultSet rs, int index) throws Exception {
+                       String val = rs.getString(index);
+                       if (val == null) {
+                               return(null);
+                       } else {
+                               return(Enum.valueOf(enclass, val));
+                       }
+               }
+               public void set(PreparedStatement ps, int index, Object value) throws Exception {
+                       if (value == null) {
+                               ps.setString(index, null);
+                       } else {
+                               ps.setString(index, value.toString());
+                       }
+               }
+       }
+       private static class    SqlDate implements SqlOp {
+               public Object get(ResultSet rs, int index) throws Exception {
+                       return(rs.getTimestamp(index));
+               }
+               public void set(PreparedStatement ps, int index, Object val) throws Exception {
+                       if (val instanceof java.util.Date && !(val instanceof java.sql.Timestamp)) {
+                               val = new java.sql.Timestamp(((java.util.Date)val).getTime());
+                       }
+                       ps.setTimestamp(index, (java.sql.Timestamp)val);
+               }
+       }
+        private static class    SqlType implements SqlOp {
+                private Method   sqlget;
+                private Method   sqlset;
+                private SqlType(String tag) throws Exception {
+                       sqlget = ResultSet.class.getMethod("get" + tag, Integer.TYPE);
+                        sqlset = PreparedStatement.class.getMethod("set" + tag, Integer.TYPE, sqlget.getReturnType());
+                        sqltypes.put(sqlget.getReturnType().getName(), this);
+                }
+               public Object get(ResultSet rs, int index) throws Exception {
+                       return(sqlget.invoke(rs, index));
+               }
+               public void set(PreparedStatement ps, int index, Object val) throws Exception {
+                       try {
+                               sqlset.invoke(ps, index, val);
+                       } catch (Exception e) {
+                               errorLogger.error(DmaapbcLogMessageEnum.DB_FIELD_INIT_ERROR,  Integer.toString(index), val.toString(), ps.toString());
+                               throw e;
+                       }
+               }
+        }
+        private static Map<String, SqlOp> sqltypes;
+        static {
+                sqltypes = new HashMap<String, SqlOp>();
+               sqltypes.put("[Ljava.lang.String;", new AofString());
+               sqltypes.put("java.util.Date", new SqlDate());
+                try {
+                        new SqlType("Boolean");
+                        new SqlType("Timestamp");
+                        new SqlType("Double");
+                        new SqlType("Float");
+                        new SqlType("Int");
+                        new SqlType("Long");
+                        new SqlType("Short");
+                        new SqlType("String");
+                } catch (Exception e) {
+                       errorLogger.error(DmaapbcLogMessageEnum.DB_ACCESS_INIT_ERROR,  e.getMessage() );
+                }
+        }
+       private Method  objget;
+       private Method  objset;
+       private SqlOp   sqlop;
+       private int     fieldnum;
+       public void copy(Object from, Object to) throws Exception {
+               objset.invoke(to, objget.invoke(from));
+       }
+       public void setKey(Object o, String key) throws Exception {
+               objset.invoke(o, key);
+       }
+       public String getKey(Object o) throws Exception {
+               return((String)objget.invoke(o));
+       }
+       public void toSQL(Object o, PreparedStatement ps) throws Exception {
+               sqlop.set(ps, fieldnum, objget.invoke(o));
+       }
+       public void fromSQL(ResultSet r, Object o) throws Exception {
+               objset.invoke(o, sqlop.get(r, fieldnum));
+       }
+       public DBFieldHandler(Class<?> c, String fieldname, int fieldnum) throws Exception {
+               this(c, fieldname, fieldnum, null);
+       }
+       public DBFieldHandler(Class<?> c, String fieldname, int fieldnum, SqlOp op) throws Exception {
+               this.fieldnum = fieldnum;
+               StringBuffer sb = new StringBuffer();
+               for (String s: fieldname.split("_")) {
+                       sb.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
+               }
+               String camelcase = sb.toString();
+               try {
+                       objget = c.getMethod("is" + camelcase);
+               } catch (Exception e) {
+                       objget = c.getMethod("get" + camelcase);
+               }
+               objset = c.getMethod("set" + camelcase, objget.getReturnType());
+               sqlop = op;
+               if (sqlop != null) {
+                       return;
+               }
+               Class<?> x = objget.getReturnType();
+               if (x.isEnum()) {
+                       sqlop = new EnumSql(x);
+                       return;
+               }
+               sqlop = sqltypes.get(x.getName());
+               if (sqlop != null) {
+                       return;
+               }
+               errorLogger.error(DmaapbcLogMessageEnum.DB_NO_FIELD_HANDLER,  c.getName(),  fieldname,  Integer.toString(fieldnum),  x.getName());
+       }
+       public static String fesc(String s) {
+               if (s == null) {
+                       return(s);
+               }
+               return(s.replaceAll("@", "@a").replaceAll(";", "@s").replaceAll(",", "@c"));
+       }
+       public static String funesc(String s) {
+               if (s == null) {
+                       return(s);
+               }
+               return(s.replaceAll("@c", ",").replaceAll("@s", ";").replaceAll("@a", "@"));
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBMap.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBMap.java
new file mode 100644 (file)
index 0000000..8b8e3ad
--- /dev/null
@@ -0,0 +1,138 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.sql.*;
+import java.util.*;
+
+public class DBMap<C> extends TableHandler<C> implements Map<String, C>        {
+       public DBMap(Class<C> cls, String tabname, String keyfield) throws Exception {
+               this(ConnectionFactory.getDefaultInstance(), cls, tabname, keyfield);
+       }
+       public DBMap(ConnectionFactory cf, Class<C> cls, String tabname, String keyfield) throws Exception {
+               super(cf, cls, tabname, keyfield);
+       }
+       public void clear() throws UnsupportedOperationException {
+               throw new UnsupportedOperationException();
+       }
+       public boolean containsKey(Object key) throws DBException {
+               return(get(key) != null);
+       }
+       public boolean containsValue(Object value) throws UnsupportedOperationException {
+               throw new UnsupportedOperationException();
+       }
+       public boolean isEmpty() {
+               return(false);
+       }
+       public Set<Map.Entry<String, C>> entrySet() throws DBException {
+               return(list());
+       }
+       public Set<String> keySet() throws DBException {
+               Set<String> ret = new HashSet<String>();
+               for (Map.Entry<String, C> x: list()) {
+                       ret.add(x.getKey());
+               }
+               return(ret);
+       }
+       public void putAll(Map<? extends String, ? extends C> m) throws UnsupportedOperationException {
+               throw new UnsupportedOperationException();
+       }
+       public int size() {
+               return(2);
+       }
+       public Collection<C> values() throws DBException {
+               Collection<C> ret = new Vector<C>();
+               for (Map.Entry<String, C> x: list()) {
+                       ret.add(x.getValue());
+               }
+               return(ret);
+       }
+       public C get(Object key) throws DBException {
+               if (!(key instanceof String)) {
+                       return(null);
+               }
+               return((new ConnWrapper<C, String>() {
+                       protected C run(String key) throws Exception {
+                               ps = c.prepareStatement(getstmt);
+                               ps.setString(1, (String)key);
+                               rs = ps.executeQuery();
+                               if (!rs.next()) {
+                                       return(null);
+                               }
+                               C ret = cls.newInstance();
+                               for (DBFieldHandler f: fields) {
+                                       f.fromSQL(rs, ret);
+                               }
+                               return(ret);
+                       }
+               }).protect(cf, (String)key));
+       }
+       public Set<Map.Entry<String, C>> list() throws DBException {
+               return((new ConnWrapper<Set<Map.Entry<String, C>>, Object>() {
+                       protected Set<Map.Entry<String, C>> run(Object junk) throws Exception {
+                               DBFieldHandler keyfield = fields[fields.length - 1];
+                               ps = c.prepareStatement(liststmt);
+                               rs = ps.executeQuery();
+                               Set<Map.Entry<String, C>> ret = new HashSet<Map.Entry<String, C>>();
+                               while (rs.next()) {
+                                       C val = cls.newInstance();
+                                       for (DBFieldHandler f: fields) {
+                                               f.fromSQL(rs, val);
+                                       }
+                                       String key = keyfield.getKey(val);
+                                       ret.add(new AbstractMap.SimpleEntry<String, C>(key, val));
+                               }
+                               return(ret);
+                       }
+               }).protect(cf, null));
+       }
+       public C put(String key, C val) throws DBException {
+               try {
+                       fields[fields.length - 1].setKey(val, key);
+               } catch (Exception e) {
+                       throw new DBException(e);
+               }
+               PreparedStatement ps = null;
+               return((new ConnWrapper<C, C>() {
+                       protected C run(C val) throws Exception {
+                               ps = c.prepareStatement(insorreplstmt);
+                               for (DBFieldHandler f: fields) {
+                                       f.toSQL(val, ps);
+                               }
+                               ps.executeUpdate();
+                               return(null);
+                       }
+               }).protect(cf, val));
+       }
+       public C remove(Object key) throws DBException {
+               if (!(key instanceof String)) {
+                       return(null);
+               }
+               return((new ConnWrapper<C, String>() {
+                       protected C run(String key) throws Exception {
+                               ps = c.prepareStatement(delstmt);
+                               ps.setString(1, key);
+                               ps.executeUpdate();
+                               return(null);
+                       }
+               }).protect(cf, (String)key));
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBSingleton.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DBSingleton.java
new file mode 100644 (file)
index 0000000..8c158ca
--- /dev/null
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.sql.*;
+import java.util.*;
+
+import org.onap.dmaap.dbcapi.util.Singleton;
+
+public class DBSingleton<C> extends TableHandler<C> implements Singleton<C>    {
+       private C singleton;
+       public DBSingleton(Class<C> cls, String tabname) throws Exception {
+               this(ConnectionFactory.getDefaultInstance(), cls, tabname);
+       }
+       public DBSingleton(ConnectionFactory cf, Class<C> cls, String tabname) throws Exception {
+               super(cf, cls, tabname, null);
+               singleton = cls.newInstance();
+       }
+       public C get() throws DBException {
+               return((new ConnWrapper<C, Object>() {
+                       protected C run(Object junk) throws Exception {
+                               ps = c.prepareStatement(getstmt);
+                               rs = ps.executeQuery();
+                               if (!rs.next()) {
+                                       return(null);
+                               }
+                               for (DBFieldHandler f: fields) {
+                                       f.fromSQL(rs, singleton);
+                               }
+                               return(singleton);
+                       }
+               }).protect(cf, null));
+       }
+       public void init(C val) throws DBException {
+               if (get() != null) {
+                       return;
+               }
+               (new ConnWrapper<Void, C>() {
+                       protected Void run(C val) throws Exception {
+                               ps = c.prepareStatement(initstmt);
+                               for (DBFieldHandler f: fields) {
+                                       f.toSQL(val, ps);
+                               }
+                               ps.executeUpdate();
+                               if (val != singleton) {
+                                       for (DBFieldHandler f: fields) {
+                                               f.copy(val, singleton);
+                                       }
+                               }
+                               return(null);
+                       }
+               }).protect(cf, val);
+       }
+       public void update(C val) throws DBException {
+               (new ConnWrapper<Void, C>() {
+                       protected Void run(C val) throws Exception {
+                               ps = c.prepareStatement(insorreplstmt);
+                               for (DBFieldHandler f: fields) {
+                                       f.toSQL(val, ps);
+                               }
+                               ps.executeUpdate();
+                               if (val != singleton) {
+                                       for (DBFieldHandler f: fields) {
+                                               f.copy(val, singleton);
+                                       }
+                               }
+                               return(null);
+                       }
+               }).protect(cf, val);
+       }
+       public void remove() throws DBException {
+               (new ConnWrapper<Void, Object>() {
+                       protected Void run(Object junk) throws Exception {
+                               ps = c.prepareStatement(delstmt);
+                               ps.executeUpdate();
+                               return(null);
+                       }
+               }).protect(cf, null);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DatabaseClass.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/DatabaseClass.java
new file mode 100644 (file)
index 0000000..baa86a6
--- /dev/null
@@ -0,0 +1,270 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.util.*;
+import java.sql.*;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.*;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.Singleton;
+
+
+
+
+public class DatabaseClass extends BaseLoggingClass {
+       
+       private static Singleton<Dmaap> dmaap;
+       private static Map<String, DcaeLocation> dcaeLocations;
+       private static Map<String, DR_Node> dr_nodes;
+       private static Map<String, DR_Pub> dr_pubs;
+       private static Map<String, DR_Sub> dr_subs;
+       private static Map<String, MR_Client> mr_clients;
+       private static Map<String, MR_Cluster> mr_clusters;
+       private static Map<String, Feed> feeds;
+       private static Map<String, Topic> topics;
+       private static Map<String, MirrorMaker> mirrors;
+       
+       private static long lastTime = 0L;
+       
+       private static class MirrorVectorHandler implements DBFieldHandler.SqlOp {
+               public Object get(ResultSet rs, int index) throws Exception {
+                       String val = rs.getString(index);
+                       if (val == null) {
+                               return(null);
+                       }
+                       Set<ReplicationVector> rv = new HashSet<ReplicationVector>();
+                       for (String s: val.split(",")) {
+                               String[] f = s.split(";");
+                               if (f.length < 3) {
+                                       continue;
+                               }
+                               rv.add(new ReplicationVector(DBFieldHandler.funesc(f[0]), DBFieldHandler.funesc(f[1]), DBFieldHandler.funesc(f[2])));
+                       }
+                       return(rv);
+               }
+               public void set(PreparedStatement ps, int index, Object val) throws Exception {
+                       if (val == null) {
+                               ps.setString(index, null);
+                               return;
+                       }
+                       Set xv = (Set)val;
+                       StringBuffer sb = new StringBuffer();
+                       String sep = "";
+                       for (Object o: xv) {
+                               ReplicationVector rv = (ReplicationVector)o;
+                               sb.append(sep).append(DBFieldHandler.fesc(rv.getFqtn())).append(';').append(DBFieldHandler.fesc(rv.getSourceCluster())).append(';').append(DBFieldHandler.fesc(rv.getTargetCluster()));
+                               sep = ",";
+                       }
+                       ps.setString(index, sb.toString());
+               }
+       }
+
+       // modified version of MirrorVectorHandler for Topics
+       private static class MirrorTopicsHandler implements DBFieldHandler.SqlOp {
+               public Object get(ResultSet rs, int index) throws Exception {
+                       String val = rs.getString(index);
+                       if (val == null) {
+                               return(null);
+                       }
+                       List<String> rv = new ArrayList<String>();
+                       for (String s: val.split(",")) {
+                               //String[] f = s.split(";");
+                               //if (f.length < 3) {
+                               //      continue;
+                               //}
+                               rv.add(new String(s));
+                       }
+                       return(rv);
+               }
+               public void set(PreparedStatement ps, int index, Object val) throws Exception {
+                       if (val == null) {
+                               ps.setString(index, null);
+                               return;
+                       }
+                       @SuppressWarnings("unchecked")
+                       List<String> xv = (List<String>)val;
+                       StringBuffer sb = new StringBuffer();
+                       String sep = "";
+                       for (Object o: xv) {
+                               String rv = (String)o;
+                               sb.append(sep).append(DBFieldHandler.fesc(rv));
+                               sep = ",";
+                       }
+                       ps.setString(index, sb.toString());
+               }
+       }
+       private static class TopicReplicationTypeHandler implements DBFieldHandler.SqlOp {
+               public Object get(ResultSet rs, int index) throws Exception {
+                       int val = rs.getInt(index);
+
+                       return (ReplicationType.valueOf(val));
+               }
+               public void set(PreparedStatement ps, int index, Object val) throws Exception {
+                       if (val == null) {
+                               ps.setInt(index, 0);
+                               return;
+                       }
+                       @SuppressWarnings("unchecked")
+                       ReplicationType rep = (ReplicationType) val;
+                       ps.setInt(index, rep.getValue());
+               }       
+       }
+       public static Singleton<Dmaap> getDmaap() {
+               return dmaap;
+       }
+       
+
+       
+       public static Map<String, DcaeLocation> getDcaeLocations() {
+               return dcaeLocations;
+       }
+       
+       public static Map<String, DR_Node> getDr_nodes() {
+               return dr_nodes;
+       }
+       
+       public static Map<String, DR_Sub> getDr_subs() {
+               return dr_subs;
+       }
+       public static Map<String, DR_Pub> getDr_pubs() {
+               return dr_pubs;
+       }
+
+       public static Map<String, MR_Client> getMr_clients() {
+               return mr_clients;
+       }
+
+
+       public static Map<String, MR_Cluster> getMr_clusters() {
+               return mr_clusters;
+       }
+       
+       public static Map<String, Feed> getFeeds() {
+               return feeds;
+       }
+       public static Map<String, Topic> getTopics() {
+               return topics;
+       }
+       public static Map<String, MirrorMaker> getMirrorMakers() {
+               return mirrors;
+       }
+
+       static {
+               try {
+               appLogger.info( "begin static initialization");
+               appLogger.info( "initializing dmaap" );
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               if ("true".equalsIgnoreCase(p.getProperty("UsePGSQL", "false"))) {
+                       appLogger.info("Data from database");
+                       try {
+                               LoadSchema.upgrade();
+                       } catch (Exception e) {
+                               appLogger.warn("Problem updating DB schema", e);
+                       }
+                       try {
+                               dmaap = new DBSingleton<Dmaap>(Dmaap.class, "dmaap");
+                               dcaeLocations = new DBMap<DcaeLocation>(DcaeLocation.class, "dcae_location", "dcae_location_name");
+                               dr_nodes = new DBMap<DR_Node>(DR_Node.class, "dr_node", "fqdn");
+                               dr_pubs = new DBMap<DR_Pub>(DR_Pub.class, "dr_pub", "pub_id");
+                               dr_subs = new DBMap<DR_Sub>(DR_Sub.class, "dr_sub", "sub_id");
+                               mr_clients = new DBMap<MR_Client>(MR_Client.class, "mr_client", "mr_client_id");
+                               mr_clusters = new DBMap<MR_Cluster>(MR_Cluster.class, "mr_cluster", "dcae_location_name");
+                               feeds = new DBMap<Feed>(Feed.class, "feed", "feed_id");
+                               TableHandler.setSpecialCase("topic", "replication_case", new TopicReplicationTypeHandler());
+                               topics = new DBMap<Topic>(Topic.class, "topic", "fqtn");
+                               //TableHandler.setSpecialCase("mirror_maker", "vectors", new MirrorVectorHandler());
+                               TableHandler.setSpecialCase("mirror_maker", "topics", new MirrorTopicsHandler());
+                               mirrors = new DBMap<MirrorMaker>(MirrorMaker.class, "mirror_maker", "mm_name");
+                       } catch (Exception e) {
+                               errorLogger.error("Error initializing database access " + e, e);
+                               System.exit(1);
+                       }
+               } else {
+                       appLogger.info("Data from memory");
+                       dmaap = new Singleton<Dmaap>() {
+                               private Dmaap dmaap;
+                               public void remove() {
+                                       dmaap = null;
+                               }
+                               public void init(Dmaap val) {
+                                       if (dmaap == null) {
+                                               dmaap = val;
+                                       }
+                               }
+                               public Dmaap get() {
+                                       return(dmaap);
+                               }
+                               public void update(Dmaap nd) {
+                                       dmaap.setVersion(nd.getVersion());
+                                       dmaap.setTopicNsRoot(nd.getTopicNsRoot());
+                                       dmaap.setDmaapName(nd.getDmaapName());
+                                       dmaap.setDrProvUrl(nd.getDrProvUrl());
+                                       dmaap.setBridgeAdminTopic(nd.getBridgeAdminTopic());
+                                       dmaap.setLoggingUrl(nd.getLoggingUrl());
+                                       dmaap.setNodeKey(nd.getNodeKey());
+                                       dmaap.setAccessKeyOwner(nd.getAccessKeyOwner());
+                               }
+                       };
+                       dcaeLocations = new HashMap<String, DcaeLocation>();
+                       dr_nodes = new HashMap<String, DR_Node>();
+                       dr_pubs = new HashMap<String, DR_Pub>();
+                       dr_subs = new HashMap<String, DR_Sub>();
+                       mr_clients = new HashMap<String, MR_Client>();
+                       mr_clusters = new HashMap<String, MR_Cluster>();
+                       feeds = new HashMap<String, Feed>();
+                       topics = new HashMap<String, Topic>();
+                       mirrors = new HashMap<String, MirrorMaker>();
+               }
+               dmaap.init(new Dmaap("0", "", "", "", "", "", "", ""));
+               // check for, and set up initial data, if it isn't already there
+               Dmaap dmx = dmaap.get();
+               if ("0".equals(dmx.getVersion())) {
+
+                       dmx = new Dmaap("0", "", "", "", "", "", "", "");
+                       dmx.setDmaapName(p.getProperty("DmaapName"));
+                       dmx.setDrProvUrl("https://" + p.getProperty("DR.provhost", "notSet"));
+                       dmx.setTopicNsRoot(p.getProperty("topicNsRoot"));
+                       dmx.setBridgeAdminTopic("DCAE_MM_AGENT");
+
+                       dmaap.update(dmx);
+               }
+               } catch (Exception e) {
+                       errorLogger.error(DmaapbcLogMessageEnum.DB_UPDATE_ERROR, e.getMessage());
+               }
+       }
+       
+       public synchronized static String getNextClientId() {
+               
+               long id = System.currentTimeMillis();
+               if ( id <= lastTime ) {
+                       id = lastTime + 1;
+               }
+               lastTime = id;
+               return Long.toString(id);
+       }
+
+       
+
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/LoadSchema.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/LoadSchema.java
new file mode 100644 (file)
index 0000000..bbd6f18
--- /dev/null
@@ -0,0 +1,117 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.io.*;
+import java.sql.*;
+
+import org.apache.log4j.Logger;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+
+public class LoadSchema        {
+       private static final EELFLogger logger = EELFManager.getInstance().getLogger(LoadSchema.class);
+       private static final EELFLogger appLogger = EELFManager.getInstance().getApplicationLogger();
+       private static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+       private static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+       private static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+       private static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+       
+       static int getVer(Statement s) throws SQLException {
+               ResultSet rs = null;
+               try {
+                       rs = s.executeQuery("SELECT version FROM dmaapbc_sch_ver");
+                       rs.next();
+                       return(rs.getInt(1));
+               } finally {
+                       if (rs != null) {
+                               rs.close();
+                       }
+               }
+       }
+       static void upgrade() throws SQLException {
+               ConnectionFactory cf = ConnectionFactory.getDefaultInstance();
+               Connection c = null;
+               Statement stmt = null;
+               InputStream is = null;
+               try {
+                       c = cf.get(true);
+                       stmt = c.createStatement();
+                       int newver = -1;
+                       try {
+                               newver = getVer(stmt);
+                       } catch (Exception e) {}
+                       logger.info("Database schema currently at version " + newver++);
+                       while ((is = LoadSchema.class.getClassLoader().getResourceAsStream("schema_" + newver + ".sql")) != null) {
+                               logger.info("Upgrading database schema to version " + newver);
+                               BufferedReader br = new BufferedReader(new InputStreamReader(is));
+                               String s;
+                               String sofar = null;
+                               while ((s = br.readLine()) != null) {
+                                       logger.info("SCHEMA: " + s);
+                                       s = s.trim();
+                                       if (s.length() == 0 || s.startsWith("--")) {
+                                               continue;
+                                       }
+                                       if (sofar == null) {
+                                               sofar = s;
+                                       } else {
+                                               sofar = sofar + " " + s;
+                                       }
+                                       if (s.endsWith(";")) {
+                                               sofar = sofar.substring(0, sofar.length() - 1);
+                                               boolean ignore = false;
+                                               if (sofar.startsWith("@")) {
+                                                       ignore = true;
+                                                       sofar = sofar.substring(1).trim();
+                                               }
+                                               try {
+                                                       stmt.execute(sofar);
+                                               } catch (SQLException sqle) {
+                                                       if (!ignore) {
+                                                               throw sqle;
+                                                       }
+                                               }
+                                               sofar = null;
+                                       }
+                               }
+                               is.close();
+                               is = null;
+                               if (getVer(stmt) != newver) {
+                                       throw new SQLException("Schema version not properly updated to " + newver + " by upgrade script");
+                               }
+                               logger.info("Upgrade to database schema version " + newver + " successful");
+                               newver++;
+                       }
+               } catch (IOException ioe) {
+                       throw new SQLException(ioe);
+               } finally {
+                       if (stmt != null) { try { stmt.close(); } catch (Exception e) {}}
+                       if (c != null) { try { c.close(); } catch (Exception e) {}}
+               }
+       }
+       public static void main(String[] args) throws Exception {
+               upgrade();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/aaf/database/TableHandler.java b/src/main/java/org/onap/dmaap/dbcapi/aaf/database/TableHandler.java
new file mode 100644 (file)
index 0000000..fe610ab
--- /dev/null
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.aaf.database;
+
+import java.util.*;
+import java.lang.reflect.*;
+import java.sql.*;
+
+class TableHandler<C>  {
+       protected ConnectionFactory cf;
+       protected boolean       haskey;
+       protected String        delstmt;
+       protected String        insorreplstmt;
+       protected String        getstmt;
+       protected String        liststmt;
+       protected String        initstmt;
+       protected Class<C>      cls;
+       protected DBFieldHandler[] fields;
+       private static Map<String, Map<String, DBFieldHandler.SqlOp>> exceptions = new HashMap<String, Map<String, DBFieldHandler.SqlOp>>();
+       public static void setSpecialCase(String dbtabname, String dbfldname, DBFieldHandler.SqlOp handler) {
+               Map<String, DBFieldHandler.SqlOp> m = exceptions.get(dbtabname);
+               if (m == null) {
+                       m = new HashMap<String, DBFieldHandler.SqlOp>();
+                       exceptions.put(dbtabname, m);
+               }
+               m.put(dbfldname, handler);
+       }
+       public static DBFieldHandler.SqlOp getSpecialCase(String dbtabname, String dbfldname) {
+               Map<String, DBFieldHandler.SqlOp> m = exceptions.get(dbtabname);
+               if (m != null) {
+                       return(m.get(dbfldname));
+               }
+               return(null);
+       }
+       protected TableHandler(Class<C> cls, String tabname, String keyname) throws Exception {
+               this(ConnectionFactory.getDefaultInstance(), cls, tabname, keyname);
+       }
+       protected TableHandler(ConnectionFactory cf, Class<C> cls, String tabname, String keyname) throws Exception {
+               this.cf = cf;
+               Connection c = null;
+               try {
+                       c = cf.get(false);
+                       setup(c.getMetaData(), cls, tabname, keyname);
+               } finally {
+                       if (c != null) {
+                               cf.release(c);
+                       }
+               }
+       }
+       private void setup(DatabaseMetaData dmd, Class<C> cls, String tabname, String keyname) throws Exception {
+               this.cls = cls;
+               Vector<DBFieldHandler> h = new Vector<DBFieldHandler>();
+               ResultSet rs = dmd.getColumns("", "public", tabname, null);
+               StringBuffer sb1 = new StringBuffer();
+               StringBuffer sb2 = new StringBuffer();
+               StringBuffer sb3 = new StringBuffer();
+               int     count = 0;
+               while (rs.next()) {
+                       if (!rs.getString(3).equals(tabname)) {
+                               continue;
+                       }
+                       String cname = rs.getString(4);
+                       if (cname.equals(keyname)) {
+                               haskey = true;
+                               continue;
+                       }
+                       sb1.append(", ").append(cname);
+                       sb2.append(", ?");
+                       sb3.append(", EXCLUDED.").append(cname);
+                       count++;
+                       h.add(new DBFieldHandler(cls, cname, count, getSpecialCase(tabname, cname)));
+               }
+               if (count == 0) {
+                       throw new SQLException("Table " + tabname + " not found");
+               }
+               String clist = sb1.substring(2);
+               String qlist = sb2.substring(2);
+               String elist = sb3.substring(2);
+               if (keyname != null && !haskey) {
+                       throw new SQLException("Table " + tabname + " does not have key column " + keyname + " not found");
+               }
+               if (haskey) {
+                       count++;
+                       h.add(new DBFieldHandler(cls, keyname, count, getSpecialCase(tabname, keyname)));
+                       delstmt = "DELETE FROM " + tabname + " WHERE " + keyname + " = ?";
+                       insorreplstmt = "INSERT INTO " + tabname + " (" + clist + ", " + keyname + ") VALUES (" + qlist + ", ?) ON CONFLICT(" + keyname + ") DO UPDATE SET (" + clist + ") = (" + elist + ")";
+                       getstmt = "SELECT " + clist + ", " + keyname + " FROM " + tabname + " WHERE " + keyname + " = ?";
+                       liststmt = "SELECT " + clist + ", " + keyname + " FROM " + tabname;
+               } else {
+                       delstmt = "DELETE FROM " + tabname;
+                       initstmt = "INSERT INTO " + tabname + " (" + clist + ") VALUES (" + qlist + ")";
+                       insorreplstmt = "UPDATE " + tabname + " SET (" + clist + ") = (" + qlist + ")";
+                       getstmt = "SELECT " + clist + ", " + keyname + " FROM " + tabname;
+               }
+               fields = h.toArray(new DBFieldHandler[h.size()]);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/logging/BaseLoggingClass.java b/src/main/java/org/onap/dmaap/dbcapi/logging/BaseLoggingClass.java
new file mode 100644 (file)
index 0000000..bb078cf
--- /dev/null
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.logging;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+public abstract class BaseLoggingClass {
+       protected  EELFLogger logger = EELFManager.getInstance().getLogger( super.getClass());
+       protected static final EELFLogger appLogger = EELFManager.getInstance().getApplicationLogger();
+       protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+       protected static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+       protected static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+       protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+       protected static final EELFLogger serverLogger = EELFManager.getInstance().getServerLogger();
+
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/logging/DmaapbcLogMessageEnum.java b/src/main/java/org/onap/dmaap/dbcapi/logging/DmaapbcLogMessageEnum.java
new file mode 100644 (file)
index 0000000..86c5fe0
--- /dev/null
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.logging;
+
+import com.att.eelf.i18n.EELFResourceManager;
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+
+public enum DmaapbcLogMessageEnum implements EELFResolvableErrorEnum {
+//0xx sample stock messages
+  MESSAGE_SAMPLE_NOARGS,
+  MESSAGE_SAMPLE_ONE_ARG,
+  MESSAGE_SAMPLE_TWO_ARGS,
+
+// 1xx Permission Errors
+  AAF_CREDENTIAL_ERROR,
+  CODEC_CREDENTIAL_ERROR,
+  PE_AUTHENTICATION_ERROR,
+  DR_PROV_AUTHORIZATION,
+
+// 2xx Availability Errors/Timeouts
+  DRIVER_UNAVAILABLE,
+  HTTP_CONNECTION_ERROR,
+  HTTP_CONNECTION_EXCEPTION,
+  UNKNOWN_HOST_EXCEPTION,
+
+  
+// 3xx Data Errors
+  IO_EXCEPTION,
+  SSL_HANDSHAKE_ERROR,
+  AAF_UNEXPECTED_RESPONSE,
+  PE_EXCEPTION,
+  SOCKET_EXCEPTION,
+  JSON_PARSING_ERROR,
+  DECRYPT_IO_ERROR,
+  
+//4xx Schema Errors
+  DB_UPGRADE_ERROR,
+  DB_INIT_ERROR,
+  DB_UPDATE_ERROR,
+  DB_ACCESS_ERROR,
+  DB_FIELD_INIT_ERROR,
+  DB_ACCESS_INIT_ERROR,
+  DB_NO_FIELD_HANDLER,
+
+
+// 5xx Business Process Errors
+  PREREQ_DMAAP_OBJECT,
+  PROV_OUT_OF_SYNC,
+  MM_CIRCULAR_REF,
+  TOPIC_CREATE_ERROR,
+  INGRESS_CREATE_ERROR,
+  FEED_PUB_PROV_ERROR,
+  FEED_SUB_PROV_ERROR,
+  MM_PUBLISH_ERROR,
+  EGRESS_CREATE_ERROR,
+
+// 900 Unknown Errors
+  UNEXPECTED_CONDITION;
+
+       static {
+               EELFResourceManager.loadMessageBundle("logmsg");
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/logging/logmsg.properties b/src/main/java/org/onap/dmaap/dbcapi/logging/logmsg.properties
new file mode 100644 (file)
index 0000000..cb8a939
--- /dev/null
@@ -0,0 +1,240 @@
+###
+# ============LICENSE_START=======================================================
+#  org.onap.dmaap
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+# 0xx sample stock messages
+MESSAGE_SAMPLE_NOARGS=\
+  01|\
+  Ignore: demo msg with no arg|\
+  No resolution|\
+  An example of a message with no args
+
+MESSAGE_SAMPLE_ONE_ARG=\
+  02|\
+  Ignore: demo  msg with 1 arg {0}|\
+  No resolution|\
+  An example of a message with 1 arg
+
+MESSAGE_SAMPLE_TWO_ARGS=\
+  03|\
+  Ignore: demo msg with arg1 {0} and arg2 {1}|\
+  No resolution|\
+  An example of a message with 2 args
+  
+
+  
+# 1xx Permission Errors
+AAF_CREDENTIAL_ERROR=\
+  101|\
+  Service credentials ({0}) are not valid for AAF connection|\
+  Check credentials are valid in appropriate AAF environment.|\
+  Connection to AAF was not allowed for the specified credentials.
+  
+CODEC_CREDENTIAL_ERROR=\
+  102|\
+  Failed to read CredentialCodecKeyfile {0} with error {1}|\
+  Check if CredentialCodecKeyfile has been corrupted.|\
+  CredentialCodecKeyfile is not in sync with application
+  
+PE_AUTHENTICATION_ERROR=\
+  103|\
+  User {0} perms {1} caught PolicyEngineException {1}|\
+  User needs to be granted perm before access.|\
+  Identified user was not authorized for the specific perm.
+  
+DR_PROV_AUTHORIZATION=\
+  104|\
+  Not authorized for API {0}|\
+  Bus Controller host needs to be provisioned as a Node and an AUTHORIZED_HOST.|\
+  DR Prov indicates that Bus Controller host is not authorized for the specified API.
+
+# 2xx Availability Errors/Timeouts
+DRIVER_UNAVAILABLE=\
+  201|\
+  Unable to load driver {0}. Error {1}|\
+  Check that specified driver is installed and accessible to application.|\
+  The software attempted to load a driver and was not successful.
+  
+HTTP_CONNECTION_ERROR=\
+  202|\
+  Exception during openConnection to {0} failed with {1}|\
+  Confirm syntax of URL is correct and network access from this host is allowed.|\
+  An attempt to URL.openConnection failed
+
+HTTP_CONNECTION_EXCEPTION=\
+  203|\
+  Connection to {0} refused because {1}|\  
+  Check if this is the proper server.|\
+  Application caught a ConnectionException
+
+UNKNOWN_HOST_EXCEPTION=\
+  204|\
+  Caught exception {0} attempting to access {1}|\
+  Confirm that host is in DNS|\
+  Caught UnknownHostException when connecting to the designated host name.
+
+# 3xx Data Errors
+IO_EXCEPTION=\
+  301|\
+  IOexception {0}|\
+  No resolution.|\
+  Generic IO Exception condition
+
+SSL_HANDSHAKE_ERROR=\
+  302|\
+  SSLHandshakeException from URL {0}|\
+  Confirm that target host has proper SSL certificate for DNS value used to access it.|\
+  SSLHandshake exception thrown on HttpsURLConnection method
+  
+AAF_UNEXPECTED_RESPONSE=\
+  303|\
+  rc= {0} :unable to {1} for {2}|\
+  Check configuration for this AAF instance.|\
+  Unexpected response from AAF for the intended action
+  
+PE_EXCEPTION=\
+  304|\
+  Trying to read {0} and caught PolicyEngineException {1}|\
+  Check config file exists and has proper settings.|\
+  An unexpected exception from PE was caught.
+  
+SOCKET_EXCEPTION=\
+  305|\
+  Caught exception {0} while {1}|\
+  No comment.|\
+  An unexpected socket exception was caught while performing the specified action.
+  
+JSON_PARSING_ERROR=\
+  306|\
+  ParsingException for object {0} using data:{1}|\
+  No comment.|\
+  The JSON data provided to the object was not in the expected format
+ DECRYPT_IO_ERROR=\
+   307|\
+   IO Error attempting using {0} to decrypt value {1}|\
+   Check permissions of file set for property CredentialCodecKeyfile.|\
+   Error using codec file for decryption. 
+  
+# 4xx Schema Errors
+
+DB_UPGRADE_ERROR=\
+  401|\
+  Problem updating DB schema. {0}|\
+  Examine stack trace for clues.|\
+  The software was not able to process the sql file resources in the jar file.
+DB_INIT_ERROR=\
+  402|\
+  Error initializing database access: {0}|\
+  Correct configuration based on detail.|\
+  The software was not able initialize objects from the DB.
+  
+DB_UPDATE_ERROR=\
+  403|\
+  Error while updating DB: {0}|\
+  Correct configuration based on detail.|\
+  The software was not able to update record(s) in the DB.
+DB_ACCESS_ERROR=\
+  404|\
+  Database access problem: {0}|\
+  Correct configuration based on detail.|\
+  An exception related to DB access was caught and logged.
+  
+DB_FIELD_INIT_ERROR=\
+  405|\
+  Problem setting field {0} to {1} statement is {2}|\
+  DB schema may be out of sync with code.|\
+  SQLDate.set() failed to set field value.
+
+DB_ACCESS_INIT_ERROR=\
+  406|\
+  Problem initializing sql access methods {0} |\
+  No comment.|\
+  Error encountered while initializing basic field types.
+  
+DB_NO_FIELD_HANDLER=\
+  407|\
+  No field handler for class {0} field {1} index {2} type {3}|\
+  No comment.|\
+  Missing field handler for specified code.
+
+
+# 5xx Business Process Errors
+PREREQ_DMAAP_OBJECT=\
+  501|\
+  Attempt to access {} before dmaap object resource is available.|\
+  No remediation.|\
+  The dmaap object needs to be defined before attempting the desired access
+  
+PROV_OUT_OF_SYNC=\
+  502|\
+  Resource {0} with id {1} was not in sync with DR Prov.\
+  May need manual sync steps.\
+  The Bus Controller view of a resource does not match what was found on DR Prov
+  
+MM_CIRCULAR_REF=\
+  503|\
+  Trying to add edge from source {0} into Map belonging to {1}|\
+  May indicate a provisioning error.|\
+  Some error in logic is attempting to add an edge to a Map that is an edge.
+  
+TOPIC_CREATE_ERROR=\
+  504|\
+  Unable to create topic for {0} err={1} fields={2} msg={3}|\
+  No comment.|\
+  Reporting an error caught while creating a topic
+  
+INGRESS_CREATE_ERROR=\
+  505|\
+  rc={0} unable to create ingress rule for {1} on feed {2} to {3}|\
+  No comment.|\
+  Unexpected response while creating ingress rule
+  
+FEED_PUB_PROV_ERROR=\
+  506|\
+  For feed {0} resulting set of publishers do not match requested set of publishers {1} vs {2}|\
+  No comment.|\
+  The number of publishers on a feed do not match after provisioning request.
+  
+FEED_SUB_PROV_ERROR=\
+  507|\
+  For feed {0} i={1} url={2}  err={3}|\
+  No comment.|\
+  An error occurred when provisioning subs on a feed.
+  
+MM_PUBLISH_ERROR=\
+  508|\
+  Unable to publish {0} provisioning message. rc={1} msg={2}|\
+  No comment.|\
+  An error occurred when publishing a message to MM
+  
+EGRESS_CREATE_ERROR=\
+  509|\
+  rc={0} unable to create egress rule for {1} on feed {2} to {3}|\
+  No comment.|\
+  Unexpected response while creating egress rule
+  
+# 900 Unknown Errors
+UNEXPECTED_CONDITION=\
+  901|\
+  Unexpected exception encountered {0}|\
+  No resolution|\
+  An error to catch unexpected conditions.  Hopefully a clue in the stack trace.
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java b/src/main/java/org/onap/dmaap/dbcapi/model/ApiError.java
new file mode 100644 (file)
index 0000000..8d8e23f
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class ApiError {
+       private int code;
+       private String message;
+       private String fields;
+       
+       public int getCode() {
+               return code;
+       }
+       public void setCode(int rc) {
+               this.code = rc;
+       }
+       public String getMessage() {
+               return message;
+       }
+       public void setMessage(String message) {
+               this.message = message;
+       }
+       public String getFields() {
+               return fields;
+       }
+       public void setFields(String fields) {
+               this.fields = fields;
+       }
+       public String toString() {
+               return String.format( "code=%d msg=%s fields=%s", this.code, this.message, this.fields );
+       }
+       public boolean is2xx() {
+               
+               return code >= 200 && code < 300;
+       }
+       public void reset() {
+               code = 0;
+               message = null;
+               fields = null;
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/BrTopic.java b/src/main/java/org/onap/dmaap/dbcapi/model/BrTopic.java
new file mode 100644 (file)
index 0000000..a7041d0
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.log4j.Logger;
+
+@XmlRootElement
+public class BrTopic {
+       static final Logger logger = Logger.getLogger(BrTopic.class);
+       
+       private String brSource;
+       private String brTarget;
+       private int topicCount;
+       
+       // no-op constructor used by framework
+       public BrTopic() {
+       }
+
+       public String getBrSource() {
+               return brSource;
+       }
+
+       public void setBrSource(String brSource) {
+               this.brSource = brSource;
+       }
+
+       public String getBrTarget() {
+               return brTarget;
+       }
+
+       public void setBrTarget(String brTarget) {
+               this.brTarget = brTarget;
+       }
+
+       public int getTopicCount() {
+               return topicCount;
+       }
+
+       public void setTopicCount(int topicCount) {
+               this.topicCount = topicCount;
+       }
+
+
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Node.java
new file mode 100644 (file)
index 0000000..a85f040
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class DR_Node extends DmaapObject {
+       private String fqdn;
+       private String dcaeLocationName;
+       private String hostName;
+       private String version;
+       
+       public DR_Node() {
+               
+       }
+       
+       public DR_Node( String f,
+                                       String dLN,
+                                       String hN,
+                                       String v ) {
+               this.fqdn = f;
+               this.dcaeLocationName = dLN;
+               this.hostName = hN;
+               this.version = v;
+       }
+
+       public String getFqdn() {
+               return fqdn;
+       }
+
+       public void setFqdn(String fqdn) {
+               this.fqdn = fqdn;
+       }
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+
+       public String getHostName() {
+               return hostName;
+       }
+
+       public void setHostName(String hostName) {
+               this.hostName = hostName;
+       }
+
+       public String getVersion() {
+               return version;
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Pub.java b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Pub.java
new file mode 100644 (file)
index 0000000..06598f7
--- /dev/null
@@ -0,0 +1,135 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.onap.dmaap.dbcapi.util.RandomString;
+
+@XmlRootElement
+public class DR_Pub extends DmaapObject {
+
+       private String dcaeLocationName;
+       private String username;
+       private String userpwd;
+       private String feedId;
+       private String pubId;
+
+       
+       public DR_Pub() {
+               status = DmaapObject_Status.EMPTY;
+               
+       }
+       
+       public DR_Pub( String dLN ) {
+               this.dcaeLocationName = dLN;
+               this.status = DmaapObject_Status.STAGED;
+       }
+       
+       public DR_Pub( String dLN, 
+                                       String uN,
+                                       String uP,
+                                       String fI,
+                                       String pI ) {
+               this.dcaeLocationName = dLN;
+               this.username = uN;
+               this.userpwd = uP;
+               this.feedId = fI;
+               this.pubId = pI;
+               this.status = DmaapObject_Status.VALID;
+       }
+
+
+       public DR_Pub( String dLN, 
+                                                       String uN,
+                                                       String uP,
+                                                       String fI ) {
+               this.dcaeLocationName = dLN;
+               this.username = uN;
+               this.userpwd = uP;
+               this.feedId = fI;
+               this.pubId = fI + "." +  DR_Pub.nextKey();
+               this.status = DmaapObject_Status.VALID; 
+       }
+                       
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+
+       public String getUsername() {
+               return username;
+       }
+
+       public void setUsername(String username) {
+               this.username = username;
+       }
+
+       public String getUserpwd() {
+               return userpwd;
+       }
+
+       public void setUserpwd(String userpwd) {
+               this.userpwd = userpwd;
+       }
+
+       public String getFeedId() {
+               return feedId;
+       }
+
+       public void setFeedId(String feedId) {
+               this.feedId = feedId;
+       }
+
+       public String getPubId() {
+               return pubId;
+       }
+
+       public void setPubId(String pubId) {
+               this.pubId = pubId;
+       }
+       
+       public void setNextPubId() {
+               this.pubId = this.feedId + "." +  DR_Pub.nextKey();
+       }
+
+       public DR_Pub setRandomUserName() {
+               RandomString r = new RandomString(15);
+               this.username = "tmp_" + r.nextString();        
+               return this;
+       }
+       public DR_Pub setRandomPassword() {
+               RandomString r = new RandomString(15);
+               this.userpwd = r.nextString();
+               return this;
+       }
+
+       public static String nextKey() {
+               RandomString ri = new RandomString(5);
+               return ri.nextString();
+               
+       }
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java b/src/main/java/org/onap/dmaap/dbcapi/model/DR_Sub.java
new file mode 100644 (file)
index 0000000..6d36a89
--- /dev/null
@@ -0,0 +1,232 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+
+@XmlRootElement
+public class DR_Sub extends DmaapObject {
+
+       private String dcaeLocationName;
+       private String username;
+       private String userpwd;
+       private String feedId;
+       private String deliveryURL;
+       private String logURL;
+       private String subId;
+       private boolean use100;
+       private boolean suspended;
+       private String owner;
+       
+       public String getOwner() {
+               return owner;
+       }
+
+       public void setOwner(String owner) {
+               this.owner = owner;
+       }
+
+       public boolean isSuspended() {
+               return suspended;
+       }
+
+       public void setSuspended(boolean suspended) {
+               this.suspended = suspended;
+       }
+
+
+
+       public boolean isUse100() {
+               return use100;
+       }
+
+       public void setUse100(boolean use100) {
+               this.use100 = use100;
+       }
+
+       public DR_Sub() {
+
+       }
+       
+       public DR_Sub( String dLN,
+                                       String uN,
+                                       String uP,
+                                       String fI,
+                                       String dU,
+                                       String lU,
+                                       boolean u100 ) {
+               this.dcaeLocationName = dLN;
+               this.username = uN;
+               this.userpwd = uP;
+               this.feedId = fI;
+               this.deliveryURL = dU;
+               this.logURL = lU;
+               this.use100 = u100;
+               this.setStatus( DmaapObject_Status.NEW );
+               this.subId = "0";
+       }
+       
+       public DR_Sub ( String json ) {
+               logger.info( "DR_Sub:" + json );
+               JSONParser parser = new JSONParser();
+               JSONObject jsonObj;
+               
+               try {
+                       jsonObj = (JSONObject) parser.parse( json );
+               } catch ( ParseException pe ) {
+                       errorLogger.error( DmaapbcLogMessageEnum.JSON_PARSING_ERROR, "DR_Sub", json );
+            this.setStatus( DmaapObject_Status.INVALID );
+            return;
+        }
+
+               this.setOwner( (String) jsonObj.get("subscriber"));
+               this.setSuspended( (boolean) jsonObj.get("suspend"));
+               
+               JSONObject links = (JSONObject) jsonObj.get("links");
+               String url = (String) links.get("feed");
+               this.setFeedId( url.substring( url.lastIndexOf('/')+1, url.length() ));
+               url = (String) links.get("self");
+               this.setSubId( url.substring( url.lastIndexOf('/')+1, url.length() ));
+               logger.info( "feedid="+ this.getFeedId() );
+               this.setLogURL( (String) links.get("log") );
+               
+               JSONObject del = (JSONObject) jsonObj.get("delivery");
+               this.setDeliveryURL( (String) del.get("url") ); 
+               this.setUsername( (String) del.get("user"));
+               this.setUserpwd( (String) del.get( "password"));
+               this.setUse100((boolean) del.get( "use100"));
+
+               this.setStatus( DmaapObject_Status.VALID );
+
+               logger.info( "new DR_Sub returning");
+       }
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+
+       public String getUsername() {
+               return username;
+       }
+
+       public void setUsername(String username) {
+               this.username = username;
+       }
+
+       public String getUserpwd() {
+               return userpwd;
+       }
+
+       public void setUserpwd(String userpwd) {
+               this.userpwd = userpwd;
+       }
+
+       public String getFeedId() {
+               return feedId;
+       }
+
+       public void setFeedId(String feedId) {
+               this.feedId = feedId;
+       }
+
+       public String getDeliveryURL() {
+               return deliveryURL;
+       }
+
+       public void setDeliveryURL(String deliveryURL) {
+               this.deliveryURL = deliveryURL;
+       }
+
+       public String getLogURL() {
+               return logURL;
+       }
+
+       public void setLogURL(String logURL) {
+               this.logURL = logURL;
+       }
+
+       public String getSubId() {
+               return subId;
+       }
+
+       public void setSubId(String subId) {
+               this.subId = subId;
+       }
+
+
+
+       public byte[] getBytes() {
+               return toProvJSON().getBytes(StandardCharsets.UTF_8);
+       }
+       // returns the DR_Sub object in JSON that conforms to DR Prov Server expectations
+       public String toProvJSON() {
+               
+               // in DR 3.0, API v2.1 a new groupid field is added.  We are not using this required field so just set it to 0.
+               // we send this regardless of DR Release because older versions of DR seem to safely ignore it
+               // and soon those versions won't be around anyway...
+               // Similarly, in the 1704 Release, a new subscriber attribute "follow_redirect" was introduced.
+               // We are setting it to "true" because that is the general behavior desired in OpenDCAE.
+               // But it is really a no-op for OpenDCAE because we've deployed DR with the SYSTEM-level parameter for FOLLOW_REDIRECTS set to true.
+               // In the event we abandon that, then setting the sub attribute to true will be a good thing.
+               // TODO:
+               //   - introduce Bus Controller API support for these attributes
+               //   - store the default values in the DB
+               String postJSON = String.format("{\"delivery\": {\"url\": \"%s\", \"user\": \"%s\", \"password\": \"%s\", \"use100\":  \"%s\"}, \"metadataOnly\": %s, \"groupid\": \"%s\", \"follow_redirect\": %s }", 
+                               this.getDeliveryURL(), 
+                               this.getUsername(),
+                               this.getUserpwd(),
+                               this.isUse100(),
+                               "false",
+                               "0",
+                               "true");        
+               
+               logger.info( postJSON );
+               return postJSON;
+       }
+       
+       @Override
+       public String toString() {
+               String rc = String.format ( "DR_Sub: {dcaeLocationName=%s username=%s userpwd=%s feedId=%s deliveryURL=%s logURL=%s subid=%s use100=%s suspended=%s owner=%s}",
+                               dcaeLocationName,
+                               username,
+                               userpwd,
+                               feedId,
+                               deliveryURL,
+                               logURL,
+                               subId,
+                               use100,
+                               suspended,
+                               owner
+                               );
+               return rc;
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DcaeLocation.java b/src/main/java/org/onap/dmaap/dbcapi/model/DcaeLocation.java
new file mode 100644 (file)
index 0000000..8248ef1
--- /dev/null
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.log4j.Logger;
+
+@XmlRootElement
+public class DcaeLocation extends DmaapObject {
+       static final Logger logger = Logger.getLogger(MR_Cluster.class);
+       private String clli;
+       private String dcaeLayer;
+       private String dcaeLocationName;
+       private String openStackAvailabilityZone;
+       private String subnet;
+
+       
+
+       public DcaeLocation() {
+
+       }
+
+       public DcaeLocation( String c,
+                                               String dL,
+                                               String dLN,
+                                               String oSAZ,
+                                               String s ) {
+               
+               this.clli = c;
+               this.dcaeLayer = dL;
+               this.dcaeLocationName = dLN;
+               this.openStackAvailabilityZone = oSAZ;
+               this.subnet = s;
+       }
+
+       public String getClli() {
+               return clli;
+       }
+
+       public void setClli(String clli) {
+               this.clli = clli;
+       }
+
+       public String getDcaeLayer() {
+               return dcaeLayer;
+       }
+
+       public void setDcaeLayer(String dcaeLayer) {
+               this.dcaeLayer = dcaeLayer;
+       }
+       public boolean isCentral() {
+               return dcaeLayer != null && dcaeLayer.contains("central");
+       }
+       public boolean isLocal() {
+               return dcaeLayer != null && dcaeLayer.contains("local");
+       }
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+       
+
+
+       public String getOpenStackAvailabilityZone() {
+               return openStackAvailabilityZone;
+       }
+
+       public void setOpenStackAvailabilityZone(String openStackAvailabilityZone) {
+               this.openStackAvailabilityZone = openStackAvailabilityZone;
+       }
+       
+       public String getSubnet() {
+               return subnet;
+       }
+
+       public void setSubnet(String subnet) {
+               this.subnet = subnet;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/Dmaap.java b/src/main/java/org/onap/dmaap/dbcapi/model/Dmaap.java
new file mode 100644 (file)
index 0000000..3f2ef82
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.log4j.Logger;
+
+@XmlRootElement
+public class Dmaap extends DmaapObject {
+       
+       private String version;
+       private String topicNsRoot;
+       private String dmaapName;
+       private String drProvUrl;
+       private String  bridgeAdminTopic;
+       private String loggingUrl;
+       private String nodeKey;
+       private String  accessKeyOwner;
+
+
+
+       // no-op constructor used by framework
+       public Dmaap() {
+               
+       }
+       
+       public Dmaap( String ver, 
+                                       String tnr,
+                                       String dn,
+                                       String dpu,
+                                       String lu,
+                                       String bat,
+                                       String nk,
+                                       String ako ) {
+               this.version = ver;
+               this.topicNsRoot = tnr;
+               this.dmaapName = dn;
+               this.drProvUrl = dpu;
+               this.bridgeAdminTopic = bat;
+               this.loggingUrl = lu;
+               this.nodeKey = nk;
+               this.accessKeyOwner = ako;
+               this.setStatus( DmaapObject_Status.NEW );
+       }
+
+       public String getVersion() {
+               return version;
+       }
+
+       public void setVersion(String version) {
+               this.version = version;
+       }
+
+       public String getTopicNsRoot() {
+               return topicNsRoot;
+       }
+
+       public void setTopicNsRoot(String topicNsRoot) {
+               this.topicNsRoot = topicNsRoot;
+       }
+
+       public String getDmaapName() {
+               return dmaapName;
+       }
+
+       public void setDmaapName(String dmaapName) {
+               this.dmaapName = dmaapName;
+       }
+
+       public String getDrProvUrl() {
+               return drProvUrl;
+       }
+
+       public void setDrProvUrl(String drProvUrl) {
+               this.drProvUrl = drProvUrl;
+       }
+
+
+       public String getNodeKey() {
+               return nodeKey;
+       }
+
+       public void setNodeKey(String nodeKey) {
+               this.nodeKey = nodeKey;
+       }
+
+       public String getAccessKeyOwner() {
+               return accessKeyOwner;
+       }
+
+       public void setAccessKeyOwner(String accessKeyOwner) {
+               this.accessKeyOwner = accessKeyOwner;
+       }
+
+       
+       public String getBridgeAdminTopic() {
+               return bridgeAdminTopic;
+       }
+
+       public void setBridgeAdminTopic(String bridgeAdminTopic) {
+               this.bridgeAdminTopic = bridgeAdminTopic;
+       }
+
+       public String getLoggingUrl() {
+               return loggingUrl;
+       }
+
+       public void setLoggingUrl(String loggingUrl) {
+               this.loggingUrl = loggingUrl;
+       }
+
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java b/src/main/java/org/onap/dmaap/dbcapi/model/DmaapObject.java
new file mode 100644 (file)
index 0000000..567e042
--- /dev/null
@@ -0,0 +1,127 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+
+@XmlRootElement
+public abstract class DmaapObject extends BaseLoggingClass {
+       protected Date lastMod;
+       protected       DmaapObject_Status      status;
+       
+       public Date getLastMod() {
+               return lastMod;
+       }
+
+       public void setLastMod(Date lastMod) {
+               this.lastMod = lastMod;
+       }
+
+       public void setLastMod() {
+               this.lastMod = Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime();
+       }
+       
+       public enum DmaapObject_Status {
+               EMPTY,
+               NEW,
+               STAGED,
+               VALID,
+               INVALID,
+               DELETED
+       }
+       public DmaapObject_Status getStatus() {
+               return status;
+       }
+
+       public void setStatus(DmaapObject_Status status) {
+               this.status = status;
+       }
+       
+       public boolean isStatusValid() {
+               if ( this.status == DmaapObject_Status.VALID ) {
+                       return true;
+               }
+               return false;
+       }
+       
+       /*
+        * TODO: get this working so arrays and sub-class within an Object can be logged
+        * 
+       public String toString() {
+                       return classToString( this );
+       }
+       
+       private String classToString( Object obj ) {
+               Field[] fields = obj.getClass().getDeclaredFields();
+               StringBuilder res = new StringBuilder( "{");
+               boolean first = true;
+               for ( Field field: fields ) {
+                       logger.info( field.getName() + " toString=" + field.toString() + " toGenericString=" + field.toGenericString());
+                       if ( first ) {
+                               first = false;
+                       } else {
+                               res.append( ", ");
+                       }
+
+
+                       field.setAccessible(true);  // avoid IllegalAccessException
+
+                       
+                       Class<?> t = field.getType();
+                       
+                       if ( t == String.class ) {
+                               res.append( "\"" ).append( field.getName() ).append( "\": \"");
+       
+                               try {
+                                       res.append(field.get(this));
+                               } catch ( IllegalAccessException iae) {
+                                       res.append( "UNK(iae)");
+                               } catch (IllegalArgumentException iae2 ) {
+                                       res.append( "UNK(iae2)");
+                               } catch ( NullPointerException npe ) {
+                                       res.append( "UNK(npe)");
+                               } catch ( ExceptionInInitializerError eie ) {
+                                       res.append( "UNK(eie)");
+                               }
+                               res.append( "\"");
+                       } else if ( t == ArrayList.class ){
+                               res.append( "[");
+                               res.append( classToString( field ));
+                               res.append( "]");
+                               
+                       }
+               }
+               res.append( "}");
+               return( res.toString());
+       
+               
+       }
+       */
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/Feed.java b/src/main/java/org/onap/dmaap/dbcapi/model/Feed.java
new file mode 100644 (file)
index 0000000..9f7b3fc
--- /dev/null
@@ -0,0 +1,299 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.json.simple.*;
+import org.json.simple.parser.*;
+import org.onap.dmaap.dbcapi.service.DmaapService;
+
+@XmlRootElement
+public class Feed extends DmaapObject {
+               
+               private String feedId;
+
+               private String feedName;
+               private String feedVersion;
+               private String feedDescription;
+               private String owner;
+               private String asprClassification;
+               private String publishURL;
+               private String subscribeURL;
+               private boolean suspended;
+               private String logURL;
+               private String formatUuid;
+
+               private ArrayList<DR_Pub> pubs;
+               private ArrayList<DR_Sub> subs; 
+
+               
+
+               public boolean isSuspended() {
+                       return suspended;
+               }
+
+               public void setSuspended(boolean suspended) {
+                       this.suspended = suspended;
+               }
+
+               public String getSubscribeURL() {
+                       return subscribeURL;
+               }
+
+               public void setSubscribeURL(String subscribeURL) {
+                       this.subscribeURL = subscribeURL;
+               }
+
+
+               
+               public Feed() {
+                       this.pubs = new ArrayList<DR_Pub>();
+                       this.subs = new ArrayList<DR_Sub>();
+                       this.setStatus( DmaapObject_Status.EMPTY );
+                       
+               }
+               
+               public  Feed( String name,
+                                       String version,
+                                       String description,
+                                       String owner,
+                                       String aspr
+                                        ) {
+                       this.feedName = name;
+                       this.feedVersion = version;
+                       this.feedDescription = description;
+                       this.owner = owner;
+                       this.asprClassification = aspr;
+                       this.pubs = new ArrayList<DR_Pub>();
+                       this.subs = new ArrayList<DR_Sub>();
+                       this.setStatus( DmaapObject_Status.NEW );
+                       
+               }
+               
+               // expects a String in JSON format, with known fields to populate Feed object
+               public Feed ( String json ) {
+                       JSONParser parser = new JSONParser();
+                       JSONObject jsonObj;
+                       
+                       try {
+                               jsonObj = (JSONObject) parser.parse( json );
+                       } catch ( ParseException pe ) {
+                   logger.error( "Error parsing provisioning data: " + json );
+                   this.setStatus( DmaapObject_Status.INVALID );
+                   return;
+               }
+                       this.setFeedName( (String) jsonObj.get("name"));
+
+
+                       this.setFeedVersion( (String) jsonObj.get("version"));
+                       this.setFeedDescription( (String) jsonObj.get("description"));
+                       this.setOwner( (String) jsonObj.get("publisher"));
+
+                       this.setSuspended( (boolean) jsonObj.get("suspend"));
+                       JSONObject links = (JSONObject) jsonObj.get("links");
+                       String url = (String) links.get("publish");
+                       this.setPublishURL( url );
+                       this.setFeedId( url.substring( url.lastIndexOf('/')+1, url.length() ));
+                       logger.info( "feedid="+ this.getFeedId() );
+                       this.setSubscribeURL( (String) links.get("subscribe") );                                        
+                       this.setLogURL( (String) links.get("log") );
+                       JSONObject auth = (JSONObject) jsonObj.get("authorization");
+                       this.setAsprClassification( (String) auth.get("classification"));
+                       JSONArray pubs = (JSONArray) auth.get( "endpoint_ids");
+                       int i;
+                       ArrayList<DR_Pub> dr_pub = new ArrayList<DR_Pub>();
+                       this.subs = new ArrayList<DR_Sub>();
+
+                       for( i = 0; i < pubs.size(); i++ ) {
+                               JSONObject entry = (JSONObject) pubs.get(i);
+                               dr_pub.add(  new DR_Pub( "someLocation", 
+                                                                       (String) entry.get("id"),
+                                                                       (String) entry.get("password"),
+                                                                       this.getFeedId(),
+                                                                       this.getFeedId() + "." +  DR_Pub.nextKey() ));
+                       
+                       }
+                       this.setPubs( dr_pub );
+       
+                       this.setStatus( DmaapObject_Status.VALID );
+
+               }
+
+               public String getFeedId() {
+                       return feedId;
+               }
+
+               public void setFeedId(String feedId) {
+                       this.feedId = feedId;
+               }
+
+               public String getFeedName() {
+                       return feedName;
+               }
+
+               public void setFeedName(String feedName) {
+                       this.feedName = feedName;
+               }
+
+               public String getFeedVersion() {
+                       return feedVersion;
+               }
+
+               public void setFeedVersion(String feedVersion) {
+                       this.feedVersion = feedVersion;
+               }
+
+               public String getFeedDescription() {
+                       return feedDescription;
+               }
+
+               public void setFeedDescription(String feedDescription) {
+                       this.feedDescription = feedDescription;
+               }
+
+               public String getOwner() {
+                       return owner;
+               }
+
+               public void setOwner(String owner) {
+                       this.owner = owner;
+               }
+
+               public String getAsprClassification() {
+                       return asprClassification;
+               }
+
+               public void setAsprClassification(String asprClassification) {
+                       this.asprClassification = asprClassification;
+               }
+
+               public String getPublishURL() {
+                       return publishURL;
+               }
+
+               public void setPublishURL(String publishURL) {
+                       this.publishURL = publishURL;
+               }
+
+               public String getLogURL() {
+                       return logURL;
+               }
+
+               public void setLogURL(String logURL) {
+                       this.logURL = logURL;
+               }
+
+
+               
+               public String getFormatUuid() {
+                       return formatUuid;
+               }
+
+               public void setFormatUuid(String formatUuid) {
+                       this.formatUuid = formatUuid;
+               }
+
+               // returns the Feed object in JSON that conforms to DR Prov Server expectations
+               public String toProvJSON() {
+
+                       ArrayList<DR_Pub> pubs = this.getPubs();
+                       String postJSON = String.format("{\"name\": \"%s\", \"version\": \"%s\", \"description\": \"%s\", \"suspend\": %s, \"authorization\": { \"classification\": \"%s\", ",  
+                                       this.getFeedName(), 
+                                       this.getFeedVersion(),
+                                       this.getFeedDescription(),
+                                       this.isSuspended() ,
+                                       this.getAsprClassification()
+                                       );
+                       int i;
+                       postJSON += "\"endpoint_addrs\": [],\"endpoint_ids\": [";
+                       String comma = "";
+                       for( i = 0 ; i < pubs.size(); i++) {
+                               postJSON +=     String.format(" %s{\"id\": \"%s\",\"password\": \"%s\"}", 
+                                               comma,
+                                               pubs.get(i).getUsername(),
+                                               pubs.get(i).getUserpwd()
+                                               ) ;
+                               comma = ",";
+                       }
+                       postJSON += "]}}";
+                       
+                       logger.info( "postJSON=" + postJSON);           
+                       return postJSON;
+               }
+               
+               public ArrayList<DR_Pub> getPubs() {
+                       return pubs;
+               }
+
+               public void setPubs( ArrayList<DR_Pub> pubs) {
+                       this.pubs = pubs;
+               }
+
+               public ArrayList<DR_Sub> getSubs() {
+                       return subs;
+               }
+
+               public void setSubs( ArrayList<DR_Sub> subs) {
+                       this.subs = subs;
+               }
+
+               public byte[] getBytes() {
+                       return toProvJSON().getBytes(StandardCharsets.UTF_8);
+               }
+               
+               public static String getSubProvURL( String feedId ) {
+                       String ret = new String();
+                       ret = new DmaapService().getDmaap().getDrProvUrl() + "/subscribe/" + feedId ;
+                       return ret;
+               }
+
+               @Override
+               public String toString() {
+                       String rc = String.format ( "Feed: {feedId=%s feedName=%s feedVersion=%s feedDescription=%s owner=%s asprClassification=%s publishURL=%s subscriberURL=%s suspended=%s logURL=%s formatUuid=%s}",
+                                       feedId,
+                                       feedName,
+                                       feedVersion,
+                                       feedDescription,
+                                       owner,
+                                       asprClassification,
+                                       publishURL,
+                                       subscribeURL,
+                                       suspended,
+                                       logURL,
+                                       formatUuid
+
+               
+                                       );
+
+                       for( DR_Pub pub: pubs) {
+                               rc += "\n" + pub.toString();
+                       }
+
+                       for( DR_Sub sub: subs ) {
+                               rc += "\n" + sub.toString();
+                       }
+                       return rc;
+               }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java b/src/main/java/org/onap/dmaap/dbcapi/model/MR_Client.java
new file mode 100644 (file)
index 0000000..dc43cc0
--- /dev/null
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+
+@XmlRootElement
+public class MR_Client extends DmaapObject {
+
+       private String dcaeLocationName;
+       private String  topicURL;
+       private String fqtn;
+       private String clientRole;
+       private String[] action;
+       private String mrClientId;
+       
+
+       public MR_Client() {
+               this.mrClientId = DatabaseClass.getNextClientId();
+               this.lastMod = new Date();
+               this.setLastMod();
+               debugLogger.debug( "MR_Client constructor " + this.lastMod );
+                       
+       }
+       
+       public MR_Client( String dLN,
+                                       String f,
+                                       String cR,
+                                       String[] a ) {
+               this.dcaeLocationName = dLN;
+               this.fqtn = f;
+               this.clientRole = cR;
+               int i = 0;
+               
+               if ( this.action == null ) {
+                       this.action = new String[a.length];
+               }
+               for( String aa : a ) {
+                       this.action[i++] = new String( aa );
+               }
+               this.setStatus( DmaapObject_Status.NEW );
+               this.mrClientId = DatabaseClass.getNextClientId();
+               this.setLastMod();
+               debugLogger.debug( "MR_Client constructor w initialization " + this.lastMod );
+       }
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+
+       public String getFqtn() {
+               return fqtn;
+       }
+
+       public void setFqtn(String fqtn) {
+               this.fqtn = fqtn;
+       }
+
+       public String getClientRole() {
+               return clientRole;
+       }
+
+       public void setClientRole(String clientRole) {
+               this.clientRole = clientRole;
+       }
+
+       public String[] getAction() {
+               return action;
+       }
+
+       public void setAction(String[] action) {
+               this.action = action;
+       }
+
+       public String getMrClientId() {
+               return mrClientId;
+       }
+
+       public void setMrClientId(String mrClientId) {
+               this.mrClientId = mrClientId;
+       }
+
+
+
+       public String getTopicURL() {
+               return topicURL;
+       }
+
+       public void setTopicURL(String topicURL) {
+               this.topicURL = topicURL;
+       }
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/MR_Cluster.java b/src/main/java/org/onap/dmaap/dbcapi/model/MR_Cluster.java
new file mode 100644 (file)
index 0000000..d8ebc8b
--- /dev/null
@@ -0,0 +1,129 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+
+@XmlRootElement
+public class MR_Cluster extends DmaapObject {
+
+       private String dcaeLocationName;
+       private String fqdn;
+       private String[] hosts;
+       //private       DmaapTimestamp lastMod;
+       private String  topicProtocol;
+       private String  topicPort;
+
+       
+       // TODO: make this a system property
+       private static String defaultTopicProtocol = "https";
+       private static String defaultTopicPort = "3905";
+       
+
+
+
+       public MR_Cluster() {
+               this.topicProtocol = defaultTopicProtocol;
+               this.topicPort = defaultTopicPort;
+               this.lastMod = new Date();
+
+               debugLogger.debug( "MR_Cluster constructor " + this.lastMod );
+               
+       }
+       
+       public MR_Cluster( String dLN,
+                                               String f,
+                                               String a,
+                                               String[] h ) {
+               this.dcaeLocationName = dLN;
+               this.fqdn = f;
+               this.hosts[0] = h[0];
+               this.hosts[1] = h[1];
+               this.hosts[2] = h[2];
+               this.topicProtocol = defaultTopicProtocol;
+               this.topicPort = defaultTopicPort;
+
+               debugLogger.debug( "MR_Cluster constructor w initialization complete" + this.lastMod );
+       }
+
+       public String getDcaeLocationName() {
+               return dcaeLocationName;
+       }
+
+       public void setDcaeLocationName(String dcaeLocationName) {
+               this.dcaeLocationName = dcaeLocationName;
+       }
+
+       public String getFqdn() {
+               return fqdn;
+       }
+
+       public void setFqdn(String fqdn) {
+               this.fqdn = fqdn;
+       }
+
+       public String[] getHosts() {
+               return hosts;
+       }
+
+       public void setHosts(String[] hosts) {
+               this.hosts = hosts;
+       }
+
+       public String getTopicProtocol() {
+               return topicProtocol;
+       }
+
+       public void setTopicProtocol(String topicProtocol) {
+               this.topicProtocol = topicProtocol;
+       }
+
+       public String getTopicPort() {
+               return topicPort;
+       }
+
+       public void setTopicPort(String topicPort) {
+               this.topicPort = topicPort;
+       }
+
+
+
+       public String genTopicURL(String overideFqdn, String topic) {
+
+               StringBuilder str = new StringBuilder( topicProtocol );
+               str.append("://")
+                       .append( overideFqdn != null ? overideFqdn : fqdn)
+                       .append(":")
+                       .append(topicPort)
+                       .append("/events/")
+                       .append(topic);
+               
+               return str.toString();
+
+
+       }
+
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/MirrorMaker.java b/src/main/java/org/onap/dmaap/dbcapi/model/MirrorMaker.java
new file mode 100644 (file)
index 0000000..b1a2d3c
--- /dev/null
@@ -0,0 +1,203 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.service.MirrorMakerService;
+
+public class MirrorMaker extends DmaapObject {
+       static final Logger logger = Logger.getLogger(MirrorMaker.class);
+
+       private String  sourceCluster;
+       private String  targetCluster;
+       private String  mmName;
+       private ArrayList<String> topics;  //re-using this var name for backwards DB compatibility
+       
+       private Set<ReplicationVector> vectors;
+
+       
+       public MirrorMaker(){
+               
+       }
+
+       public MirrorMaker(String source, String target) {
+               sourceCluster = source;
+               targetCluster = target;
+               mmName = genKey(source, target);
+               vectors = new HashSet<ReplicationVector>();
+               topics = new ArrayList<String>();
+
+       }
+       
+       public String getMmName() {
+               return mmName;
+       }
+
+       public void setMmName(String mmName) {
+               this.mmName = mmName;
+       }
+
+       
+       public void addVector( String fqtn, String source, String target ) {
+               logger.info( "addVector: fqtn=" + fqtn + " source=" + source + " target=" + target );
+               if ( ! sourceCluster.equals( source ) ){
+                       errorLogger.error( DmaapbcLogMessageEnum.MM_CIRCULAR_REF,  source,  sourceCluster );
+               }
+               vectors.add(new ReplicationVector( fqtn, source, target ));
+       }
+       
+       public void delVector( String fqtn, String source, String target ) {
+               vectors.remove(new ReplicationVector( fqtn, source, target));
+       }
+
+       
+       
+       public String toJSON() {
+               StringBuilder str = new StringBuilder( "{ \"source\": " + sourceCluster + ",\"topics\": ["  );
+               int numTargets = 0;
+               for (ReplicationVector rv: vectors) {
+                       if ( numTargets > 0 ) {
+                               str.append( ",");
+                       }
+                       str.append( " \"target\": " + rv.getTargetCluster() + ", \"topic\": " + rv.getFqtn());
+                       numTargets++;
+               }
+               str.append( "] }" );
+               
+               return str.toString();
+       }
+               
+       
+       // returns the JSON for MM message containing which Topics to replicate
+       /* 
+        * example:
+        * 
+                       {
+                           "messageID":"12349",
+                           "updateWhiteList":
+                               {
+                                   "name":"Global1ToGlobal3",
+                                   "whitelist":"org.openecomp.dcae.topic1,org.openecomp.dcae.topic2"
+                               }
+                       }   
+        */
+       public String updateWhiteList() {
+               StringBuilder str = new StringBuilder( "{ \"messageID\": \"" + MirrorMakerService.genTransactionId() + "\", \"updateWhiteList\": {"  );
+               str.append( " \"name\": \"" + this.getMmName() + "\", \"whitelist\": \"" );
+               int numTargets = 0;
+
+               //for (ReplicationVector rv: vectors) {
+               for (String rv: topics) {
+                       if ( numTargets > 0 ) {
+                               str.append( ",");
+                       }
+                       //str.append(  rv.getFqtn() );
+                       str.append( rv );
+                       numTargets++;
+               }
+               str.append( "\" } }" );
+               
+               return str.toString();
+       }
+       
+       // returns the JSON for MM message indicating that a MM agent is needed between two clusters
+       // example:
+       /*
+        * 
+                       {
+                           "messageID":"12345"
+                           "createMirrorMaker":
+                               {
+                                   "name":"Global1ToGlobal2",
+                                   "consumer":"192.168.0.1:2181",
+                                   "producer":"192.168.0.2:9092"
+                               }
+                       }
+        */
+       public String createMirrorMaker() {
+               StringBuilder str = new StringBuilder( "{ \"messageID\": \"" + MirrorMakerService.genTransactionId() + "\", \"createMirrorMaker\": {"  );
+               str.append( " \"name\": \"" + this.getMmName() + "\", " );
+               str.append( " \"consumer\": \"" + this.sourceCluster + ":2181\", " );
+               str.append( " \"producer\": \"" + this.targetCluster + ":9092\" ");
+               
+               str.append( " } }" );
+               
+               return str.toString();
+       }
+
+
+       public String getSourceCluster() {
+               return sourceCluster;
+       }
+
+       public void setSourceCluster(String sourceCluster) {
+               this.sourceCluster = sourceCluster;
+       }
+
+       public String getTargetCluster() {
+               return targetCluster;
+       }
+
+       public void setTargetCluster(String targetCluster) {
+               this.targetCluster = targetCluster;
+       }
+
+
+       public Set<ReplicationVector> getVectors() {
+               return vectors;
+       }
+
+       public void setVectors(Set<ReplicationVector> vectors) {
+               this.vectors = vectors;
+       }
+       public ArrayList<String> getTopics() {
+               return topics;
+       }
+
+       //public void setVectors(Set<ReplicationVector> vectors) {
+       public void setTopics(ArrayList<String> topics) {
+               this.topics = topics;
+       }
+
+
+       public static String genKey( String s, String t) {
+               StringBuilder str = new StringBuilder();
+               str.append(s);
+               str.append("-To-");
+               str.append(t);
+               return str.toString();
+       }
+
+
+       
+       public void addTopic( String topic ) {
+               topics.add(topic);
+       }
+       
+       public int getTopicCount() {
+               return topics.size();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/ReplicationType.java b/src/main/java/org/onap/dmaap/dbcapi/model/ReplicationType.java
new file mode 100644 (file)
index 0000000..49b93a6
--- /dev/null
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+
+@XmlRootElement
+public enum ReplicationType {
+       REPLICATION_NOT_SPECIFIED(0),
+       REPLICATION_NONE(1),
+       REPLICATION_EDGE_TO_CENTRAL(10),
+       REPLICATION_EDGE_TO_CENTRAL_TO_GLOBAL(110),
+       REPLICATION_CENTRAL_TO_EDGE(20),
+       REPLICATION_CENTRAL_TO_GLOBAL(21),
+       REPLICATION_GLOBAL_TO_CENTRAL(30),
+       REPLICATION_GLOBAL_TO_CENTRAL_TO_EDGE(120);
+
+    private int value;
+    private static Map map = new HashMap<>();
+
+    private ReplicationType(int value) {
+        this.value = value;
+    }
+
+    static {
+        for (ReplicationType repType : ReplicationType.values()) {
+            map.put(repType.value, repType);
+        }
+    }
+
+    public static ReplicationType valueOf(int repType) {
+        return (ReplicationType) map.get(repType);
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    static public ReplicationType Validator( String input ){
+   
+               ReplicationType t;
+               try {
+                       t = ReplicationType.valueOf( input );
+               } catch ( IllegalArgumentException e ) {
+                       t = REPLICATION_NOT_SPECIFIED;
+               }
+               return t;
+       }
+
+       public boolean involvesGlobal() {
+               if ( this.compareTo(REPLICATION_CENTRAL_TO_GLOBAL) == 0 ||
+                               this.compareTo(REPLICATION_GLOBAL_TO_CENTRAL) == 0 ||
+                               this.compareTo(REPLICATION_EDGE_TO_CENTRAL_TO_GLOBAL) == 0 ||
+                               this.compareTo(REPLICATION_GLOBAL_TO_CENTRAL_TO_EDGE) == 0) {
+                       return true;
+               }
+               return false;
+       }
+
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/ReplicationVector.java b/src/main/java/org/onap/dmaap/dbcapi/model/ReplicationVector.java
new file mode 100644 (file)
index 0000000..add3998
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+public class ReplicationVector {
+       
+       public enum ReplicationVector_Status {
+               EMPTY,
+               NEW,
+               STAGED,
+               VALID,
+               INVALID,
+               INVALID_DUP,
+               DELETED
+       }
+
+       String  fqtn;
+       String  sourceCluster;
+       String  targetCluster;
+       ReplicationVector_Status status;
+       
+       public ReplicationVector(){
+               
+       }
+       
+       public ReplicationVector(String fqtn, String sourceCluster,
+                       String targetCluster) {
+               super();
+               this.fqtn = fqtn;
+               this.sourceCluster = sourceCluster;
+               this.targetCluster = targetCluster;
+       }
+
+       public String getFqtn() {
+               return fqtn;
+       }
+
+       public void setFqtn(String fqtn) {
+               this.fqtn = fqtn;
+       }
+
+       public String getSourceCluster() {
+               return sourceCluster;
+       }
+
+       public void setSourceCluster(String sourceCluster) {
+               this.sourceCluster = sourceCluster;
+       }
+
+       public String getTargetCluster() {
+               return targetCluster;
+       }
+
+       public void setTargetCluster(String targetCluster) {
+               this.targetCluster = targetCluster;
+       }
+       
+       public int hashCode() {
+               StringBuilder tmp = new StringBuilder( this.fqtn );
+               tmp.append(this.sourceCluster);
+               tmp.append(this.targetCluster);
+               
+               return tmp.toString().hashCode();
+       }
+       private static boolean xeq(String s1, String s2) {
+               if (s1 == null) {
+                       return(s2 == null);
+               } else {
+                       return(s1.equals(s2));
+               }
+       }
+       public boolean equals(Object o) {
+               if (o == this) {
+                       return(true);
+               }
+               if (!(o instanceof ReplicationVector)) {
+                       return(false);
+               }
+               ReplicationVector x = (ReplicationVector)o;
+               return(xeq(fqtn, x.fqtn) && xeq(sourceCluster, x.sourceCluster) && xeq(targetCluster, x.targetCluster));
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java b/src/main/java/org/onap/dmaap/dbcapi/model/Topic.java
new file mode 100644 (file)
index 0000000..712c2eb
--- /dev/null
@@ -0,0 +1,193 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.model;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.onap.dmaap.dbcapi.service.DmaapService;
+
+
+@XmlRootElement
+public class Topic extends DmaapObject  {
+
+       private String fqtn;
+       private String topicName;
+       private String  topicDescription;
+       private String  tnxEnabled;
+       private String  owner;
+       private String  formatUuid;
+       private ReplicationType replicationCase;  
+       private String  globalMrURL;            // optional: URL of global MR to replicate to/from
+
+       private ArrayList<MR_Client> clients;
+
+
+       
+       private static Dmaap dmaap = new DmaapService().getDmaap();
+       
+       //
+       // utility function to generate the FQTN of a topic
+       public static String genFqtn(  String name ) {
+               CharSequence signal = ".";
+               String ret;
+               if ( name.contains( signal )) {
+                       // presence of a dot indicates the name is already fully qualified
+                       ret = name;
+               } else {
+                       ret = dmaap.getTopicNsRoot() + "." + dmaap.getDmaapName() + "." + name;
+               }
+               return ret;
+       }
+
+
+
+       public Topic() {
+               super();
+               this.clients = new ArrayList<MR_Client>();
+               this.lastMod = new Date();
+               this.replicationCase = ReplicationType.Validator("none");
+               this.setLastMod();
+               logger.debug( "Topic constructor " + this.lastMod );
+       }
+       public Topic(String fqtn, String topicName, String topicDescription,
+                        String tnxEnabled, String owner) {
+               super();
+               this.fqtn = fqtn;
+               this.topicName = topicName;
+               this.topicDescription = topicDescription;
+               //this.dcaeLocationName = dcaeLocationName;
+               this.tnxEnabled = tnxEnabled;
+               this.owner = owner;
+               this.setLastMod();
+               this.setStatus( DmaapObject_Status.NEW );
+               this.replicationCase = ReplicationType.Validator("none");
+               logger.debug( "Topic constructor " + this.getLastMod() );
+       }
+       public String getFqtn() {
+               return fqtn;
+       }
+       public void setFqtn(String fqtn) {
+               this.fqtn = fqtn;
+       }
+       public String getTopicName() {
+               return topicName;
+       }
+       public void setTopicName(String topicName) {
+               this.topicName = topicName;
+       }
+       public String getTopicDescription() {
+               return topicDescription;
+       }
+       public void setTopicDescription(String topicDescription) {
+               this.topicDescription = topicDescription;
+       }
+
+       public String getTnxEnabled() {
+               return tnxEnabled;
+       }
+       public void setTnxEnabled(String tnxEnabled) {
+               this.tnxEnabled = tnxEnabled;
+       }
+       public String getOwner() {
+               return owner;
+       }
+       public void setOwner(String owner) {
+               this.owner = owner;
+       }
+
+
+       public void setClients(ArrayList<MR_Client> clients) {
+               this.clients = clients;
+       }
+
+       public ArrayList<MR_Client> getClients() {
+               return clients;
+       }
+
+       public int getNumClients() {
+               if ( this.clients == null ) {
+                       return 0;
+               }
+               return this.clients.size();
+       }
+
+
+
+
+       public String getFormatUuid() {
+               return formatUuid;
+       }
+
+
+
+       public void setFormatUuid(String formatUuid) {
+               this.formatUuid = formatUuid;
+       }
+
+
+       public ReplicationType getReplicationCase() {
+               return replicationCase;
+       }
+
+
+
+       /*
+       public void setReplicationCase(String val) {
+               this.replicationCase = ReplicationType.Validator(val);
+       }
+       */
+       
+       public void setReplicationCase(ReplicationType t) {
+               this.replicationCase = t;
+       }
+
+
+       public String getGlobalMrURL() {
+               return globalMrURL;
+       }
+
+
+
+       public void setGlobalMrURL(String globalMrURL) {
+               this.globalMrURL = globalMrURL;
+       }
+
+
+
+       public String toProvJSON() {
+               StringBuilder str = new StringBuilder();
+               str.append("{ \"topicName\": \"");
+               str.append( this.getFqtn() );
+               str.append( "\", \"topicDescription\": \"");
+               str.append( this.getTopicDescription());
+               str.append( "\", \"partitionCount\": \"2\", \"replicationCount\": \"1\" } ");
+               logger.info( str.toString() );
+               return str.toString();
+       }
+       
+       public byte[] getBytes() {
+               return toProvJSON().getBytes(StandardCharsets.UTF_8);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/Authorization.java b/src/main/java/org/onap/dmaap/dbcapi/resources/Authorization.java
new file mode 100644 (file)
index 0000000..e8b05c6
--- /dev/null
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.resources;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+import javax.ws.rs.NameBinding;
+
+// @Authorization annotation
+@NameBinding
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Authorization {
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java b/src/main/java/org/onap/dmaap/dbcapi/resources/AuthorizationFilter.java
new file mode 100644 (file)
index 0000000..d990b09
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import java.io.IOException;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+
+import org.onap.dmaap.dbcapi.aaf.authentication.AuthenticationErrorException;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+
+@Authorization
+public class AuthorizationFilter implements ContainerRequestFilter   {
+       
+
+       
+       @Override
+       public void filter(ContainerRequestContext requestContext)
+                       throws IOException {
+
+               ApiService apiResp = new ApiService()
+                       .setAuth( requestContext.getHeaderString("Authorization") )
+                       .setUriPath(requestContext.getUriInfo().getPath())
+                       .setHttpMethod( requestContext.getMethod() )
+                       .setRequestId( requestContext.getHeaderString("X-ECOMP-RequestID") );
+               
+               try {
+                       apiResp.checkAuthorization();
+               } catch ( AuthenticationErrorException ae ) {
+                       requestContext.abortWith( apiResp.unauthorized( apiResp.getErr().getMessage() ) );
+                       return ;
+               } catch ( Exception e ) {
+                       requestContext.abortWith( apiResp.unavailable() ); 
+                       return;
+               }
+               
+
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/BridgeResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/BridgeResource.java
new file mode 100644 (file)
index 0000000..5003801
--- /dev/null
@@ -0,0 +1,116 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.aaf.authentication.AuthenticationErrorException;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.BrTopic;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.model.MirrorMaker;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.MirrorMakerService;
+
+@Path("/bridge")
+@Api( value= "bridge", description = "Endpoint for retreiving MR Bridge metrics" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class BridgeResource extends BaseLoggingClass {
+       
+       private MirrorMakerService mmService = new MirrorMakerService();
+
+       @GET
+       @ApiOperation( value = "return BrTopic details", 
+       notes = "Returns array of  `BrTopic` objects.", 
+       response = BrTopic.class)
+@ApiResponses( value = {
+    @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+    @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+})
+       public Response getBridgedTopics(@QueryParam("source") String source,
+                                                                       @QueryParam("target") String target){
+               ApiService check = new ApiService();
+
+               BrTopic brTopic = new BrTopic();
+               
+               logger.info( "getBridgeTopics():" + " source=" + source + ", target=" + target);
+//             System.out.println("getBridgedTopics() " + "source=" + source + ", target=" + target );
+               if (source != null && target != null) {         // get topics between 2 bridged locations
+                       brTopic.setBrSource(source);
+                       brTopic.setBrTarget(target);
+                       MirrorMaker mm = mmService.getMirrorMaker(source, target);
+                       if ( mm != null ) {
+                               brTopic.setTopicCount( mm.getTopicCount() );
+                       } 
+
+                       logger.info( "topicCount [2 locations]: " + brTopic.getTopicCount() );
+               }
+               else if (source == null && target == null ) {
+                       List<String> mmList = mmService.getAllMirrorMakers();
+                       brTopic.setBrSource("all");
+                       brTopic.setBrTarget("all");
+                       int totCnt = 0;
+                       for( String key: mmList ) {
+                               int mCnt = 0;
+                               MirrorMaker mm = mmService.getMirrorMaker(key);
+                               if ( mm != null ) {
+                                       mCnt = mm.getTopicCount();
+                               }
+                               logger.info( "Count for "+ key + ": " + mCnt);
+                               totCnt += mCnt;
+                       }
+                       
+                       logger.info( "topicCount [all locations]: " + totCnt );
+                       brTopic.setTopicCount(totCnt);
+
+               }
+               else {
+
+                       logger.error( "source or target is missing");
+                       check.setCode(Status.BAD_REQUEST.getStatusCode());
+                       check.setMessage("Either 2 locations or no location must be provided");
+                       return check.error();
+               }
+               return check.success(brTopic);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_NodeResource.java
new file mode 100644 (file)
index 0000000..8091ac3
--- /dev/null
@@ -0,0 +1,183 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Node;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.DR_NodeService;
+
+@Path("/dr_nodes")
+@Api( value= "dr_nodes", description = "Endpoint for a Data Router Node server" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class DR_NodeResource extends BaseLoggingClass {
+
+       DR_NodeService dr_nodeService = new DR_NodeService();
+       
+       @GET
+       @ApiOperation( value = "return DR_Node details", 
+       notes = "Returns array of `DR_Node` object array.  Need to add filter by dcaeLocation.", 
+       response = DR_Node.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Node.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getDr_Nodes() {
+               ApiService resp = new ApiService();
+
+               List<DR_Node> nodes = dr_nodeService.getAllDr_Nodes();
+
+               GenericEntity<List<DR_Node>> list = new GenericEntity<List<DR_Node>>(nodes) {
+        };
+        return resp.success(list);
+       }
+       
+       @POST
+       @ApiOperation( value = "return DR_Node details", 
+       notes = "create a `DR_Node` in a *dcaeLocation*.  Note that multiple `DR_Node`s may exist in the same `dcaeLocation`.", 
+       response = DR_Node.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Node.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response addDr_Node( 
+                       DR_Node node
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "dcaeLocation", node.getDcaeLocationName(), "");
+                       resp.required( "fqdn", node.getFqdn(), "");
+               } catch ( RequiredFieldException rfe ) {
+                       resp.setCode(Status.BAD_REQUEST.getStatusCode());
+                       resp.setMessage("missing required field");
+                       resp.setFields("dcaeLocation, fqdn");
+                       
+                       return resp.error();
+               }
+               DR_Node nNode = dr_nodeService.addDr_Node(node, resp.getErr());
+               if ( resp.getErr().is2xx()) {
+                       return resp.success(nNode);
+               }
+               return resp.error();
+       }
+       
+       @PUT
+       @ApiOperation( value = "return DR_Node details", 
+       notes = "Update a single `DR_Node` object.", 
+       response = DR_Node.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Node.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{fqdn}")
+       public Response updateDr_Node( 
+                       @PathParam("fqdn") String name, 
+                       DR_Node node
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "dcaeLocation", name, "");
+                       resp.required( "fqdn", node.getFqdn(), "");
+               } catch ( RequiredFieldException rfe ) {
+                       return resp.error();    
+               }
+               node.setFqdn(name);
+               DR_Node nNode = dr_nodeService.updateDr_Node(node, resp.getErr());
+               if ( resp.getErr().is2xx()) {
+                       return resp.success(nNode);
+               }
+               return resp.error();
+       }
+       
+       @DELETE
+       @ApiOperation( value = "No Content", 
+       notes = "Delete a single `DR_Node` object.", 
+       response = DR_Node.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Node.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{fqdn}")
+       public Response deleteDr_Node( 
+                       @PathParam("fqdn") String name
+                       ){
+
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "fqdn", name, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               dr_nodeService.removeDr_Node(name, resp.getErr());
+               if ( resp.getErr().is2xx() ) {
+                       return resp.success(Status.NO_CONTENT.getStatusCode(), null);
+               }
+               return resp.error();
+       }
+
+       @GET
+       @ApiOperation( value = "return DR_Node details", 
+       notes = "Retrieve a single `DR_Node` object.", 
+       response = DR_Node.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Node.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{fqdn}")
+       public Response get( 
+                       @PathParam("fqdn") String name
+                       ) {
+               ApiService resp = new ApiService();
+
+               DR_Node nNode = dr_nodeService.getDr_Node( name, resp.getErr() );
+               if ( resp.getErr().is2xx() ) {
+                       return resp.success(nNode);
+               }
+               return resp.error();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_PubResource.java
new file mode 100644 (file)
index 0000000..06319de
--- /dev/null
@@ -0,0 +1,241 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.Feed;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.DR_PubService;
+import org.onap.dmaap.dbcapi.service.FeedService;
+
+
+@Path("/dr_pubs")
+@Api( value= "dr_pubs", description = "Endpoint for a Data Router client that implements a Publisher" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class DR_PubResource extends BaseLoggingClass {
+
+       DR_PubService dr_pubService = new DR_PubService();
+       
+       @GET
+       @ApiOperation( value = "return DR_Pub details", 
+       notes = "Returns array of  `DR_Pub` objects.  Add filter for feedId.", 
+       response = DR_Pub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public  Response getDr_Pubs() {
+               ApiService resp = new ApiService();
+
+               logger.info( "Entry: GET /dr_pubs");
+               List<DR_Pub> pubs = dr_pubService.getAllDr_Pubs();
+
+               GenericEntity<List<DR_Pub>> list = new GenericEntity<List<DR_Pub>>(pubs) {
+        };
+        return resp.success(list);
+       }
+       
+       @POST
+       @ApiOperation( value = "return DR_Pub details", 
+       notes = "create a DR Publisher in the specified environment.", 
+       response = DR_Pub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response addDr_Pub( 
+                       DR_Pub pub
+                       ) {
+               ApiService resp = new ApiService();
+
+               logger.info( "Entry: POST /dr_pubs");
+
+               try {
+                       resp.required( "feedId", pub.getFeedId(), "");
+                       resp.required( "dcaeLocationName", pub.getDcaeLocationName(), "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.getErr().toString() );
+                       return resp.error();    
+               }
+
+               FeedService feeds = new FeedService();
+               Feed fnew = feeds.getFeed( pub.getFeedId(), resp.getErr() );
+               if ( fnew == null ) {
+                       logger.info( "Specified feed " + pub.getFeedId() + " not known to Bus Controller");     
+                       return resp.error();    
+               }
+
+               ArrayList<DR_Pub> pubs = fnew.getPubs();
+               logger.info( "num existing pubs before = " + pubs.size() );
+               
+               logger.info( "update feed");
+               pub.setNextPubId();
+               if ( pub.getUsername() == null ) {
+                       pub.setRandomUserName();
+               }
+               if ( pub.getUserpwd() == null ) {
+                       pub.setRandomPassword();
+               }
+               pubs.add( pub );
+               fnew.setPubs(pubs);
+               fnew = feeds.updateFeed( fnew, resp.getErr() ); 
+               
+               if ( ! resp.getErr().is2xx()) { 
+                       return resp.error();                    
+               }
+               pubs = fnew.getPubs();
+               logger.info( "num existing pubs after = " + pubs.size() );
+               
+               DR_Pub pnew = dr_pubService.getDr_Pub(pub.getPubId(), resp.getErr());
+               return resp.success(Status.CREATED.getStatusCode(), pnew);
+       }
+       
+       @PUT
+       @ApiOperation( value = "return DR_Pub details", 
+       notes = "update a DR Publisher in the specified environment.  Update a `DR_Pub` object by pubId", 
+       response = DR_Pub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{pubId}")
+       public Response updateDr_Pub( 
+                       @PathParam("pubId") String name, 
+                       DR_Pub pub
+                       ) {
+               ApiService resp = new ApiService();
+
+               logger.info( "Entry: PUT /dr_pubs");
+               pub.setPubId(name);
+               DR_Pub res = dr_pubService.updateDr_Pub(pub);
+               return resp.success(res);
+       }
+       
+       @DELETE
+       @ApiOperation( value = "return DR_Pub details", 
+       notes = "delete a DR Publisher in the specified environment. Delete a `DR_Pub` object by pubId", 
+       response = DR_Pub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{pubId}")
+       public Response deleteDr_Pub( 
+                       @PathParam("pubId") String id
+                       ){
+
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "pubId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       return resp.error();
+               }
+
+               DR_Pub pub =  dr_pubService.getDr_Pub( id, resp.getErr() );
+               if ( ! resp.getErr().is2xx()) { 
+                       return resp.error();                                    
+               }
+               FeedService feeds = new FeedService();
+               Feed fnew = feeds.getFeed( pub.getFeedId(), resp.getErr() );
+               if ( fnew == null ) {
+                       logger.info( "Specified feed " + pub.getFeedId() + " not known to Bus Controller");     
+                       return resp.error();
+               }
+               ArrayList<DR_Pub> pubs = fnew.getPubs();
+               if ( pubs.size() == 1 ) {
+                       resp.setCode(Status.BAD_REQUEST.getStatusCode());
+                       resp.setMessage( "Can't delete the last publisher of a feed");
+                       return resp.error();    
+               }
+               
+               for( Iterator<DR_Pub> i = pubs.iterator(); i.hasNext(); ) {
+                       DR_Pub listItem = i.next();
+                       if ( listItem.getPubId().equals(id)) {
+                               pubs.remove( listItem );
+                       }
+               }
+               fnew.setPubs(pubs);
+               fnew = feeds.updateFeed( fnew, resp.getErr() );
+               if ( ! resp.getErr().is2xx()) { 
+                       return resp.error();                    
+               }
+               
+               dr_pubService.removeDr_Pub(id, resp.getErr() );
+               if ( ! resp.getErr().is2xx()) { 
+                       return resp.error();            
+               }
+               return resp.success(Status.NO_CONTENT.getStatusCode(), null);
+       }
+
+       @GET
+       @ApiOperation( value = "return DR_Pub details", 
+       notes = "returns a DR Publisher in the specified environment. Gets a `DR_Pub` object by pubId", 
+       response = DR_Pub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{pubId}")
+       public Response get( 
+                       @PathParam("pubId") String id
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "feedId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       return resp.error();    
+               }
+
+               DR_Pub pub =  dr_pubService.getDr_Pub( id, resp.getErr() );
+               if ( ! resp.getErr().is2xx()) { 
+                       resp.getErr();                  
+               }
+               return resp.success(Status.OK.getStatusCode(), pub);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DR_SubResource.java
new file mode 100644 (file)
index 0000000..03a8e2f
--- /dev/null
@@ -0,0 +1,227 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.DR_Sub;
+import org.onap.dmaap.dbcapi.model.Feed;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.DR_SubService;
+import org.onap.dmaap.dbcapi.service.FeedService;
+
+
+@Path("/dr_subs")
+@Api( value= "dr_subs", description = "Endpoint for a Data Router client that implements a Subscriber" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class DR_SubResource extends BaseLoggingClass {
+               
+       @GET
+       @ApiOperation( value = "return DR_Sub details", 
+       notes = "Returns array of  `DR_Sub` objects.  Add filter for feedId.", 
+       response = DR_Sub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getDr_Subs() {
+
+               ApiService resp = new ApiService();
+
+               DR_SubService dr_subService = new DR_SubService();
+               List<DR_Sub> subs = dr_subService.getAllDr_Subs();
+
+               GenericEntity<List<DR_Sub>> list = new GenericEntity<List<DR_Sub>>(subs) {
+        };
+        return resp.success(list);
+       }
+               
+       @POST
+       @ApiOperation( value = "return DR_Sub details", 
+       notes = "Create a  `DR_Sub` object.  ", 
+       response = DR_Sub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response addDr_Sub( 
+                       DR_Sub sub
+                       ) {
+       
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "feedId", sub.getFeedId(), "");
+                       resp.required( "dcaeLocationName", sub.getDcaeLocationName(), "");
+       
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               
+               FeedService feeds = new FeedService();
+               Feed fnew = feeds.getFeed( sub.getFeedId(), resp.getErr() );
+               if ( fnew == null ) {
+                       logger.warn( "Specified feed " + sub.getFeedId() + " not known to Bus Controller");
+                       resp.setCode(Status.NOT_FOUND.getStatusCode());
+                       return resp.error();
+               }
+
+               DR_SubService dr_subService = new DR_SubService( fnew.getSubscribeURL());
+               ArrayList<DR_Sub> subs = fnew.getSubs();
+               logger.info( "num existing subs before = " + subs.size() );
+               DR_Sub snew = dr_subService.addDr_Sub(sub, resp.getErr() );
+               if ( ! resp.getErr().is2xx() ) {
+                       return resp.error();
+               }
+               subs.add( snew );
+               logger.info( "num existing subs after = " + subs.size() );
+               
+               fnew.setSubs(subs);
+               logger.info( "update feed");
+               //feeds.updateFeed( fnew, err );                        
+               
+               return resp.success(Status.CREATED.getStatusCode(), snew);
+
+       }
+               
+       @PUT
+       @ApiOperation( value = "return DR_Sub details", 
+       notes = "Update a  `DR_Sub` object, selected by subId", 
+       response = DR_Sub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{subId}")
+       public Response updateDr_Sub( 
+                       @PathParam("subId") String name, 
+                       DR_Sub sub
+                       ) {
+
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "subId", name, "");
+                       resp.required( "feedId", sub.getFeedId(), "");
+                       resp.required( "dcaeLocationName", sub.getDcaeLocationName(), "");
+       
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();
+               }
+               FeedService feeds = new FeedService();
+               Feed fnew = feeds.getFeed( sub.getFeedId(), resp.getErr() );
+               if ( fnew == null ) {
+                       logger.warn( "Specified feed " + sub.getFeedId() + " not known to Bus Controller");
+                       return resp.error();
+               }
+               
+               DR_SubService dr_subService = new DR_SubService();
+               sub.setSubId(name);
+               DR_Sub nsub = dr_subService.updateDr_Sub(sub, resp.getErr() );
+               if ( nsub != null && nsub.isStatusValid() ) {
+                       return resp.success(nsub);
+               }
+               return resp.error();
+       }
+               
+       @DELETE
+       @ApiOperation( value = "return DR_Sub details", 
+       notes = "Delete a  `DR_Sub` object, selected by subId", 
+       response = DR_Sub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{subId}")
+       public Response deleteDr_Sub( 
+                       @PathParam("subId") String id
+                       ){
+
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "subId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               DR_SubService dr_subService = new DR_SubService();
+               dr_subService.removeDr_Sub(id, resp.getErr() );
+               if ( ! resp.getErr().is2xx() ) {
+                       return resp.error();
+               }
+               return resp.success(Status.NO_CONTENT.getStatusCode(), null );
+       }
+
+       @GET
+       @ApiOperation( value = "return DR_Sub details", 
+       notes = "Retrieve a  `DR_Sub` object, selected by subId", 
+       response = DR_Sub.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{subId}")
+       public Response get( 
+                       @PathParam("subId") String id
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "subId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();
+               }
+               DR_SubService dr_subService = new DR_SubService();
+               DR_Sub sub =  dr_subService.getDr_Sub( id, resp.getErr() );
+               if ( sub != null && sub.isStatusValid() ) {
+                       return resp.success(sub);
+               }
+               return resp.error();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DcaeLocationResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DcaeLocationResource.java
new file mode 100644 (file)
index 0000000..25e6f3a
--- /dev/null
@@ -0,0 +1,180 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.DcaeLocationService;
+
+
+@Path("/dcaeLocations")
+@Api( value= "dcaeLocations", description = "an OpenStack tenant purposed for OpenDCAE (i.e. where OpenDCAE components might be deployed)" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class DcaeLocationResource extends BaseLoggingClass {
+       static final Logger logger = Logger.getLogger(DcaeLocationResource.class);      
+       DcaeLocationService locationService = new DcaeLocationService();
+       
+       @GET
+       @ApiOperation( value = "return dcaeLocation details", 
+               notes = "Returns array of  `dcaeLocation` objects.  All objects managed by DMaaP are deployed in some `dcaeLocation` which is a unique identifier for an *OpenStack* tenant purposed for a *dcaeLayer*  (ecomp or edge).", 
+               response = DcaeLocation.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       public Response getDcaeLocations() {
+               ApiService check = new ApiService();
+
+               List<DcaeLocation> locs = locationService.getAllDcaeLocations();
+
+               GenericEntity<List<DcaeLocation>> list = new GenericEntity<List<DcaeLocation>>(locs) {
+        };
+        return check.success(list);
+       }
+       
+       @POST
+       @ApiOperation( value = "return dcaeLocation details", 
+               notes = "Create some `dcaeLocation` which is a unique identifier for an *OpenStack* tenant purposed for a *dcaeLayer*  (ecomp or edge).", 
+               response = DcaeLocation.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       public Response addDcaeLocation( 
+                       DcaeLocation location 
+                       ) {
+               ApiService check = new ApiService();
+
+               if ( locationService.getDcaeLocation(location.getDcaeLocationName()) != null ) {
+                               
+                       check.setCode(Status.CONFLICT.getStatusCode());
+                       check.setMessage("dcaeLocation already exists");
+                       check.setFields("dcaeLocation");
+                       
+                       return check.error();
+
+               }
+               DcaeLocation loc = locationService.addDcaeLocation(location);
+               return check.success(Status.CREATED.getStatusCode(), loc);
+       }
+       
+       @PUT
+       @ApiOperation( value = "return dcaeLocation details", 
+               notes = "update the openStackAvailabilityZone of a dcaeLocation", 
+               response = DcaeLocation.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       @Path("/{locationName}")
+       public Response updateDcaeLocation( 
+                       @PathParam("locationName") String name, 
+                       DcaeLocation location
+                        ) {
+               ApiService check = new ApiService();
+
+               location.setDcaeLocationName(name);
+               if ( locationService.getDcaeLocation(location.getDcaeLocationName()) == null ) {
+                       ApiError err = new ApiError();
+                               
+                       err.setCode(Status.NOT_FOUND.getStatusCode());
+                       err.setMessage("dcaeLocation does not exist");
+                       err.setFields("dcaeLocation");
+                       
+                       return check.notFound();
+
+
+               }
+               DcaeLocation loc = locationService.updateDcaeLocation(location);
+               return check.success(Status.CREATED.getStatusCode(), loc );
+       }
+       
+       @DELETE
+       @ApiOperation( value = "return dcaeLocation details", notes = "delete a dcaeLocation", response = Dmaap.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 204, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       @Path("/{locationName}")
+       public Response deleteDcaeLocation( 
+                       @PathParam("locationName") String name
+                        ){
+               ApiService check = new ApiService();
+
+               locationService.removeDcaeLocation(name);
+               return check.success(Status.NO_CONTENT.getStatusCode(), null);
+       }
+
+       @GET
+       @ApiOperation( value = "return dcaeLocation details", notes = "Returns a specific `dcaeLocation` object with specified tag", response = Dmaap.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       @Path("/{locationName}")
+       public Response getDcaeLocation( 
+                       @PathParam("locationName") String name
+                        ) {
+               ApiService check = new ApiService();
+
+               DcaeLocation loc =  locationService.getDcaeLocation( name );
+               if ( loc == null ) {
+                       ApiError err = new ApiError();
+                               
+                       err.setCode(Status.NOT_FOUND.getStatusCode());
+                       err.setMessage("dcaeLocation does not exist");
+                       err.setFields("dcaeLocation");
+                       
+                       return check.error();
+
+
+               }
+
+               return check.success(loc);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/DmaapResource.java
new file mode 100644 (file)
index 0000000..bd30055
--- /dev/null
@@ -0,0 +1,129 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+// $Id$
+
+package org.onap.dmaap.dbcapi.resources;
+
+
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.DmaapService;
+
+
+
+@Path("/dmaap")
+@Api( value= "dmaap", description = "Endpoint for this instance of DMaaP object containing values for this OpenDCAE deployment" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class DmaapResource extends BaseLoggingClass {
+
+
+       DmaapService dmaapService = new DmaapService();
+       
+       @GET
+       @ApiOperation( value = "return dmaap details", notes = "returns the `dmaap` object, which contains system wide configuration settings", response = Dmaap.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+
+       public Response getDmaap(@Context UriInfo uriInfo)  {
+               ApiService check = new ApiService();
+                       
+               Dmaap d =  dmaapService.getDmaap();
+               return check.success(d);
+       }
+       
+       @POST
+       @ApiOperation( value = "return dmaap details", notes = "Create a new DMaaP set system wide configuration settings for the *dcaeEnvironment*.  Deprecated with introduction of persistence in 1610.", response = Dmaap.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       public Response addDmaap( Dmaap obj ) {
+               ApiService check = new ApiService();    
+
+               try { //check for required fields
+                       check.required( "dmaapName", obj.getDmaapName(), "^\\S+$" );  //no white space allowed in dmaapName
+                       check.required( "dmaapProvUrl", obj.getDrProvUrl(), "" );
+                       check.required( "topicNsRoot", obj.getTopicNsRoot(), "" );
+                       check.required( "bridgeAdminTopic", obj.getBridgeAdminTopic(), "" );
+               } catch( RequiredFieldException rfe ) {
+                       return check.error();
+               }
+       
+               Dmaap d =  dmaapService.addDmaap(obj);
+               if ( d == null ) {
+                       return check.notFound();
+
+               } 
+
+               return check.success(d);
+       }
+       
+       @PUT
+       @ApiOperation( value = "return dmaap details", notes = "Update system settings for *dcaeEnvironment*.", response = Dmaap.class)
+    @ApiResponses( value = {
+        @ApiResponse( code = 200, message = "Success", response = Dmaap.class),
+        @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+    })
+       public Response updateDmaap(  Dmaap obj ) {
+               ApiService check = new ApiService();
+
+               try { //check for required fields
+                       check.required( "dmaapName", obj.getDmaapName(), "^\\S+$" );  //no white space allowed in dmaapName
+                       check.required( "dmaapProvUrl", obj.getDrProvUrl(), "" );
+                       check.required( "topicNsRoot", obj.getTopicNsRoot(), "" );
+                       check.required( "bridgeAdminTopic", obj.getBridgeAdminTopic(), "" );
+               } catch( RequiredFieldException rfe ) {
+                       return check.error();
+               }
+               Dmaap d =  dmaapService.updateDmaap(obj);
+               if ( d != null ) {
+                       return check.success(d);
+               } else {
+                       return check.notFound();        
+               }       
+       }
+       
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/FeedResource.java
new file mode 100644 (file)
index 0000000..361491a
--- /dev/null
@@ -0,0 +1,255 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.jws.WebParam;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.log4j.Logger;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.authentication.AuthenticationErrorException;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.DR_Sub;
+import org.onap.dmaap.dbcapi.model.Feed;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.FeedService;
+
+
+@Path("/feeds")
+@Api( value= "Feeds", description = "Endpoint for a Data Router Feed" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class FeedResource extends BaseLoggingClass {
+       
+       @GET
+       @ApiOperation( value = "return Feed details", 
+       notes = "Returns array of  `Feed` objects.", 
+       response = Feed.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getFeeds() {
+
+               ApiService resp = new ApiService();
+
+               FeedService feedService = new FeedService();
+               List<Feed> nfeeds =  feedService.getAllFeeds();
+               GenericEntity<List<Feed>> list = new GenericEntity<List<Feed>>(nfeeds) {
+        };
+        return resp.success(list);
+       }
+       
+
+       
+       @POST
+       @ApiOperation( value = "return Feed details", 
+       notes = "Create a of  `Feed` object.", 
+       response = Feed.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response addFeed( 
+                       @WebParam(name = "feed") Feed feed 
+                       ) {
+
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "feedName", feed.getFeedName(), "");
+                       resp.required( "feedVersion", feed.getFeedVersion(), "");
+                       resp.required( "owner", feed.getOwner(), "" );
+                       resp.required( "asprClassification", feed.getAsprClassification(), "" );
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               
+               FeedService feedService = new FeedService();
+               Feed nfeed =  feedService.getFeedByName( feed.getFeedName(), feed.getFeedVersion(), resp.getErr() );
+               if ( nfeed == null ) {
+                       nfeed =  feedService.addFeed( feed, resp.getErr() );
+                       if ( nfeed != null ) {
+                               return resp.success(nfeed);
+                       } else {
+                               logger.error( "Unable to create: " + feed.getFeedName() + ":" + feed.getFeedVersion());
+
+                               return resp.error();                    
+                       }
+               } else if ( nfeed.getStatus() == DmaapObject_Status.DELETED ) {
+                       nfeed =  feedService.updateFeed(nfeed, resp.getErr());
+                       if ( nfeed != null ) {
+                               return resp.success(nfeed);
+                       } else {
+                               logger.info( "Unable to update: " + feed.getFeedName() + ":" + feed.getFeedVersion());
+
+                               return resp.error();    
+                       }
+               }
+
+               resp.setCode(Status.CONFLICT.getStatusCode());
+               return resp.error();
+       }
+       
+       @PUT
+       @ApiOperation( value = "return Feed details", 
+       notes = "Update a  `Feed` object, specified by id.", 
+       response = Feed.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{id}")
+       public Response updateFeed( 
+                       @PathParam("id") String id,
+                       @WebParam(name = "feed") Feed feed 
+                       ) {
+
+               FeedService feedService = new FeedService();
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "feedId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+
+               Feed nfeed = feedService.getFeed( id, resp.getErr() );
+               if ( nfeed == null || nfeed.getStatus() == DmaapObject_Status.DELETED ) {
+                       return resp.notFound();                                         
+               }
+       
+               //  we assume there is no updates allowed for pubs and subs objects via this api...             
+               // need to update any fields supported by PUT but preserve original field values. 
+               nfeed.setSuspended(feed.isSuspended());
+               nfeed.setFeedDescription(feed.getFeedDescription());
+               nfeed.setFormatUuid(feed.getFormatUuid());
+               
+               nfeed =  feedService.updateFeed(nfeed, resp.getErr());
+               if ( nfeed != null ) {
+                       return resp.success(nfeed);
+               } else {
+                       logger.info( "Unable to update: " + feed.getFeedName() + ":" + feed.getFeedVersion());
+
+                       return resp.error();    
+               }
+       }
+       
+       @DELETE
+       @ApiOperation( value = "return Feed details", 
+       notes = "Delete a  `Feed` object, specified by id.", 
+       response = Feed.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{id}")
+       public Response deleteFeed( 
+                       @PathParam("id") String id
+                       ){
+               ApiService resp = new ApiService();
+
+               logger.debug( "Entry: DELETE  " + id);
+               FeedService feedService = new FeedService();
+               Feed nfeed =  feedService.getFeed( id, resp.getErr() );
+               if ( nfeed == null ) {
+                       resp.setCode(Status.NOT_FOUND.getStatusCode());
+                       return resp.error();
+               }
+               nfeed = feedService.removeFeed( nfeed, resp.getErr() );
+               if ( nfeed == null || nfeed.getStatus() == DmaapObject_Status.DELETED ) {
+                       return resp.success(Status.NO_CONTENT.getStatusCode(), null);
+               }
+               logger.info( "Unable to delete: " + id + ":" + nfeed.getFeedVersion());
+
+               return resp.error();
+       }
+
+       @GET
+       @ApiOperation( value = "return Feed details", 
+       notes = "Retrieve a  `Feed` object, specified by id.", 
+       response = Feed.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{id}")
+       public Response getFeed( 
+                       @PathParam("id") String id
+                       ) {
+               ApiService resp = new ApiService();
+
+               FeedService feedService = new FeedService();
+               Feed nfeed =  feedService.getFeed( id, resp.getErr() );
+               if ( nfeed == null ) {
+                       resp.setCode(Status.NOT_FOUND.getStatusCode());
+                       return resp.error();
+               }
+               return resp.success(nfeed);
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClientResource.java
new file mode 100644 (file)
index 0000000..8f6a506
--- /dev/null
@@ -0,0 +1,232 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.MR_Client;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.MR_ClientService;
+import org.onap.dmaap.dbcapi.service.MR_ClusterService;
+import org.onap.dmaap.dbcapi.service.TopicService;
+
+
+@Path("/mr_clients")
+@Api( value= "MR_Clients", description = "Endpoint for a Message Router Client that implements a Publisher or a Subscriber" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class MR_ClientResource extends BaseLoggingClass {
+
+       private MR_ClientService mr_clientService = new MR_ClientService();
+               
+       @GET
+       @ApiOperation( value = "return MR_Client details", 
+       notes = "Returns array of  `MR_Client` objects.", 
+       response = MR_Client.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getMr_Clients() {
+               ApiService resp = new ApiService();
+
+               List<MR_Client> clients = mr_clientService.getAllMr_Clients();
+
+               GenericEntity<List<MR_Client>> list = new GenericEntity<List<MR_Client>>(clients) {
+        };
+        return resp.success(list);             
+       }
+               
+       @POST
+       @ApiOperation( value = "return MR_Client details", 
+       notes = "Create a  `MR_Client` object.", 
+       response = MR_Client.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response addMr_Client( 
+                       MR_Client client
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "fqtn", client.getFqtn(), "");
+                       resp.required( "dcaeLocationName", client.getDcaeLocationName(), "");
+                       resp.required( "clientRole", client.getClientRole(), "" );
+                       resp.required( "action", client.getAction(), "");
+
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               MR_ClusterService clusters = new MR_ClusterService();
+
+               MR_Cluster cluster = clusters.getMr_Cluster(client.getDcaeLocationName(), resp.getErr());
+               if ( cluster == null ) {
+
+                       resp.setCode(Status.BAD_REQUEST.getStatusCode());
+                       resp.setMessage( "MR_Cluster alias not found for dcaeLocation: " + client.getDcaeLocationName());
+                       resp.setFields("dcaeLocationName");
+                       logger.warn( resp.toString() );
+                       return resp.error();
+               }
+               String url = cluster.getFqdn();
+               if ( url == null || url.isEmpty() ) {
+
+                       resp.setCode(Status.BAD_REQUEST.getStatusCode());
+                       resp.setMessage("FQDN not set for dcaeLocation " + client.getDcaeLocationName() );
+                       resp.setFields("fqdn");
+                       logger.warn( resp.toString() );
+                       return resp.error();
+               }
+               TopicService topics = new TopicService();
+
+               Topic t = topics.getTopic(client.getFqtn(), resp.getErr() );
+               if ( t == null ) {
+                       return resp.error();            
+               }
+               MR_Client nClient =  mr_clientService.addMr_Client(client, t, resp.getErr());
+               if ( resp.getErr().is2xx()) {
+                       t = topics.getTopic(client.getFqtn(),  resp.getErr());
+                       topics.checkForBridge(t, resp.getErr());
+                       return resp.success(nClient);
+               }
+               else {
+                       return resp.error();                    
+               }
+       }
+               
+       @PUT
+       @ApiOperation( value = "return MR_Client details", 
+       notes = "Update a  `MR_Client` object, specified by clientId", 
+       response = MR_Client.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{clientId}")
+       public Response updateMr_Client( 
+                       @PathParam("clientId") String clientId, 
+                       MR_Client client
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "fqtn", client.getFqtn(), "");
+                       resp.required( "dcaeLocationName", client.getDcaeLocationName(), "");
+                       resp.required( "clientRole", client.getClientRole(), "" );
+                       resp.required( "action", client.getAction(), "");
+
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();            
+               }
+               client.setMrClientId(clientId);
+               MR_Client nClient = mr_clientService.updateMr_Client(client, resp.getErr() );
+               if ( resp.getErr().is2xx()) {
+                       return Response.ok(nClient)
+                               .build();
+               }
+               return Response.status(resp.getErr().getCode())
+                               .entity( resp.getErr() )
+                               .build();
+       }
+               
+       @DELETE
+       @ApiOperation( value = "return MR_Client details", 
+       notes = "Delete a  `MR_Client` object, specified by clientId", 
+       response = MR_Client.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{subId}")
+       public Response deleteMr_Client( 
+                       @PathParam("subId") String id
+                       ){
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "clientId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               mr_clientService.removeMr_Client(id, true, resp.getErr() );
+               if ( resp.getErr().is2xx()) {
+                       return resp.success(Status.NO_CONTENT.getStatusCode(), null);
+               }
+               
+               return resp.error();
+       }
+
+       @GET
+       @ApiOperation( value = "return MR_Client details", 
+       notes = "Retrieve a  `MR_Client` object, specified by clientId", 
+       response = MR_Client.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{subId}")
+       public Response test( 
+                       @PathParam("subId") String id
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "clientId", id, "");
+               } catch ( RequiredFieldException rfe ) {
+                       logger.debug( resp.toString() );
+                       return resp.error();    
+               }
+               MR_Client nClient =  mr_clientService.getMr_Client( id, resp.getErr() );
+               if ( resp.getErr().is2xx()) {
+                       return resp.success(nClient);
+               }
+               return resp.error();    
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/MR_ClusterResource.java
new file mode 100644 (file)
index 0000000..41aaead
--- /dev/null
@@ -0,0 +1,187 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.MR_ClientService;
+import org.onap.dmaap.dbcapi.service.MR_ClusterService;
+
+
+@Path("/mr_clusters")
+@Api( value= "MR_Clusters", description = "Endpoint for a Message Router servers in a Cluster configuration" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class MR_ClusterResource extends BaseLoggingClass {
+
+       MR_ClusterService mr_clusterService = new MR_ClusterService();
+       MR_ClientService mr_clients = new MR_ClientService();
+               
+       @GET
+       @ApiOperation( value = "return MR_Cluster details", 
+       notes = "Returns array of  `MR_Cluster` objects.", 
+       response = MR_Cluster.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getMr_Clusters() {
+               ApiService resp = new ApiService();
+
+               List<MR_Cluster> clusters = mr_clusterService.getAllMr_Clusters();
+
+               GenericEntity<List<MR_Cluster>> list = new GenericEntity<List<MR_Cluster>>(clusters) {
+        };
+        return resp.success(list);
+       }
+               
+       @POST
+       @ApiOperation( value = "return MR_Cluster details", 
+       notes = "Create an  `MR_Cluster` object.", 
+       response = MR_Cluster.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response  addMr_Cluster( 
+                       MR_Cluster cluster
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "dcaeLocationName", cluster.getDcaeLocationName(), "" );  
+                       resp.required( "fqdn", cluster.getFqdn(), "" );
+               } catch( RequiredFieldException rfe ) {
+                       return resp.error();
+               }
+               MR_Cluster mrc =  mr_clusterService.addMr_Cluster(cluster, resp.getErr() );
+               if ( mrc != null && mrc.isStatusValid() ) {
+                       return resp.success(Status.CREATED.getStatusCode(), mrc);
+               }
+               return resp.error();
+
+       }
+               
+       @PUT
+       @ApiOperation( value = "return MR_Cluster details", 
+       notes = "Update an  `MR_Cluster` object, specified by clusterId.", 
+       response = MR_Cluster.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{clusterId}")
+       public Response updateMr_Cluster( 
+                       @PathParam("clusterId") String clusterId, 
+                       MR_Cluster cluster
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "fqdn", clusterId, "" );
+                       resp.required( "dcaeLocationName", cluster.getDcaeLocationName(), "" );  
+               } catch( RequiredFieldException rfe ) {
+                       return resp.error();
+               }
+               cluster.setDcaeLocationName(clusterId);
+               MR_Cluster mrc =  mr_clusterService.updateMr_Cluster(cluster, resp.getErr() );
+               if ( mrc != null && mrc.isStatusValid() ) {
+                       return resp.success(Status.CREATED.getStatusCode(), mrc);
+               }
+               return resp.error();
+       }
+               
+       @DELETE
+       @ApiOperation( value = "return MR_Cluster details", 
+       notes = "Delete an  `MR_Cluster` object, specified by clusterId.", 
+       response = MR_Cluster.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{clusterId}")
+       public Response deleteMr_Cluster( 
+                       @PathParam("clusterId") String id
+                       ){
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "fqdn", id, "" );
+               } catch( RequiredFieldException rfe ) {
+                       return resp.error();
+               }
+               mr_clusterService.removeMr_Cluster(id, resp.getErr() );
+               if ( resp.getErr().is2xx()) {
+                       return resp.success(Status.NO_CONTENT.getStatusCode(), null);
+               } 
+               return resp.error();
+       }
+
+       @GET
+       @ApiOperation( value = "return MR_Cluster details", 
+       notes = "Retrieve an  `MR_Cluster` object, specified by clusterId.", 
+       response = MR_Cluster.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{clusterId}")
+       public Response getMR_Cluster( 
+                       @PathParam("clusterId") String id
+                       ) {
+               ApiService resp = new ApiService();
+
+               try {
+                       resp.required( "dcaeLocationName", id, "" );
+               } catch( RequiredFieldException rfe ) {
+                       return resp.error();
+               }
+               MR_Cluster mrc =  mr_clusterService.getMr_Cluster( id, resp.getErr() );
+               if ( mrc != null && mrc.isStatusValid() ) {
+                       return resp.success(Status.CREATED.getStatusCode(), mrc);
+               }
+               return resp.error();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java b/src/main/java/org/onap/dmaap/dbcapi/resources/RequiredFieldException.java
new file mode 100644 (file)
index 0000000..74af356
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+public class RequiredFieldException extends Exception {
+
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java b/src/main/java/org/onap/dmaap/dbcapi/resources/TopicResource.java
new file mode 100644 (file)
index 0000000..0f99fb6
--- /dev/null
@@ -0,0 +1,191 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.resources;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.ReplicationType;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.service.ApiService;
+import org.onap.dmaap.dbcapi.service.TopicService;
+
+@Path("/topics")
+@Api( value= "topics", description = "Endpoint for retreiving MR Topics" )
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Authorization
+public class TopicResource extends BaseLoggingClass {
+
+       TopicService mr_topicService = new TopicService();
+               
+       @GET
+       @ApiOperation( value = "return Topic details", 
+       notes = "Returns array of  `Topic` objects.", 
+       response = Topic.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response getTopics() {
+
+               ApiService check = new ApiService();
+
+               List<Topic> allTopics = mr_topicService.getAllTopics();
+               
+               GenericEntity<List<Topic>> list = new GenericEntity<List<Topic>>(allTopics) {
+                       };
+               return check.success(list);
+               
+       }
+               
+       @POST
+       @ApiOperation( value = "return Topic details", 
+       notes = "Create  `Topic` object.", 
+       response = Topic.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       public Response  addTopic( 
+                       Topic topic
+                       ) {
+               logger.info( "addTopic request: " + String.valueOf(topic) );
+               ApiService check = new ApiService();
+
+               try {
+                       check.required( "topicName", topic.getTopicName(), "^\\S+$" );  //no white space allowed in topicName
+                       check.required( "topicDescription", topic.getTopicDescription(), "" );
+                       check.required( "owner", topic.getOwner(), "" );
+               } catch( RequiredFieldException rfe ) {
+                       return check.error();
+               }
+               
+               //String repReq = topic.getReplicationRequest();
+               ReplicationType t = topic.getReplicationCase();
+               if ( t == null || t == ReplicationType.REPLICATION_NOT_SPECIFIED ) {
+                       topic.setReplicationCase( mr_topicService.reviewTopic(topic));
+               } 
+               
+               topic.setLastMod();
+               
+               Topic mrc =  mr_topicService.addTopic(topic, check.getErr());
+               if ( mrc != null && mrc.isStatusValid() ) {
+                       return check.success(Status.CREATED.getStatusCode(), mrc);
+               }
+               return check.error();
+       }
+       
+       @PUT
+       @ApiOperation( value = "return Topic details", 
+       notes = "Update a  `Topic` object, identified by topicId", 
+       response = Topic.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{topicId}")
+       public Response updateTopic( 
+                       @PathParam("topicId") String topicId
+                       ) {
+               ApiService check = new ApiService();
+
+               check.setCode(Status.BAD_REQUEST.getStatusCode());
+               check.setMessage( "Method /PUT not supported for /topics");
+               
+               return check.error();
+       }
+               
+       @DELETE
+       @ApiOperation( value = "return Topic details", 
+       notes = "Delete a  `Topic` object, identified by topicId", 
+       response = Topic.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 204, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{topicId}")
+       public Response deleteTopic( 
+                       @PathParam("topicId") String id
+                       ){
+               ApiService check = new ApiService();
+
+               try {
+                       check.required( "fqtn", id, "" );
+               } catch( RequiredFieldException rfe ) {
+                       return check.error();
+               }
+               
+               mr_topicService.removeTopic(id, check.getErr());
+               if ( check.getErr().is2xx()) {
+                       return check.success(Status.NO_CONTENT.getStatusCode(), null);
+               } 
+               return check.error();
+       }
+       
+
+       @GET
+       @ApiOperation( value = "return Topic details", 
+       notes = "Retrieve a  `Topic` object, identified by topicId", 
+       response = Topic.class)
+       @ApiResponses( value = {
+           @ApiResponse( code = 200, message = "Success", response = DR_Pub.class),
+           @ApiResponse( code = 400, message = "Error", response = ApiError.class )
+       })
+       @Path("/{topicId}")
+       public Response getTopic( 
+                       @PathParam("topicId") String id
+                       ) {
+               logger.info("Entry: /GET " + id);
+               ApiService check = new ApiService();
+
+               try {
+                       check.required( "topicName", id, "^\\S+$" );  //no white space allowed in topicName
+               } catch( RequiredFieldException rfe ) {
+                       return check.error();
+               }
+               Topic mrc =  mr_topicService.getTopic( id, check.getErr() );
+               if ( mrc == null ) {
+                       return check.error();
+               }
+               return check.success(mrc);
+               }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java b/src/main/java/org/onap/dmaap/dbcapi/server/ApplicationConfig.java
new file mode 100644 (file)
index 0000000..2283ea2
--- /dev/null
@@ -0,0 +1,36 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.dmaap.dbcapi.server;
+
+import org.glassfish.jersey.server.ResourceConfig;
+
+
+
+public class ApplicationConfig extends ResourceConfig {
+       
+       /*
+        * Register JAX-RS application components
+        */
+       public ApplicationConfig() {
+               
+        register(org.onap.dmaap.dbcapi.resources.AuthorizationFilter.class);
+  
+    }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java b/src/main/java/org/onap/dmaap/dbcapi/server/JettyServer.java
new file mode 100644 (file)
index 0000000..4d06310
--- /dev/null
@@ -0,0 +1,151 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.server;
+
+
+import java.util.Properties;
+
+import javax.net.ssl.SSLContext;
+
+import org.apache.log4j.Logger;
+import org.eclipse.jetty.security.SecurityHandler;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import org.onap.dmaap.dbcapi.aaf.database.LoadSchema;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+/**
+ * A  Jetty server which supports:
+ *     - http and https (simultaneously for dev env)
+ *  - REST API context
+ *  - static html pages (for documentation).
+ */
+public class JettyServer extends BaseLoggingClass {
+
+    public JettyServer( Properties params ) throws Exception {
+
+        Server server = new Server();
+       int httpPort = Integer.valueOf(params.getProperty("IntHttpPort", "80" ));
+               int sslPort = Integer.valueOf(params.getProperty("IntHttpsPort", "443" ));
+               boolean allowHttp = Boolean.valueOf(params.getProperty("HttpAllowed", "false"));
+       serverLogger.info( "port params: http=" + httpPort + " https=" + sslPort );
+       serverLogger.info( "allowHttp=" + allowHttp );
+        
+        // HTTP Server
+
+       HttpConfiguration http_config = new HttpConfiguration();
+       http_config.setSecureScheme("https");
+       http_config.setSecurePort(sslPort);
+       http_config.setOutputBufferSize(32768);
+
+       
+       
+        ServerConnector httpConnector = new ServerConnector(server, new HttpConnectionFactory(http_config));
+        httpConnector.setPort(httpPort);  
+        httpConnector.setIdleTimeout(30000);
+  
+        
+        // HTTPS Server
+        HttpConfiguration https_config = new HttpConfiguration(http_config);
+        https_config.addCustomizer(new SecureRequestCustomizer());
+        SslContextFactory sslContextFactory = new SslContextFactory();
+        String keystore = params.getProperty("KeyStoreFile", "etc/keystore");
+        logger.info( "https Server using keystore at " + keystore );
+        String keystorePwd = params.getProperty( "KeyStorePassword", "changeit");
+        String keyPwd = params.getProperty("KeyPassword", "changeit");
+
+        sslContextFactory.setKeyStorePath(keystore);
+        sslContextFactory.setKeyStorePassword(keystorePwd);
+        sslContextFactory.setKeyManagerPassword(keyPwd);     
+
+  
+               ServerConnector sslConnector = null;
+               if ( sslPort != 0 ) {
+                       sslConnector = new ServerConnector(server,
+                                       new SslConnectionFactory(sslContextFactory, "http/1.1"),
+                                       new HttpConnectionFactory(https_config));
+                       sslConnector.setPort(sslPort);
+               if ( allowHttp ) {
+               logger.info("Starting httpConnector on port " + httpPort );
+               logger.info("Starting sslConnector on port " +   sslPort + " for https");
+                       server.setConnectors( new Connector[] { httpConnector, sslConnector });
+               } else {
+               logger.info("NOT starting httpConnector because HttpAllowed param is " + allowHttp  );  
+               logger.info("Starting sslConnector on port " +   sslPort + " for https");
+                       server.setConnectors( new Connector[] { sslConnector });        
+               }
+               }
+               else {
+            serverLogger.info("NOT starting sslConnector on port " +   sslPort + " for https");
+               if ( allowHttp ) {
+               serverLogger.info("Starting httpConnector on port " + httpPort );
+                       server.setConnectors( new Connector[] { httpConnector });
+                       } 
+        } 
+        // Set context for servlet.  This is shared for http and https
+               ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+       context.setContextPath("/");
+        server.setHandler( context );
+
+        ServletHolder jerseyServlet = context.addServlet( org.glassfish.jersey.servlet.ServletContainer.class, "/webapi/*");
+        jerseyServlet.setInitOrder(1);
+        jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "org.onap.dmaap.dbcapi.resources" );   
+        jerseyServlet.setInitParameter("javax.ws.rs.Application", "org.onap.dmaap.dbcapi.server.ApplicationConfig" );
+        
+        // also serve up some static pages...
+        ServletHolder staticServlet = context.addServlet(DefaultServlet.class,"/*");
+        staticServlet.setInitParameter("resourceBase","www");
+        staticServlet.setInitParameter("pathInfoOnly","true");
+
+        try {
+
+            serverLogger.info("Starting jetty server");
+               server.start();
+               server.dumpStdErr();
+            server.join();
+        } catch ( Exception e ) {
+               errorLogger.error( "Exception " + e );
+               errorLogger.error( "possibly unable to use keystore " + keystore + " with passwords " + keystorePwd +  " and " + keyPwd );
+               //System.exit(1);
+        } finally {
+               server.destroy();
+        }
+        
+    }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/server/Main.java b/src/main/java/org/onap/dmaap/dbcapi/server/Main.java
new file mode 100644 (file)
index 0000000..1ada428
--- /dev/null
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.server;
+import java.net.InetAddress;
+import java.util.Properties;
+import java.util.UUID;
+
+import org.onap.dmaap.dbcapi.aaf.authentication.ApiPerms;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.*;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.Singleton;
+
+import static com.att.eelf.configuration.Configuration.*;
+
+import org.slf4j.MDC;
+
+public class Main extends BaseLoggingClass {
+
+       
+    private Properties parameters;
+    private static String provFQDN;
+
+    public static String getProvFQDN() {
+               return provFQDN;
+       }
+       public void setProvFQDN(String provFQDN) {
+               Main.provFQDN = provFQDN;
+       }
+       private Main() {
+    }
+    public static void main(String[] args) throws Exception {
+        (new Main()).main();
+    }
+
+    private void main()  {
+    
+        MDC.clear();
+
+        MDC.put(MDC_SERVICE_INSTANCE_ID, "");
+        try {
+            MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getHostName());
+            MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        MDC.put(MDC_INSTANCE_UUID, UUID.randomUUID().toString());
+        MDC.put(MDC_ALERT_SEVERITY, "0");
+
+
+        MDC.put(MDC_TARGET_ENTITY, "DCAE");
+
+
+/*
+       String msg = "This is a sample {} message to demo EELF logging.";
+    
+       appLogger.info( msg, "appLogger.info");
+
+       auditLogger.auditEvent( msg, "auditLogger.auditEvent");
+       errorLogger.error(DmaapbcLogMessageEnum.MESSAGE_SAMPLE_NOARGS);
+       errorLogger.error(DmaapbcLogMessageEnum.MESSAGE_SAMPLE_ONE_ARG, "errorLogger.error");
+       errorLogger.error(DmaapbcLogMessageEnum.MESSAGE_SAMPLE_TWO_ARGS, new Date().toString(), "errorLogger.error" );
+       metricsLogger.metricsEvent( msg, "metricsLogger.metricsEvent" );
+       debugLogger.debug( msg, "debugLogger.debug");
+       
+       //String log = System.getProperty( "log4j.configuration");
+       //if ( log.isEmpty() ) {
+       //      log = "log4j.properties";
+       //}
+        //PropertyConfigurator.configure( log );
+         * 
+         */
+        appLogger.info("Started.");
+        parameters = DmaapConfig.getConfig();
+        setProvFQDN( parameters.getProperty("ProvFQDN", "ProvFQDN.notset.com"));
+               
+               
+               // for fresh installs, we may come up with no dmaap name so need to have a way for Controller to talk to us
+               Singleton<Dmaap> dmaapholder = DatabaseClass.getDmaap();
+               String name = dmaapholder.get().getDmaapName();
+               if ( name == null || name.isEmpty()) {
+                       ApiPerms p = new ApiPerms();
+                       p.setBootMap();
+               }
+
+       
+        try {
+               new JettyServer( parameters );
+        } catch (Exception e) {
+            errorLogger.error("Unable to start Jetty " + DmaapConfig.getConfigFileName(), e);
+            System.exit(1);
+        }
+
+    }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java b/src/main/java/org/onap/dmaap/dbcapi/service/ApiService.java
new file mode 100644 (file)
index 0000000..aab989d
--- /dev/null
@@ -0,0 +1,339 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import static com.att.eelf.configuration.Configuration.MDC_BEGIN_TIMESTAMP;
+import static com.att.eelf.configuration.Configuration.MDC_ELAPSED_TIME;
+import static com.att.eelf.configuration.Configuration.MDC_END_TIMESTAMP;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
+import static com.att.eelf.configuration.Configuration.MDC_PARTNER_NAME;
+import static com.att.eelf.configuration.Configuration.MDC_RESPONSE_CODE;
+import static com.att.eelf.configuration.Configuration.MDC_RESPONSE_DESC;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+import static com.att.eelf.configuration.Configuration.MDC_STATUS_CODE;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.bind.DatatypeConverter;
+
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.authentication.ApiPolicy;
+import org.onap.dmaap.dbcapi.aaf.authentication.AuthenticationErrorException;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.resources.RequiredFieldException;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.RandomString;
+import org.slf4j.MDC;
+
+public class ApiService extends BaseLoggingClass {
+       private class StopWatch {
+               private long clock = 0;
+               private long elapsed = 0;
+               
+
+               
+               public StopWatch() {
+                       clock = 0;
+                       elapsed = 0;
+               }
+               
+               public void reset() {
+                       clock = System.currentTimeMillis();
+                       elapsed = 0;
+               }
+               public void stop() {
+                       Long stopTime = System.currentTimeMillis();
+                       elapsed +=  stopTime - clock;
+                       clock = 0;
+                       MDC.put( MDC_END_TIMESTAMP, isoFormatter.format(new Date(stopTime)));
+                       MDC.put( MDC_ELAPSED_TIME, String.valueOf(elapsed));
+               }
+               public void start() {
+                       if ( clock != 0 ) {
+                               //not stopped
+                               return;
+                       }
+                       clock = System.currentTimeMillis();     
+                       MDC.put( MDC_BEGIN_TIMESTAMP, isoFormatter.format(new Date(clock)));
+               }
+               private long getElapsed() {
+                       return elapsed;
+               }
+       }
+
+        private String apiNamespace;
+        private boolean usePE;
+        private String uri;
+        private String uriPath;
+        private String method;
+        private String authorization;
+        private String requestId;
+       private ApiError err;
+       private StopWatch stopwatch;
+       private ApiPolicy apiPolicy;
+       
+       public static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+    public final static TimeZone utc = TimeZone.getTimeZone("UTC");
+    public final static SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
+       
+    static {
+       isoFormatter.setTimeZone(utc);
+    }  
+       public ApiService() {
+
+               stopwatch = new StopWatch();
+               stopwatch.start();
+               err = new ApiError();
+               requestId = (new RandomString(10)).nextString();
+               
+               if (apiNamespace == null) {
+                       DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+                       usePE = "true".equalsIgnoreCase(p.getProperty("UsePE", "false"));
+                       apiNamespace = p.getProperty("ApiNamespace", "org.openecomp.dmaapBC.api");
+               }
+               apiPolicy = new ApiPolicy();
+               logger.info( "usePE=" + usePE + " apiNamespace=" + apiNamespace);       
+       }
+
+       public ApiService setAuth( String auth ) {
+               this.authorization = auth;
+               logger.info( "setAuth:  authorization={} ",  authorization);
+               return this;
+       }
+       private void setServiceName(){
+               String svcRequest = new String( this.method + " " + this.uriPath );
+        MDC.put(MDC_SERVICE_NAME, svcRequest );
+       }
+       public ApiService setHttpMethod( String httpMethod ) {
+               this.method = httpMethod;
+               logger.info( "setHttpMethod: method={} ", method);
+               setServiceName();
+               return this;
+       }
+       public ApiService setUriPath( String uriPath ) {
+               this.uriPath = uriPath;
+               this.uri = setUriFromPath( uriPath );
+               logger.info( "setUriPath: uriPath={} uri={}", uriPath, uri);
+               setServiceName();
+               return this;
+       }
+       private String setUriFromPath( String uriPath ) {
+               int ch = uriPath.indexOf("/");
+               if ( ch > 0 ) {
+                       return( (String) uriPath.subSequence(0, ch ) );
+               } else {
+                       return uriPath;
+               }
+       }       
+       
+       public ApiError getErr() {
+               return err;
+       }
+
+
+       public void setErr(ApiError err) {
+               this.err = err;
+       }
+
+
+       // test for presence of a required field
+       public void required( String name, Object val, String expr ) throws RequiredFieldException {
+               if ( val == null  ) {
+                       err.setCode(Status.BAD_REQUEST.getStatusCode());
+                       err.setMessage("missing required field");
+                       err.setFields( name );  
+                       throw new RequiredFieldException();
+               }
+               if ( expr != null && ! expr.isEmpty() ) {
+                       Pattern pattern = Pattern.compile(expr);
+                       Matcher matcher = pattern.matcher((CharSequence) val);
+                       if ( ! matcher.find() ) {
+                               err.setCode(Status.BAD_REQUEST.getStatusCode());
+                               err.setMessage( "value '" + val + "' violates regexp check '" + expr + "'");
+                               err.setFields( name );
+                               throw new RequiredFieldException();
+                       }
+               }
+       }
+       
+       // utility to serialize ApiErr object
+       public String toString() {
+               return String.format( "code=%d msg=%s fields=%s", err.getCode(), err.getMessage(), err.getFields() );
+       }
+
+
+       public void setCode(int statusCode) {
+               err.setCode(statusCode);        
+       }
+
+
+       public void setMessage(String string) {
+               err.setMessage(string);
+       }
+
+
+       public void setFields(String string) {
+               err.setFields(string);
+       }
+
+       private Response  buildResponse( Object obj ) {
+               stopwatch.stop();
+               MDC.put( MDC_RESPONSE_CODE, String.valueOf(err.getCode()) );
+               
+               auditLogger.auditEvent( "" );
+               return Response.status( err.getCode())
+                               .entity(obj)
+                               .build();
+       }
+       private Response  buildSuccessResponse(Object d) {
+               MDC.put( MDC_STATUS_CODE,  "COMPLETE");
+               MDC.put( MDC_RESPONSE_DESC, "");
+               return buildResponse( d );
+       }
+       private Response  buildErrResponse() {
+       
+               MDC.put( MDC_STATUS_CODE,  "ERROR");
+               MDC.put( MDC_RESPONSE_DESC, err.getMessage());
+               
+               return buildResponse(getErr());
+       }
+       public Response success( Object d ) {
+               err.setCode(Status.OK.getStatusCode());
+               return buildSuccessResponse(d);
+                               
+       }
+       public Response success( int code, Object d ) {
+               err.setCode(code);
+               return buildSuccessResponse(d);
+       }
+
+       public Response unauthorized( String msg ) {
+               err.setCode(Status.UNAUTHORIZED.getStatusCode());
+               err.setFields( "Authorization");
+               err.setMessage( msg );
+               return buildErrResponse();
+       }
+       public Response unauthorized() {
+               err.setCode(Status.UNAUTHORIZED.getStatusCode());
+               err.setFields( "Authorization");
+               err.setMessage( "User credentials in HTTP Header field Authorization are not authorized for the requested action");
+               return buildErrResponse();
+       }
+       public Response unavailable() {
+               err.setCode(Status.SERVICE_UNAVAILABLE.getStatusCode());
+               err.setMessage( "Request is unavailable due to unexpected condition");
+               return buildErrResponse();
+       }
+       public Response notFound() {
+               err.setCode(Status.NOT_FOUND.getStatusCode());
+               err.setMessage( "Requested object not found");
+               return buildErrResponse();
+       }
+       public Response error() {
+               return buildErrResponse();
+       }
+       
+       public void checkAuthorization( String auth, String uriPath, String httpMethod ) throws AuthenticationErrorException, Exception {
+               authorization = auth;
+               setUriFromPath( uriPath );
+               method = httpMethod;
+               
+               checkAuthorization();
+       }
+
+       
+       public void checkAuthorization() throws AuthenticationErrorException, Exception {
+
+               MDC.put(MDC_KEY_REQUEST_ID, requestId); 
+       
+               logger.info("request: uri={} method={} auth={}", uri, method, authorization );
+
+               if ( uri == null || uri.isEmpty()) {
+                       String errmsg = "No URI value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );                      
+               }
+               if ( method == null || method.isEmpty()) {
+                       String errmsg = "No method value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );                      
+               }
+               DmaapService dmaapService = new DmaapService();
+               Dmaap dmaap = dmaapService.getDmaap();
+               String env =            dmaap.getDmaapName();
+               
+               // special case during bootstrap of app when DMaaP environment may not be set.
+               // this allows us to authorize certain APIs used for initialization during this window.
+               if ( env == null || env.isEmpty() ) {
+                       env = "boot";
+               }
+               if ( ! usePE ) return;  // skip authorization if not enabled
+               if ( authorization == null || authorization.isEmpty()) {
+                       String errmsg = "No basic authorization value provided ";
+                       err.setMessage(errmsg);
+                       logger.info( errmsg );
+                       throw new AuthenticationErrorException( );
+               }
+               String credentials = authorization.substring("Basic".length()).trim();
+        byte[] decoded = DatatypeConverter.parseBase64Binary(credentials);
+        String decodedString = new String(decoded);
+        String[] actualCredentials = decodedString.split(":");
+        String ID = actualCredentials[0];
+        String Password = actualCredentials[1];
+        MDC.put(MDC_PARTNER_NAME, ID);
+               try {
+                       
+                       DmaapPerm p = new DmaapPerm( apiNamespace + "." + uri, env, method );
+                       apiPolicy.check( ID, Password, p);
+               } catch ( AuthenticationErrorException ae ) {
+                       String errmsg =  "User " + ID + " failed authentication/authorization for " + apiNamespace + "." + uriPath + " " + env + " " + method;
+                       logger.info( errmsg );
+                       err.setMessage(errmsg);
+                       throw ae;
+
+               } 
+               
+
+       }
+       public String getRequestId() {
+               return requestId;
+       }
+       public ApiService setRequestId(String requestId) {
+               if ( requestId == null || requestId.isEmpty()) {        
+                       this.requestId = (new RandomString(10)).nextString();
+                       logger.warn( "X-ECOMP-RequestID not set in HTTP Header.  Setting RequestId value to: " + this.requestId );
+               } else {
+                       this.requestId = requestId;
+               }
+               MDC.put(MDC_KEY_REQUEST_ID, this.requestId); 
+               return this;
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_NodeService.java
new file mode 100644 (file)
index 0000000..e80b531
--- /dev/null
@@ -0,0 +1,249 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dcae
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.aaf.client.DrProvConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Node;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+
+public class DR_NodeService extends BaseLoggingClass {
+       private  class DrProv {
+               String currentNodes;
+               String currentStaticNodes;
+               
+               private String getX( String X, ApiError apiError ) {
+                       
+                       DrProvConnection prov = new DrProvConnection();
+                       prov.makeNodesConnection( X );  
+                       String resp  = prov.doGetNodes(  apiError );
+                       logger.info( "rc=" + apiError.getCode() );
+                       return resp;
+               }
+               
+               private void setX( String X, String list, ApiError apiError ) {
+                       DrProvConnection prov = new DrProvConnection();
+                       prov.makeNodesConnection( X, list );    
+                       String resp = prov.doPutNodes( apiError );
+               }
+               
+               private String removeFromList( String aNode, String aList ) {
+                       String[] nodeList = aList.split("\\|");
+                       StringBuilder res = new StringBuilder();
+                       for ( String n: nodeList ) {
+                               logger.info( "compare existing node " + n + " vs " + aNode );
+                               if ( ! n.equals(aNode)) {
+                                       if (res.length() > 0 ) {
+                                               res.append( "|" );
+                                       }
+                                       res.append(n);
+                               }
+                       }
+                       logger.info( "result=" + res.toString() );
+                       return res.toString();
+               }
+               
+                boolean containsNode( String aNode , ApiError apiError ){
+       
+                       //DrProvConnection prov = new DrProvConnection();
+                       //prov.makeNodesConnection();   
+                       currentNodes = getX( "NODES", apiError );
+                       if ( ! apiError.is2xx() || currentNodes == null ) {
+                               return false;
+                       }
+                       logger.info( "NODES now=" + currentNodes );
+                       String[] nodeList = currentNodes.split("\\|");
+                       for( String n: nodeList ) {
+                               logger.info( "compare existing node " + n + " vs " + aNode );
+                               if ( n.equals(aNode) ) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               
+                void addNode( String aNode, ApiError apiError ) {
+                       
+                       currentNodes = currentNodes + "|" + aNode;
+                       setX( "NODES", currentNodes, apiError );        
+
+                       
+               }
+               void removeNode( String aNode, ApiError apiError ) {
+                       currentNodes = removeFromList( aNode, currentNodes );
+                       setX( "NODES", currentNodes, apiError );                        
+               }
+
+               public boolean containsStaticNode(String aNode, ApiError apiError) {
+       
+                       //DrProvConnection prov = new DrProvConnection();
+                       //prov.makeNodesConnection();   
+                       currentStaticNodes = getX( "STATIC_ROUTING_NODES", apiError );
+                       if (! apiError.is2xx() || currentStaticNodes == null ) {
+                               return false;
+                       }
+                       logger.info( "STATIC_ROUTING_NODES now=" + currentNodes );
+                       String[] nodeList = currentStaticNodes.split("\\|");
+                       for( String n: nodeList ) {
+                               logger.info( "compare existing node " + n + " vs " + aNode );
+                               if ( n.equals(aNode) ) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               
+
+               public void addStaticNode(String aNode, ApiError apiError) {
+                       currentStaticNodes = currentStaticNodes + "|" + aNode;
+                       setX( "STATIC_ROUTING_NODES", currentStaticNodes, apiError );
+               }
+               void removeStaticNode( String aNode, ApiError apiError ) {
+                       currentStaticNodes = removeFromList( aNode, currentStaticNodes );
+                       setX( "STATIC_ROUTING_NODES", currentStaticNodes, apiError );                   
+               }
+       }       
+       private Map<String, DR_Node> dr_nodes = DatabaseClass.getDr_nodes();
+       
+       public Map<String, DR_Node> getDr_Nodes() {
+               return dr_nodes;
+       }
+       
+       public List<DR_Node> getAllDr_Nodes() {
+               return new ArrayList<DR_Node>(dr_nodes.values());
+       }
+       
+       public DR_Node getDr_Node( String fqdn, ApiError apiError ) {
+               DR_Node old = dr_nodes.get( fqdn );
+               if ( old == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "fqdn");
+                       apiError.setMessage( "Node " + fqdn + " does not exist");
+                       return null;
+               }
+               apiError.setCode(200);
+               return old;
+       }
+
+       public DR_Node addDr_Node( DR_Node node, ApiError apiError ) {
+               String fqdn = node.getFqdn();
+               DR_Node old = dr_nodes.get( fqdn );
+               if ( old != null ) {
+                       apiError.setCode(Status.CONFLICT.getStatusCode());
+                       apiError.setFields( "fqdn");
+                       apiError.setMessage( "Node " + fqdn + " already exists");
+                       return null;
+               }
+               
+               DrProv drProv = new DrProv();
+
+               if ( ! drProv.containsNode( node.getFqdn(), apiError ) && apiError.is2xx() ) {
+                       drProv.addNode( node.getFqdn(), apiError );
+               }
+               if ( ! apiError.is2xx()) {
+                       return null;
+               }
+               DcaeLocationService locService = new DcaeLocationService();
+               if ( locService.isEdgeLocation( node.getDcaeLocationName()) && ! drProv.containsStaticNode( node.getFqdn(), apiError ) ) {
+                       if ( apiError.is2xx() ) {
+                               drProv.addStaticNode( node.getFqdn(), apiError );
+                       }
+               }
+               if ( ! apiError.is2xx()) {
+                       return null;
+               }
+               
+               node.setLastMod();
+               node.setStatus(DmaapObject_Status.VALID);
+               dr_nodes.put( node.getFqdn(), node );
+               apiError.setCode(200);
+               return node;
+       }
+       
+       public DR_Node updateDr_Node( DR_Node node, ApiError apiError ) {
+               DR_Node old = dr_nodes.get( node );
+               if ( old == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "fqdn");
+                       apiError.setMessage( "Node " + node + " does not exist");
+                       return null;
+               }
+               node.setLastMod();
+               dr_nodes.put( node.getFqdn(), node );
+               apiError.setCode(200);
+               return node;
+       }
+       
+       public DR_Node removeDr_Node( String nodeName, ApiError apiError ) {
+               DR_Node old = dr_nodes.get( nodeName );
+               if ( old == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "fqdn");
+                       apiError.setMessage( "Node " + nodeName + " does not exist");
+                       return null;
+               }
+               
+               DrProv drProv = new DrProv();
+               if ( drProv.containsNode( old.getFqdn(), apiError ) && apiError.is2xx() ) {
+                       drProv.removeNode( old.getFqdn(), apiError );
+               }
+               DcaeLocationService locService = new DcaeLocationService();
+               if ( locService.isEdgeLocation( old.getDcaeLocationName()) && drProv.containsStaticNode( old.getFqdn(), apiError ) ) {
+                       if ( apiError.is2xx()) {
+                               drProv.removeStaticNode( old.getFqdn(), apiError );
+                       }
+                       
+               }
+               
+               apiError.setCode(200);
+               return dr_nodes.remove(nodeName);
+       }               
+
+       public String getNodePatternAtLocation( String loc, boolean allowMult ) {
+               logger.info( "loc=" + loc );
+               if ( loc == null ) {
+                       return null;
+               }
+               StringBuilder str = new StringBuilder();
+               for( DR_Node node : dr_nodes.values() ) {
+                       if ( loc.equals( node.getDcaeLocationName()) ) {
+                               if ( str.length() > 0 ) {
+                                       str.append( ",");
+                               }
+                               str.append( node.getFqdn());
+                               if ( ! allowMult ) {
+                                       break;
+                               }
+                       }
+               }
+               logger.info( "returning " + str.toString() );
+               return str.toString();
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_PubService.java
new file mode 100644 (file)
index 0000000..ca60b8a
--- /dev/null
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.aaf.client.DrProvConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+
+public class DR_PubService  extends BaseLoggingClass{
+       
+       private Map<String, DR_Pub> dr_pubs = DatabaseClass.getDr_pubs();
+       private DR_NodeService nodeService = new DR_NodeService();
+       private static DrProvConnection prov;
+       
+       public DR_PubService() {
+               super();
+               prov = new DrProvConnection();
+       }
+
+       public Map<String, DR_Pub> getDr_Pubs() {                       
+               return dr_pubs;
+       }
+               
+       public List<DR_Pub> getAllDr_Pubs() {
+               return new ArrayList<DR_Pub>(dr_pubs.values());
+       }
+       
+       public ArrayList<DR_Pub> getDr_PubsByFeedId( String feedId ) {
+               ArrayList<DR_Pub> somePubs = new ArrayList<DR_Pub>();
+               for( DR_Pub pub : dr_pubs.values() ) {
+                       if ( feedId.equals(  pub.getFeedId()  )) {
+                               somePubs.add( pub );
+                       }
+               }
+                       
+               return somePubs;
+       }
+               
+       public DR_Pub getDr_Pub( String key, ApiError err ) {   
+               DR_Pub pub = dr_pubs.get( key );
+               if ( pub == null ) {
+                       err.setCode(Status.NOT_FOUND.getStatusCode());
+                       err.setFields( "pubId");
+                       err.setMessage("DR_Pub with pubId = " + key + " not found");
+               } else {
+                       err.setCode(Status.OK.getStatusCode());
+               }
+               return pub;
+       }
+       
+       private void addIngressRoute( DR_Pub pub, ApiError err ) {
+               
+               String nodePattern = nodeService.getNodePatternAtLocation( pub.getDcaeLocationName(), true );
+               if ( nodePattern != null && nodePattern.length() > 0 ) {
+                       logger.info( "creating ingress rule: pub " + pub.getPubId() + " on feed " + pub.getFeedId() + " to " + nodePattern);
+                       prov.makeIngressConnection( pub.getFeedId(), pub.getUsername(), "-", nodePattern);
+                       int rc = prov.doXgressPost(err);
+                       logger.info( "rc=" + rc + " error code=" + err.getCode() );
+                       
+                       if ( rc != 200 ) {
+                               switch( rc ) {
+                               case 403:
+                                       logger.error( "Not authorized for DR ingress API");
+                                       err.setCode(500);
+                                       err.setMessage("API deployment/configuration error - contact support");
+                                       err.setFields( "PROV_AUTH_ADDRESSES");
+                                       break;
+                               
+                               default: 
+                                       logger.info( DmaapbcLogMessageEnum.INGRESS_CREATE_ERROR, Integer.toString(rc),  pub.getPubId(), pub.getFeedId(), nodePattern);
+                               }
+                       }
+
+               }
+       }
+
+       public DR_Pub addDr_Pub( DR_Pub pub ) {
+               ApiError err = new ApiError();
+               if ( pub.getPubId() != null && ! pub.getPubId().isEmpty() ) {
+                       addIngressRoute( pub, err);
+                       if ( err.getCode() > 0 ) {
+                               pub.setStatus(DmaapObject_Status.INVALID);
+                       }
+                       pub.setLastMod();
+                       dr_pubs.put( pub.getPubId(), pub );
+                       return pub;
+               }
+               else {
+                       return null;
+               }
+       }
+               
+       public DR_Pub updateDr_Pub( DR_Pub pub ) {
+               if ( pub.getPubId().isEmpty()) {
+                       return null;
+               }
+               pub.setLastMod();
+               dr_pubs.put( pub.getPubId(), pub );
+               return pub;
+       }
+               
+       public DR_Pub removeDr_Pub( String pubId, ApiError err ) {
+
+               DR_Pub pub =  dr_pubs.get( pubId );
+               if ( pub == null ) {
+                       err.setCode(Status.NOT_FOUND.getStatusCode());
+                       err.setFields( "pubId");
+                       err.setMessage( "pubId " + pubId + " not found");
+               } else {
+                       dr_pubs.remove(pubId);
+                       err.setCode(Status.OK.getStatusCode());
+               }
+               return pub;
+                               
+       }       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DR_SubService.java
new file mode 100644 (file)
index 0000000..09bf8fd
--- /dev/null
@@ -0,0 +1,173 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.aaf.client.DrProvConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Sub;
+
+public class DR_SubService extends BaseLoggingClass {
+
+       private Map<String, DR_Sub> dr_subs = DatabaseClass.getDr_subs();
+       private DR_NodeService nodeService = new DR_NodeService();
+       private String provURL;
+       private static DrProvConnection prov;
+       
+       
+       public DR_SubService(  ) {
+               logger.debug( "Entry: DR_SubService (with no args)" );
+
+       }       
+       public DR_SubService( String subURL ) {
+               logger.debug( "Entry: DR_SubService " + subURL );
+               provURL = subURL;
+       }
+       public Map<String, DR_Sub> getDR_Subs() {
+               logger.debug( "enter getDR_Subs()");
+               return dr_subs;
+       }
+               
+       public List<DR_Sub> getAllDr_Subs() {
+               logger.debug( "enter getAllDR_Subs()");
+               return new ArrayList<DR_Sub>(dr_subs.values());
+       }
+       
+       public ArrayList<DR_Sub> getDr_SubsByFeedId( String pubId ) {
+               ArrayList<DR_Sub> someSubs = new ArrayList<DR_Sub>();
+               for( DR_Sub sub : dr_subs.values() ) {
+                       if ( pubId.equals(  sub.getFeedId()  )) {
+                               someSubs.add( sub );
+                       }
+               }
+                       
+               return someSubs;
+       }
+       public DR_Sub getDr_Sub( String key, ApiError apiError ) {      
+               logger.debug( "enter getDR_Sub()");
+               DR_Sub sub = dr_subs.get( key );
+               if ( sub == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "subId");
+                       apiError.setMessage("subId " + key + " not found");
+               } else {
+                       apiError.setCode(200);
+               }
+               return sub;
+       }
+
+       public DR_Sub addDr_Sub( DR_Sub sub, ApiError apiError ) {
+               logger.debug( "enter addDR_Subs()");
+               prov = new DrProvConnection();
+               prov.makeSubPostConnection( provURL );
+               String resp = prov.doPostDr_Sub( sub, apiError );
+               logger.debug( "resp=" + resp );
+
+               DR_Sub snew = null;
+
+               if ( resp != null ) {
+                       snew = new DR_Sub( resp );
+                       snew.setDcaeLocationName(sub.getDcaeLocationName());
+                       snew.setLastMod();
+                       addEgressRoute( snew, apiError );
+                       dr_subs.put( snew.getSubId(), snew );   
+                       apiError.setCode(200);
+               } else {
+                       apiError.setCode(400);
+               }
+               
+               return snew;
+       }
+
+       private void addEgressRoute( DR_Sub sub, ApiError err ) {
+               
+               String nodePattern = nodeService.getNodePatternAtLocation( sub.getDcaeLocationName(), false );
+               if ( nodePattern != null && nodePattern.length() > 0 ) {
+                       logger.info( "creating egress rule: sub " + sub.getSubId() + " on feed " + sub.getFeedId() + " to " + nodePattern);
+                       prov.makeEgressConnection( sub.getSubId(),  nodePattern);
+                       int rc = prov.doXgressPost(err);
+                       logger.info( "rc=" + rc + " error code=" + err.getCode() );
+                       
+                       if ( rc != 200 ) {
+                               switch( rc ) {
+                               case 403:
+                                       logger.error( "Not authorized for DR egress API");
+                                       err.setCode(500);
+                                       err.setMessage("API deployment/configuration error - contact support");
+                                       err.setFields( "PROV_AUTH_ADDRESSES");
+                                       break;
+                               
+                               default: 
+                                       logger.info( DmaapbcLogMessageEnum.EGRESS_CREATE_ERROR, Integer.toString(rc),  sub.getSubId(), sub.getFeedId(), nodePattern);
+                               }
+                       }
+
+               }
+       }
+       
+       public DR_Sub updateDr_Sub( DR_Sub obj, ApiError apiError ) {
+               logger.debug( "enter updateDR_Subs()");
+
+               DrProvConnection prov = new DrProvConnection();
+               prov.makeSubPutConnection( obj.getSubId() );
+               String resp = prov.doPutDr_Sub( obj, apiError );
+               logger.debug( "resp=" + resp );
+
+               DR_Sub snew = null;
+
+               if ( resp != null ) {
+                       snew = new DR_Sub( resp );
+                       snew.setDcaeLocationName(obj.getDcaeLocationName());
+                       snew.setLastMod();
+                       dr_subs.put( snew.getSubId(), snew );   
+                       apiError.setCode(200);
+               } else if ( apiError.is2xx()) {
+                       apiError.setCode(400);
+                       apiError.setMessage("unexpected empty response from DR Prov");
+               }
+               
+               return snew;
+       }
+               
+       public void removeDr_Sub( String key, ApiError apiError ) {
+               logger.debug( "enter removeDR_Subs()");
+               DR_Sub sub = dr_subs.get( key );
+               if ( sub == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "subId");
+                       apiError.setMessage("subId " + key + " not found");
+               } else {        
+                       dr_subs.remove(key);
+                       apiError.setCode(200);
+               }
+
+               return;
+       }       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DcaeLocationService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DcaeLocationService.java
new file mode 100644 (file)
index 0000000..44166b8
--- /dev/null
@@ -0,0 +1,97 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+
+
+
+
+
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+
+public class DcaeLocationService {
+       
+       private Map<String, DcaeLocation> dcaeLocations = DatabaseClass.getDcaeLocations();
+       
+       public Map<String, DcaeLocation> getDcaeLocations() {
+               return dcaeLocations;
+       }
+       
+       public List<DcaeLocation> getAllDcaeLocations() {
+               return new ArrayList<DcaeLocation>(dcaeLocations.values());
+       }
+       
+       public DcaeLocation getDcaeLocation( String name ) {
+               return dcaeLocations.get(name);
+       }
+
+       public DcaeLocation addDcaeLocation( DcaeLocation location ) {
+               location.setLastMod();
+               location.setStatus(DmaapObject_Status.VALID);
+               dcaeLocations.put( location.getDcaeLocationName(), location );
+               return location;
+       }
+       
+       public DcaeLocation updateDcaeLocation( DcaeLocation location ) {
+               if ( location.getDcaeLocationName().isEmpty()) {
+                       return null;
+               }
+               location.setLastMod();
+               dcaeLocations.put( location.getDcaeLocationName(), location );
+               return location;
+       }
+       
+       public DcaeLocation removeDcaeLocation( String locationName ) {
+               return dcaeLocations.remove(locationName);
+       }
+
+       public String getCentralLocation() {
+               for( Map.Entry<String, DcaeLocation> entry: dcaeLocations.entrySet() ) {
+                       DcaeLocation loc = entry.getValue();
+                       if ( loc.isCentral() ) {
+                               // use the name of the first central location we hit
+                               return loc.getDcaeLocationName();
+                       }
+                       
+               }
+               return "aCentralLocation";  // default value that is obvious to see is wrong
+       }       
+       
+       public boolean isEdgeLocation(String aName) {
+               DcaeLocation loc = dcaeLocations.get(aName);
+               if ( ! loc.isCentral() ) {
+                               return true;
+               }
+               return false;
+       }       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/DmaapService.java b/src/main/java/org/onap/dmaap/dbcapi/service/DmaapService.java
new file mode 100644 (file)
index 0000000..8436820
--- /dev/null
@@ -0,0 +1,264 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+
+
+
+
+
+
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.AafService;
+import org.onap.dmaap.dbcapi.aaf.DmaapGrant;
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType;
+import org.onap.dmaap.dbcapi.aaf.authentication.ApiPerms;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.model.MR_Client;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.Singleton;
+
+public class DmaapService  extends BaseLoggingClass  {
+
+       
+       private Singleton<Dmaap> dmaapholder = DatabaseClass.getDmaap();
+       
+       // TODO put these in properties file
+       String topicFactory; // = "org.openecomp.dcae.dmaap.topicFactory";
+       String topicMgrRole; // = "org.openecomp.dmaapBC.TopicMgr";
+       
+       // TODO confirm this is  equivalent to dmaap.getTopicNsRoot() so we can retire it
+       String dcaeTopicNs; // = "org.openecomp.dcae.dmaap";
+       
+       
+       public DmaapService() {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               topicFactory = p.getProperty("MR.TopicFactoryNS", "MR.topicFactoryNS.not.set");
+               topicMgrRole = p.getProperty("MR.TopicMgrRole", "MR.TopicMgrRole.not.set" );
+               dcaeTopicNs = dmaapholder.get().getTopicNsRoot();
+               
+       }
+       
+       public Dmaap getDmaap() {
+               logger.info( "entering getDmaap()" );
+               return(dmaapholder.get());
+       }
+       
+       public Dmaap addDmaap( Dmaap nd ) {
+               
+               logger.info( "entering addDmaap()" );
+               Dmaap dmaap = dmaapholder.get();
+               if ( dmaap.getVersion().equals( "0")) {
+
+                       nd.setLastMod();
+                       dmaapholder.update(nd);
+
+                       AafService aaf = new AafService( ServiceType.AAF_Admin);
+                       ApiPerms p = new ApiPerms();
+                       p.setEnvMap();
+                       boolean anythingWrong = setTopicMgtPerms(  nd,  aaf ) || createMmaTopic();
+                                       
+                       if ( anythingWrong ) {
+                               dmaap.setStatus(DmaapObject_Status.INVALID); 
+                       }
+                       else {
+                               dmaap.setStatus(DmaapObject_Status.VALID);  
+                       }
+                       dmaap.setLastMod();
+                       dmaapholder.update(dmaap);
+
+                       return dmaap;
+               
+               }
+               else { 
+                       return dmaap;
+               }
+       }
+       
+       public Dmaap updateDmaap( Dmaap nd ) {
+               logger.info( "entering updateDmaap()" );
+               
+               boolean anythingWrong = false;
+
+               Dmaap dmaap = dmaapholder.get();
+               
+               // some triggers for when we attempt to reprovision perms and MMA topic:
+               // - if the DMaaP Name changes
+               // - if the version is 0  (this is a handy test to force this processing by updating the DB)
+               // - if the object is invalid, reprocessing might fix it.
+               if ( ! dmaap.isStatusValid()  || ! nd.getDmaapName().equals(dmaap.getDmaapName()) || dmaap.getVersion().equals( "0") ) {
+                       nd.setLastMod();
+                       dmaapholder.update(nd);  //need to set this so the following perms will pick up any new vals.
+                       ApiPerms p = new ApiPerms();
+                       p.setEnvMap();
+                       AafService aaf = new AafService( ServiceType.AAF_Admin);
+                       anythingWrong = setTopicMgtPerms(  nd,  aaf ) || createMmaTopic();
+               }
+                                       
+               if ( anythingWrong ) {
+                       nd.setStatus(DmaapObject_Status.INVALID); 
+               }
+               else {
+                       nd.setStatus(DmaapObject_Status.VALID);  
+               }
+               nd.setLastMod();
+               dmaapholder.update(nd);  // may need to update status...
+               return(dmaapholder.get());
+               
+       }
+       
+       public String getTopicPerm(){
+               Dmaap dmaap = dmaapholder.get();
+               return getTopicPerm( dmaap.getDmaapName() );
+       }
+       public String getTopicPerm( String val ) {
+               Dmaap dmaap = dmaapholder.get();
+               return dmaap.getTopicNsRoot() + "." + val + ".mr.topic";
+       }
+       
+       public String getBridgeAdminFqtn(){
+               Dmaap dmaap = dmaapholder.get();
+               String topic = dmaap.getBridgeAdminTopic();
+               
+               // check if this is already an fqtn (contains a dot)
+               // otherwise build it
+               if ( topic.indexOf('.') < 0 ) {
+                       topic = dmaap.getTopicNsRoot() + "." + dmaap.getDmaapName() + "." + dmaap.getBridgeAdminTopic();
+               }
+               return( topic );
+       }
+
+       private boolean setTopicMgtPerms( Dmaap nd, AafService aaf ){
+               String[] actions = { "create", "destroy" };
+               String instance = ":" + dcaeTopicNs + "." + nd.getDmaapName() + ".mr.topic:" + dcaeTopicNs + "." + nd.getDmaapName();
+               
+               for( String action : actions ) {
+
+                       DmaapPerm perm = new DmaapPerm( topicFactory, instance, action );
+               
+                       int rc = aaf.addPerm( perm );
+                       if ( rc != 201 &&  rc != 409 ) {
+                               logger.error( "unable to add perm for "+ topicFactory + "|" + instance + "|" + action );
+                               return true;
+                       }
+
+                       DmaapGrant grant = new DmaapGrant( perm, topicMgrRole );
+                       rc = aaf.addGrant( grant );
+                       if ( rc != 201 && rc != 409 ) {
+                               logger.error( "unable to grant to " + topicMgrRole + " perm for "+ topicFactory + "|" + instance + "|" + action );
+                               return true;
+                       }
+               }
+               
+               String t = dcaeTopicNs +"." + nd.getDmaapName() + ".mr.topic";
+               String[] s = { "view", "pub", "sub" };
+               actions = s;
+               instance = "*";
+               
+               for( String action : actions ) {
+
+                       DmaapPerm perm = new DmaapPerm( t, instance, action );
+               
+                       int rc = aaf.addPerm( perm );
+                       if ( rc != 201 &&  rc != 409 ) {
+                               errorLogger.error( DmaapbcLogMessageEnum.AAF_UNEXPECTED_RESPONSE, Integer.toString(rc), "add perm", t + "|" + instance + "|" + action );
+                               return true;
+                       }
+
+                       DmaapGrant grant = new DmaapGrant( perm, topicMgrRole );
+                       rc = aaf.addGrant( grant );
+                       if ( rc != 201 && rc != 409 ) {
+                               errorLogger.error( DmaapbcLogMessageEnum.AAF_UNEXPECTED_RESPONSE, Integer.toString(rc), "grant to " + topicMgrRole + " perm ", topicFactory + "|" + instance + "|" + action );
+                               return true;
+                       }
+                               
+               }
+               return false;
+       }
+       
+       // create the special topic for MMA provisioning.
+       // return true indicating a problem in topic creation, 
+       // else false means it was ok  (created or previously existed)
+       private boolean createMmaTopic() {
+               boolean rc = true;
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               Dmaap dmaap = dmaapholder.get();
+               
+               ArrayList<MR_Client> clients = new ArrayList<MR_Client>();
+               String[] actions = { "pub", "sub", "view" };
+               String centralMR = new DcaeLocationService().getCentralLocation();
+               if ( centralMR == null ) {
+                       return rc;
+               }
+               logger.info( "Location for " + dmaap.getBridgeAdminTopic() + " is " + centralMR );
+       
+               // first client is the Role used by Bus Controller to send messages to MMA
+               String provRole = p.getProperty("MM.ProvRole");
+               MR_Client nClient = new MR_Client();
+               nClient.setAction(actions);
+               nClient.setClientRole(provRole);
+               nClient.setDcaeLocationName(centralMR);
+               clients.add( nClient );
+       
+               // second client is the Role used by MMA to listen to messages from Bus Controller
+               String agentRole = p.getProperty("MM.AgentRole");
+               nClient = new MR_Client();
+               nClient.setAction(actions);
+               nClient.setClientRole(agentRole);
+               nClient.setDcaeLocationName(centralMR);
+               clients.add( nClient );
+       
+               // initialize Topic
+               Topic mmaTopic = new Topic();
+               mmaTopic.setTopicName(dmaap.getBridgeAdminTopic());
+               mmaTopic.setClients(clients);
+               mmaTopic.setOwner("BusController");
+               mmaTopic.setTopicDescription("topic reserved for MirrorMaker Administration");
+               mmaTopic.setTnxEnabled("false");
+               
+               ApiError err = new ApiError();
+               TopicService svc = new TopicService();
+               try {
+                       @SuppressWarnings("unused")
+                       Topic nTopic = svc.addTopic(mmaTopic, err);
+                       if ( err.is2xx() || err.getCode() == 409 ) {
+                               return false;
+                       }
+               } catch ( Exception e) {
+                       errorLogger.error( DmaapbcLogMessageEnum.UNEXPECTED_CONDITION, " while adding Topic: " + e.getMessage());
+               }
+               errorLogger.error( DmaapbcLogMessageEnum.TOPIC_CREATE_ERROR,  dmaap.getBridgeAdminTopic(), err.getFields(), err.getFields(), err.getMessage());
+               
+               return rc;
+               
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java b/src/main/java/org/onap/dmaap/dbcapi/service/FeedService.java
new file mode 100644 (file)
index 0000000..f5ea4df
--- /dev/null
@@ -0,0 +1,359 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.log4j.Logger;
+import org.onap.dmaap.dbcapi.aaf.client.DrProvConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DR_Pub;
+import org.onap.dmaap.dbcapi.model.DR_Sub;
+import org.onap.dmaap.dbcapi.model.Feed;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class FeedService  extends BaseLoggingClass {
+       
+       private Map<String, Feed> feeds = DatabaseClass.getFeeds();
+       private DR_PubService pubService = new DR_PubService();
+       private DR_SubService subService = new DR_SubService();
+       private DcaeLocationService dcaeLocations = new DcaeLocationService();
+       private String deleteHandling;
+       
+       public FeedService() {
+               logger.info( "new FeedService");
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               deleteHandling = p.getProperty("Feed.deleteHandling", "DeleteOnDR");
+
+       }
+       
+       public Map<String, Feed> getFeeds() {                   
+               return feeds;
+       }
+       
+       private void getSubObjects( Feed f ) {
+               ArrayList<DR_Pub> pubs = pubService.getDr_PubsByFeedId( f.getFeedId() );
+               f.setPubs(pubs);
+               ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( f.getFeedId() );
+               f.setSubs(subs);        
+       }
+               
+       public List<Feed> getAllFeeds() {
+               ArrayList<Feed> fatFeeds = new ArrayList<Feed>();
+               for( Feed f:  feeds.values() ) {
+                       getSubObjects(f);
+                       fatFeeds.add(f);
+               }
+               return fatFeeds;
+       }
+       
+       
+       private Feed _getFeed( String key, ApiError err, boolean flag ) {
+               Feed f = feeds.get( key );
+               if ( f != null && ( flag || f.getStatus() != DmaapObject_Status.DELETED ) ) {
+                       getSubObjects( f );
+               } else {
+                       err.setCode(Status.NOT_FOUND.getStatusCode());
+                       err.setMessage("feed not found");
+                       err.setFields("feedId=" + key );
+                       return null;
+               }
+               err.setCode(200);
+               return f;
+       }
+       public Feed getFeed( String key, ApiError err ) {
+               return _getFeed( key, err, false );
+       }
+       public Feed getFeedPure( String key, ApiError err ) {
+               return _getFeed( key, err, true );
+       }
+       
+       public Feed getFeedByName( String name, String ver, ApiError err ) {
+               for( Feed f:  feeds.values() ) {
+                       if ( f.getFeedName().equals( name ) && f.getFeedVersion().equals(ver) ) {
+                               getSubObjects(f);
+                               return f;
+                       }
+       
+               }
+               err.setCode(Status.NOT_FOUND.getStatusCode());
+               err.setMessage("feed not found");
+               err.setFields("feedName=" + name + " and ver=" + ver );
+               return null;
+       
+       }
+
+       private boolean savePubs( Feed f ) {
+               return savePubs( f, f );
+       }
+       // need to save the Pub objects independently and copy pubId from original request
+       private boolean savePubs( Feed fnew, Feed req ) {
+               // save any pubs
+               DR_PubService pubSvc = new DR_PubService();
+               ArrayList<DR_Pub> reqPubs = req.getPubs();
+               ArrayList<DR_Pub> newPubs = fnew.getPubs();
+               
+
+               
+               int nSize = newPubs.size();
+               int rSize = reqPubs.size();
+               logger.info( "reqPubs size=" + rSize + " newPubs size=" + nSize );
+               if ( nSize != rSize ) {
+                       errorLogger.error( "Resulting set of publishers do not match requested set of publishers " + nSize + " vs " + rSize );
+                       fnew.setStatus( DmaapObject_Status.INVALID);
+                       return false;
+               }
+               // NOTE: when i > 1 newPubs are in reverse order from reqPubs
+               for( int i = 0; i < reqPubs.size(); i++ ) {
+                       DR_Pub reqPub = reqPubs.get(i); 
+                       ApiError err = new ApiError();
+                       if ( pubSvc.getDr_Pub( reqPub.getPubId(), err ) == null ) {
+                               DR_Pub newPub = newPubs.get(nSize - i - 1);
+                               reqPub.setPubId(newPub.getPubId());
+                               reqPub.setFeedId(newPub.getFeedId());
+                               reqPub.setStatus(DmaapObject_Status.VALID);
+                               if ( reqPub.getDcaeLocationName() == null ) {
+                                       reqPub.setDcaeLocationName("notSpecified");
+                               }
+                               pubSvc.addDr_Pub( reqPub );
+                       }
+                       
+               }
+               
+               fnew.setPubs(reqPubs);
+               fnew.setStatus(DmaapObject_Status.VALID);
+               return true;
+
+       }
+       
+       private boolean saveSubs( Feed f ) {
+               return saveSubs( f, f );
+       }
+       // need to save the Sub objects independently
+       private boolean saveSubs( Feed fnew, Feed req ) {       
+               ArrayList<DR_Sub> subs = req.getSubs();
+               if ( subs.size() == 0 ) {
+                       logger.info( "No subs specified");
+               } else {
+                       DR_SubService subSvc = new DR_SubService( fnew.getSubscribeURL() );
+                       ApiError err = new ApiError();
+                       for( int i = 0; i <  subs.size(); i++ ) {
+                               DR_Sub sub = subs.get(i);
+                               if ( subSvc.getDr_Sub( sub.getSubId(), err) == null ) {
+                                       subs.set( i,  subSvc.addDr_Sub(sub, err));
+                                       if ( ! err.is2xx())  {
+                                               logger.error( "i=" + i + " url=" + sub.getDeliveryURL() + " err=" + err.getCode() );
+                                               return false;
+                                       }
+                               }
+                               
+                       }
+                       fnew.setSubs(subs);
+               }
+
+
+               fnew.setStatus(DmaapObject_Status.VALID);
+               return true;
+
+       }
+
+       public  Feed addFeed( Feed req, ApiError err ) {
+
+               // at least 1 pub is required by DR, so create a default pub if none is specified
+               if ( req.getPubs().size() == 0 ) {
+                       logger.info( "No pubs specified - creating tmp pub");
+                       ArrayList<DR_Pub> pubs = new ArrayList<DR_Pub>();
+                       pubs.add( new DR_Pub( dcaeLocations.getCentralLocation())
+                                                               .setRandomUserName()
+                                                               .setRandomPassword());
+                       req.setPubs(pubs);
+               } 
+               
+
+               DrProvConnection prov = new DrProvConnection();
+               prov.makeFeedConnection();      
+               String resp = prov.doPostFeed( req, err );
+               logger.info( "resp=" + resp );
+               if ( resp == null ) {
+                       switch( err.getCode() ) {
+                       case 400: 
+                               err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
+                               break;
+                       case 403:
+                               err.setCode(500);
+                               err.setMessage("API deployment/configuration error - contact support");
+                               err.setFields( "PROV_AUTH_ADDRESSES");
+                               logger.error( "Prov response: 403. " + err.getMessage() + " regarding " + err.getFields() );
+                               break;
+                       default:
+                               err.setCode(500);
+                               err.setMessage( "Unexpected response from DR backend" );
+                               err.setFields("response");
+                       }
+                       return null;
+
+               }
+
+
+               Feed fnew = new Feed( resp );
+               logger.info( "fnew status is:" + fnew.getStatus() );
+               if ( ! fnew.isStatusValid()) {          
+                       err.setCode(500);
+                       err.setMessage( "Unexpected response from DR backend" );
+                       err.setFields("response");              
+                       return null;
+               }
+               
+               //saveChildren( fnew, req );
+               if ( ! savePubs( fnew, req ) || ! saveSubs( fnew, req ) ) {
+                       err.setCode(Status.BAD_REQUEST.getStatusCode());
+                       err.setMessage("Unable to save Pub or Sub objects");
+                       return null;
+               }
+               fnew.setFormatUuid(req.getFormatUuid());
+               fnew.setLastMod();
+               feeds.put( fnew.getFeedId(), fnew );
+               return fnew;
+       }
+               
+       public Feed updateFeed( Feed req, ApiError err ) {
+       
+               // at least 1 pub is required by DR, so create a default pub if none is specified
+               if ( req.getPubs().size() == 0 ) {
+                       logger.info( "No pubs specified - creating tmp pub");
+                       ArrayList<DR_Pub> pubs = new ArrayList<DR_Pub>();
+                       pubs.add( new DR_Pub( dcaeLocations.getCentralLocation())
+                                                               .setRandomUserName()
+                                                               .setRandomPassword());
+                       req.setPubs(pubs);
+               } 
+               
+               DrProvConnection prov = new DrProvConnection();
+               prov.makeFeedConnection( req.getFeedId() );
+               String resp = prov.doPutFeed( req, err );
+               logger.info( "resp=" + resp );
+               if ( resp == null ) {
+                       switch( err.getCode() ) {
+                       case 400: 
+                               err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
+                               break;
+                       case 403:
+                               err.setCode(500);
+                               err.setMessage("API deployment/configuration error - contact support");
+                               err.setFields( "PROV_AUTH_ADDRESSES");
+                               break;
+                       default:
+                               err.setCode(500);
+                               err.setMessage( "Unexpected response from DR backend" );
+                               err.setFields("response");
+                       }
+                       return null;
+               }
+
+
+               Feed fnew = new Feed( resp );
+               logger.info( "fnew status is:" + fnew.getStatus() );
+               if ( ! fnew.isStatusValid()) {          
+                       err.setCode(500);
+                       err.setMessage( "Unexpected response from DR backend" );
+                       err.setFields("response");              
+                       return null;
+               }
+
+               if ( ! savePubs( fnew, req ) || ! saveSubs( fnew, req ) ) {
+                       err.setCode(Status.BAD_REQUEST.getStatusCode());
+                       err.setMessage("Unable to save Pub or Sub objects");
+                       return null;
+               }
+               fnew.setFormatUuid(req.getFormatUuid());
+               fnew.setLastMod();
+               feeds.put( fnew.getFeedId(), fnew );
+               return fnew;
+       }
+       
+       
+       //
+       // DR does not actually delete a feed, so we provide two behaviors:
+       // 1) clean up the feed by removing all subs and pubs, mark it here as DELETED.
+       //    then client can add it back if desired.
+       // 2) Call the DR Delete function.  Feed with the same name and version can never be added again
+       //
+       public Feed removeFeed( Feed req, ApiError err ) {
+               
+               // strip pubs and subs from feed first no matter what
+               ArrayList<DR_Pub> pubs = pubService.getDr_PubsByFeedId( req.getFeedId() );
+               for( DR_Pub pub: pubs ) {
+                       pubService.removeDr_Pub(pub.getPubId(), err);
+                       if ( ! err.is2xx()) {
+                               return req;
+                       }
+               }
+               ArrayList<DR_Sub> subs = subService.getDr_SubsByFeedId( req.getFeedId() );
+               for ( DR_Sub sub: subs ) {
+                       subService.removeDr_Sub(sub.getSubId(), err);
+                       if ( ! err.is2xx()) {
+                               return req;
+                       }
+               }
+       
+               if ( deleteHandling.equalsIgnoreCase("DeleteOnDR")) {
+                       DrProvConnection prov = new DrProvConnection();
+                       prov.makeFeedConnection( req.getFeedId() );
+                       String resp = prov.doDeleteFeed( req, err );
+                       logger.info( "resp=" + resp );
+                       if ( resp == null ) {
+                               switch( err.getCode() ) {
+                               case 400: 
+                                       err.setFields( "feedName=" + req.getFeedName() + " + feedVersion=" + req.getFeedVersion() );
+                                       break;
+                               case 403:
+                                       err.setCode(500);
+                                       err.setMessage("API deployment/configuration error - contact support");
+                                       err.setFields( "PROV_AUTH_ADDRESSES");
+                                       break;
+                               default:
+                                       err.setCode(500);
+                                       err.setMessage( "Unexpected response from DR backend" );
+                                       err.setFields("response");
+                               }
+                               return req;  // return back the requested feed - implies it wasn't removed
+                       }
+                       return feeds.remove(req.getFeedId());
+               } else {
+                       req.setStatus(DmaapObject_Status.DELETED);
+                       req.setPubs(null);
+                       req.setSubs(null);
+                       req.setLastMod();
+                       feeds.put( req.getFeedId(), req );
+                       return null;
+               }
+
+               
+       }       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java b/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClientService.java
new file mode 100644 (file)
index 0000000..68b340f
--- /dev/null
@@ -0,0 +1,289 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+
+
+
+
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.AafService;
+import org.onap.dmaap.dbcapi.aaf.DmaapGrant;
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType;
+import org.onap.dmaap.dbcapi.aaf.client.MrProvConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.MR_Client;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+
+public class MR_ClientService extends BaseLoggingClass{
+
+       private int deleteLevel;
+       private Map<String, MR_Client> mr_clients = DatabaseClass.getMr_clients();
+       private Map<String, MR_Cluster> clusters = DatabaseClass.getMr_clusters();
+       private Map<String, Topic> topics = DatabaseClass.getTopics();
+       private Map<String, DcaeLocation> locations = DatabaseClass.getDcaeLocations();
+       private DmaapService dmaap = new DmaapService();
+       
+       public MR_ClientService() {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               
+               deleteLevel = Integer.valueOf(p.getProperty("MR.ClientDeleteLevel", "0" ));
+       }
+       
+       public Map<String, MR_Client> getMR_Clients() {                 
+               return mr_clients;
+       }
+               
+       public List<MR_Client> getAllMr_Clients() {
+               return new ArrayList<MR_Client>(mr_clients.values());
+       }
+       
+       public ArrayList<MR_Client> getAllMrClients(String fqtn) {
+               ArrayList<MR_Client> results = new ArrayList<MR_Client>();
+               for (Map.Entry<String, MR_Client> entry : mr_clients.entrySet())
+               {
+                       MR_Client client = entry.getValue();
+                   if ( fqtn.equals(client.getFqtn() ) ) {
+                       results.add( client );
+                   }
+               }
+               return results;
+       }       
+
+       public ArrayList<MR_Client> getClientsByLocation(String location) {
+               ArrayList<MR_Client> results = new ArrayList<MR_Client>();
+               for (Map.Entry<String, MR_Client> entry : mr_clients.entrySet())
+               {
+                       MR_Client client = entry.getValue();
+                   if ( location.equals(client.getDcaeLocationName() ) ) {
+                       results.add( client );
+                   }
+               }
+               return results;
+       }       
+       
+       public void refreshClients( String location ) {
+               ApiError err = new ApiError();
+               ArrayList<MR_Client> clients = getClientsByLocation( location );
+               for( MR_Client client : clients ) {
+                       Topic topic = topics.get(client.getFqtn());
+                       if ( topic != null ) {
+                               addMr_Client( client, topic, err);
+                       }
+                       
+                       
+               }
+       }
+       
+       public MR_Client getMr_Client( String key, ApiError apiError ) {                        
+               MR_Client c =  mr_clients.get( key );
+               if ( c == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "mrClientId");
+                       apiError.setMessage("mrClientId " + key + " not found" );
+               } else {
+                       apiError.setCode(200);
+               }
+               return c;
+       }
+
+       public MR_Client addMr_Client( MR_Client client, Topic topic, ApiError err ) {
+               if ( client.getDcaeLocationName().isEmpty()) {
+                       logger.info( "Client  dcaeLocation that doesn't exist or not specified" );
+                       return null;
+               }
+               grantClientPerms(  client,  err);
+               if ( ! client.isStatusValid()) {
+                       return null;
+               }
+               String centralFqdn = null;
+               DcaeLocation candidate = locations.get(client.getDcaeLocationName());
+               if ( candidate != null && candidate.isCentral() ) {
+                       DmaapConfig p = ( DmaapConfig)DmaapConfig.getConfig();
+                       centralFqdn = p.getProperty("MR.CentralCname");
+               }
+               MR_Cluster cluster = clusters.get( client.getDcaeLocationName());
+               if (  cluster != null ) {
+                       client.setTopicURL(cluster.genTopicURL(centralFqdn, client.getFqtn()));
+                       if ( centralFqdn == null ) {
+                               client.setStatus( addTopicToCluster( cluster, topic, err));
+                               if( ! err.is2xx() && err.getCode() != 409 ) {
+                                       topic.setFqtn(err.getMessage());
+                                       return null;
+                               }
+                       
+                       } else {
+                               MR_ClusterService clusters = new MR_ClusterService();   
+                               // in 1610, MM should only exist for edge-to-central
+                               //  we use a cname for the central target
+                               // but still need to provision topics on all central MRs
+                               for( MR_Cluster central: clusters.getCentralClusters() ) {
+                                       client.setStatus( addTopicToCluster( central, topic, err));
+                                       if( ! err.is2xx() && err.getCode() != 409 ) {
+                                               topic.setFqtn(err.getMessage());
+                                               return null;
+                                       }
+                               }
+                       }
+                       
+               } else {
+                       logger.info( "Client references a dcaeLocation that doesn't exist:" + client.getDcaeLocationName());
+                       client.setStatus( DmaapObject_Status.STAGED);
+                       //return null;
+               }
+
+               mr_clients.put( client.getMrClientId(), client );
+
+               err.setCode(200);
+               
+               return client;
+       }
+       
+       private DmaapObject_Status addTopicToCluster( MR_Cluster cluster, Topic topic, ApiError err  ){
+               
+               MrProvConnection prov = new MrProvConnection();
+               logger.info( "POST topic " + topic.getFqtn() + " to cluster " + cluster.getFqdn() + " in loc " + cluster.getDcaeLocationName());
+               if ( prov.makeTopicConnection(cluster)) {
+                       String resp = prov.doPostTopic(topic, err);
+                       logger.info( "response code: " + err.getCode() );
+                       if ( err.is2xx() || err.getCode() == 409 ) {
+                               return DmaapObject_Status.VALID;
+                       } 
+               }
+               return DmaapObject_Status.INVALID;
+       }
+       
+       private void grantClientPerms( MR_Client client, ApiError err) {
+               AafService aaf = new AafService(ServiceType.AAF_TopicMgr);
+               
+               String instance = ":topic." + client.getFqtn();
+               client.setStatus( DmaapObject_Status.VALID);
+               for( String want : client.getAction() ) {
+                       int rc;
+                       DmaapPerm perm = new DmaapPerm( dmaap.getTopicPerm(), instance, want );
+                       DmaapGrant g = new DmaapGrant( perm, client.getClientRole() );
+                       rc = aaf.addGrant( g );
+                       if ( rc != 201 && rc != 409 ) {
+                               client.setStatus( DmaapObject_Status.INVALID);
+                               err.setCode(rc);
+                               err.setMessage( "Grant of " + dmaap.getTopicPerm() + "|" + instance + "|" + want + " failed for " + client.getClientRole() );
+                               logger.warn( err.getMessage());
+                               return;
+                       } 
+               }
+       }
+       
+       private void revokeClientPerms( MR_Client client, ApiError err) {
+               AafService aaf = new AafService(ServiceType.AAF_TopicMgr);
+               
+               String instance = ":topic." + client.getFqtn();
+               client.setStatus( DmaapObject_Status.VALID);
+               for( String want : client.getAction() ) {
+                       int rc;
+                       DmaapPerm perm = new DmaapPerm( dmaap.getTopicPerm(), instance, want );
+                       DmaapGrant g = new DmaapGrant( perm, client.getClientRole() );
+                       rc = aaf.delGrant( g );
+                       if ( rc != 200 && rc != 404 ) {
+                               client.setStatus( DmaapObject_Status.INVALID);
+                               err.setCode(rc);
+                               err.setMessage( "Revoke of " + dmaap.getTopicPerm() + "|" + instance + "|" + want + " failed for " + client.getClientRole() );
+                               logger.warn( err.getMessage());
+                               return;
+                       } 
+               }
+       }
+       
+       public MR_Client updateMr_Client( MR_Client client, ApiError apiError ) {
+               MR_Client c =  mr_clients.get( client.getMrClientId());
+               if ( c == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "mrClientId");
+                       apiError.setMessage("mrClientId " + client.getMrClientId() + " not found" );
+               } else {
+                       apiError.setCode(200);
+               }
+               mr_clients.put( client.getMrClientId(), client );
+               return client;
+       }
+               
+       public void removeMr_Client( String key, boolean updateTopicView, ApiError apiError ) {
+               MR_Client client =  mr_clients.get( key );
+               if ( client == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "mrClientId");
+                       apiError.setMessage("mrClientId " + key + " not found" );
+                       return;
+               } else {
+                       apiError.setCode(200);
+               }
+               
+               if ( updateTopicView == true ) {
+
+                       TopicService topics = new TopicService();
+                       
+                       Topic t = topics.getTopic(client.getFqtn(), apiError );
+                       if ( t != null ) {      
+                               ArrayList<MR_Client> tc = t.getClients();
+                               for( MR_Client c: tc) {
+                                       if ( c.getMrClientId().equals(client.getMrClientId())) {
+                                               tc.remove(c);
+                                               break;
+                                       }
+                               }
+                               t.setClients(tc);
+                               topics.updateTopic( t, apiError );
+                       }
+
+               }
+
+               
+               // remove from AAF
+               if ( deleteLevel >= 2 ) {
+                       revokeClientPerms( client, apiError );
+                       if ( ! apiError.is2xx()) {
+                               return;
+                       }
+               }
+               // remove from DB 
+               if ( deleteLevel >= 1 ) {
+                       mr_clients.remove(key);
+               }
+
+               return;
+       }
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClusterService.java b/src/main/java/org/onap/dmaap/dbcapi/service/MR_ClusterService.java
new file mode 100644 (file)
index 0000000..977288b
--- /dev/null
@@ -0,0 +1,149 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+
+
+
+
+
+
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+
+public class MR_ClusterService extends BaseLoggingClass {
+
+       private Map<String, MR_Cluster> mr_clusters = DatabaseClass.getMr_clusters();
+       
+       public Map<String, MR_Cluster> getMR_Clusters() {                       
+               return mr_clusters;
+       }
+               
+       public List<MR_Cluster> getAllMr_Clusters() {
+               return new ArrayList<MR_Cluster>(mr_clusters.values());
+       }
+               
+       public MR_Cluster getMr_Cluster( String key, ApiError apiError ) {                      
+               MR_Cluster mrc = mr_clusters.get( key );
+               if ( mrc == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "dcaeLocationName");
+                       apiError.setMessage( "Cluster with dcaeLocationName " + key + " not found");
+               }
+               apiError.setCode(200);
+               return mrc;
+       }
+       public MR_Cluster getMr_ClusterByFQDN( String key ) {           
+               for( MR_Cluster cluster: mr_clusters.values() ) {
+                       if ( key.equals( cluster.getFqdn() ) ) {
+                               return cluster;
+                       }
+               }
+               return null;
+       }
+       
+       public List<MR_Cluster> getCentralClusters() {
+               DcaeLocationService locations = new DcaeLocationService();
+               List<MR_Cluster> result = new ArrayList<MR_Cluster>();
+               for( MR_Cluster c: mr_clusters.values() ) {
+                       if ( locations.getDcaeLocation(c.getDcaeLocationName()).isCentral() ) {
+                               result.add(c);
+                       }
+               }
+               return result;
+       }       
+
+       public MR_Cluster addMr_Cluster( MR_Cluster cluster, ApiError apiError ) {
+               logger.info( "Entry: addMr_Cluster");
+               MR_Cluster mrc = mr_clusters.get( cluster.getDcaeLocationName() );
+               if ( mrc != null ) {
+                       apiError.setCode(Status.CONFLICT.getStatusCode());
+                       apiError.setFields( "dcaeLocationName");
+                       apiError.setMessage( "Cluster with dcaeLocationName " + cluster.getDcaeLocationName() + " already exists");
+                       return null;
+               }
+               cluster.setLastMod();
+               cluster.setStatus(DmaapObject_Status.VALID);
+               mr_clusters.put( cluster.getDcaeLocationName(), cluster );
+               DcaeLocationService svc = new DcaeLocationService();
+               DcaeLocation loc = svc.getDcaeLocation( cluster.getDcaeLocationName() );
+               if ( loc != null && loc.isCentral() ) {
+                       ApiError resp = TopicService.setBridgeClientPerms( cluster );
+                       if ( ! resp.is2xx() ) {
+                               logger.error( "Unable to provision Bridge to " + cluster.getDcaeLocationName() );
+                               cluster.setLastMod();
+                               cluster.setStatus(DmaapObject_Status.INVALID);
+                               mr_clusters.put( cluster.getDcaeLocationName(), cluster );
+                       }
+               }
+               apiError.setCode(200);
+               return cluster;
+       }
+               
+       public MR_Cluster updateMr_Cluster( MR_Cluster cluster, ApiError apiError ) {
+               MR_Cluster mrc = mr_clusters.get( cluster.getDcaeLocationName() );
+               if ( mrc == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "dcaeLocationName");
+                       apiError.setMessage( "Cluster with dcaeLocationName " + cluster.getDcaeLocationName() + " not found");
+                       return null;
+               }
+               cluster.setLastMod();
+               mr_clusters.put( cluster.getDcaeLocationName(), cluster );
+               DcaeLocationService svc = new DcaeLocationService();
+               DcaeLocation loc = svc.getDcaeLocation( cluster.getDcaeLocationName() );
+               if ( loc.isCentral() ) {
+                       ApiError resp = TopicService.setBridgeClientPerms( cluster );
+                       if ( ! resp.is2xx() ) {
+                               logger.error( "Unable to provision Bridge to " + cluster.getDcaeLocationName() );
+                               cluster.setLastMod();
+                               cluster.setStatus(DmaapObject_Status.INVALID);
+                               mr_clusters.put( cluster.getDcaeLocationName(), cluster );
+                       }
+               }
+               apiError.setCode(200);
+               return cluster;
+       }
+               
+       public MR_Cluster removeMr_Cluster( String key, ApiError apiError ) {
+               MR_Cluster mrc = mr_clusters.get( key );
+               if ( mrc == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "dcaeLocationName");
+                       apiError.setMessage( "Cluster with dcaeLocationName " + key + " not found");
+                       return null;
+               }
+               apiError.setCode(200);
+               return mr_clusters.remove(key);
+       }       
+       
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/MirrorMakerService.java b/src/main/java/org/onap/dmaap/dbcapi/service/MirrorMakerService.java
new file mode 100644 (file)
index 0000000..6701328
--- /dev/null
@@ -0,0 +1,141 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+
+
+
+
+
+
+
+//import org.openecomp.dmaapbc.aaf.AndrewDecryptor;
+import org.onap.dmaap.dbcapi.aaf.AafDecrypt;
+import org.onap.dmaap.dbcapi.aaf.client.MrTopicConnection;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.MirrorMaker;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.RandomInteger;
+
+public class MirrorMakerService extends BaseLoggingClass {
+       
+       private Map<String, MirrorMaker> mirrors = DatabaseClass.getMirrorMakers();
+       private static MrTopicConnection prov;
+       private static AafDecrypt decryptor;
+       
+       public MirrorMakerService() {
+               super();
+               
+               decryptor = new AafDecrypt();
+       }
+
+       // will create a MM on MMagent if needed
+       // will update the MMagent whitelist with all topics for this MM
+       public MirrorMaker updateMirrorMaker( MirrorMaker mm ) {
+               logger.info( "updateMirrorMaker");
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               String provUser = p.getProperty("MM.ProvUserMechId");
+               String provUserPwd = decryptor.decrypt(p.getProperty( "MM.ProvUserPwd", "notSet" ));
+               prov = new MrTopicConnection( provUser, provUserPwd );
+
+               String centralFqdn = p.getProperty("MR.CentralCname", "notSet");
+               
+               DmaapService dmaap = new DmaapService();
+               MR_ClusterService clusters = new MR_ClusterService();
+       
+               // in 1610, MM should only exist for edge-to-central
+               //  we use a cname for the central MR cluster that is active, and provision on agent topic on that target
+               // but only send 1 message so MM Agents can read it relying on kafka delivery
+               for( MR_Cluster central: clusters.getCentralClusters() ) {
+                       prov.makeTopicConnection(central, dmaap.getBridgeAdminFqtn(), centralFqdn  );
+                       ApiError resp = prov.doPostMessage(mm.createMirrorMaker());
+                       if ( ! resp.is2xx() ) {
+       
+                               errorLogger.error( DmaapbcLogMessageEnum.MM_PUBLISH_ERROR, "create MM", Integer.toString(resp.getCode()), resp.getMessage());
+                               mm.setStatus(DmaapObject_Status.INVALID);
+                       } else {
+                               prov.makeTopicConnection(central, dmaap.getBridgeAdminFqtn(), centralFqdn );
+                               resp = prov.doPostMessage(mm.updateWhiteList());
+                               if ( ! resp.is2xx()) {
+                                       errorLogger.error( DmaapbcLogMessageEnum.MM_PUBLISH_ERROR,"MR Bridge", Integer.toString(resp.getCode()), resp.getMessage());
+                                       mm.setStatus(DmaapObject_Status.INVALID);
+                               } else {
+                                       mm.setStatus(DmaapObject_Status.VALID);
+                               }
+                       }
+                       
+                       // we only want to send one message even if there are multiple central clusters
+                       break;
+               
+               } 
+               
+
+
+               mm.setLastMod();
+               return mirrors.put( mm.getMmName(), mm);
+       }
+       public MirrorMaker getMirrorMaker( String part1, String part2 ) {
+               logger.info( "getMirrorMaker using " + part1 + " and " + part2 );
+               return mirrors.get(MirrorMaker.genKey(part1, part2));
+       }       
+       public MirrorMaker getMirrorMaker( String key ) {
+               logger.info( "getMirrorMaker using " + key);
+               return mirrors.get(key);
+       }
+       
+       /*public MirrorMaker updateMirrorMaker( MirrorMaker mm ) {
+               logger.info( "updateMirrorMaker");
+               return mirrors.put( mm.getMmName(), mm);
+       }
+       */
+       
+       public void delMirrorMaker( MirrorMaker mm ) {
+               logger.info( "delMirrorMaker");
+               mirrors.remove(mm.getMmName());
+       }
+       
+       // TODO: this should probably return sequential values or get replaced by the MM client API
+       // but it should be sufficient for initial 1610 development
+       public static String genTransactionId() {
+               RandomInteger ri = new RandomInteger(100000);
+           int randomInt = ri.next();
+           return Integer.toString(randomInt);
+       }
+       public List<String> getAllMirrorMakers() {
+               List<String> ret = new ArrayList<String>();
+               for( String key: mirrors.keySet()) {
+                       ret.add( key );
+               }
+               
+               return ret;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java b/src/main/java/org/onap/dmaap/dbcapi/service/TopicService.java
new file mode 100644 (file)
index 0000000..244fe37
--- /dev/null
@@ -0,0 +1,417 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.onap.dmaap.dbcapi.aaf.AafService;
+import org.onap.dmaap.dbcapi.aaf.DmaapPerm;
+import org.onap.dmaap.dbcapi.aaf.AafService.ServiceType;
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.logging.BaseLoggingClass;
+import org.onap.dmaap.dbcapi.logging.DmaapbcLogMessageEnum;
+import org.onap.dmaap.dbcapi.model.ApiError;
+import org.onap.dmaap.dbcapi.model.Dmaap;
+import org.onap.dmaap.dbcapi.model.MR_Client;
+import org.onap.dmaap.dbcapi.model.MR_Cluster;
+import org.onap.dmaap.dbcapi.model.MirrorMaker;
+import org.onap.dmaap.dbcapi.model.ReplicationType;
+import org.onap.dmaap.dbcapi.model.Topic;
+import org.onap.dmaap.dbcapi.model.DmaapObject.DmaapObject_Status;
+import org.onap.dmaap.dbcapi.util.DmaapConfig;
+import org.onap.dmaap.dbcapi.util.Graph;
+
+public class TopicService extends BaseLoggingClass {
+
+       
+
+       // REF: https://wiki.web.att.com/pages/viewpage.action?pageId=519703122
+       private static String defaultGlobalMrHost;
+       
+       private Map<String, Topic> mr_topics = DatabaseClass.getTopics();
+       private Map<String, MR_Cluster> clusters = DatabaseClass.getMr_clusters();
+       
+       private static DmaapService dmaapSvc = new DmaapService();
+       private static Dmaap dmaap = new DmaapService().getDmaap();
+       private MR_ClientService clientService = new MR_ClientService();
+       private MirrorMakerService      bridge = new MirrorMakerService();
+
+       public TopicService(){
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               defaultGlobalMrHost = p.getProperty("MR.globalHost", "global.host.not.set");
+       }
+       
+       public Map<String, Topic> getTopics() {                 
+               return mr_topics;
+       }
+               
+       public List<Topic> getAllTopics() {
+               ArrayList<Topic> topics = new ArrayList<Topic>(mr_topics.values());
+               for( Topic topic: topics ) {
+                       topic.setClients( clientService.getAllMrClients(topic.getFqtn()));
+               }
+               return topics;
+       }
+       
+               
+       public Topic getTopic( String key, ApiError apiError ) {        
+               logger.info( "getTopic: key=" + key);
+               Topic t = mr_topics.get( key );
+               if ( t == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setFields( "fqtn");
+                       apiError.setMessage("topic with fqtn " + key + " not found");
+                       return null;
+               }
+               t.setClients( clientService.getAllMrClients( key ));
+               apiError.setCode(Status.OK.getStatusCode());
+               return t;
+       }
+
+       public Topic addTopic( Topic topic, ApiError err ) {
+               logger.info( "Entry: addTopic");
+               String nFqtn =  Topic.genFqtn( topic.getTopicName() );
+               if ( getTopic( nFqtn, err ) != null ) {
+                       String t = "topic already exists: " + nFqtn;
+                       logger.info( t );
+                       err.setMessage( t );
+                       err.setFields( "fqtn");
+                       err.setCode(Status.CONFLICT.getStatusCode());
+                       return null;
+               }
+               err.reset();  // err filled with NOT_FOUND is expected case, but don't want to litter...
+               logger.info( "fqtn: " + nFqtn );
+               topic.setFqtn( nFqtn );
+
+               AafService aaf = new AafService(ServiceType.AAF_TopicMgr);
+               String t = dmaap.getTopicNsRoot() + "." + dmaap.getDmaapName() + ".mr.topic";
+               String instance = ":topic." + topic.getFqtn();
+
+               String[] actions = { "pub", "sub", "view" };
+               for ( String action : actions ){
+                       DmaapPerm perm = new DmaapPerm( t, instance, action );
+                       int rc = aaf.addPerm( perm );
+                       if ( rc != 201 && rc != 409 ) {
+                               err.setCode(500);
+                               err.setMessage("Unexpected response from AAF:" + rc );
+                               err.setFields("t="+t + " instance="+ instance + " action="+ action);
+                               return null;
+                       }
+               }
+
+
+               if ( topic.getNumClients() > 0 ) {
+                       ArrayList<MR_Client> clients = new ArrayList<MR_Client>(topic.getClients());
+               
+       
+                       ArrayList<MR_Client> clients2 = new ArrayList<MR_Client>();
+                       for ( Iterator<MR_Client> it = clients.iterator(); it.hasNext(); ) {
+                               MR_Client c = it.next();
+
+                               logger.info( "c fqtn=" + c.getFqtn() + " ID=" + c.getMrClientId() + " url=" + c.getTopicURL());
+                               MR_Client nc = new MR_Client( c.getDcaeLocationName(), topic.getFqtn(), c.getClientRole(), c.getAction());
+                               nc.setFqtn(topic.getFqtn());
+                               logger.info( "nc fqtn=" + nc.getFqtn() + " ID=" + nc.getMrClientId() + " url=" + nc.getTopicURL());
+                               clients2.add( clientService.addMr_Client(nc, topic, err));
+                               if ( ! err.is2xx()) {
+                                       return null;
+                               }
+                       }
+
+                       topic.setClients(clients2);
+               }
+               if ( topic.getReplicationCase().involvesGlobal() ) {
+                       if ( topic.getGlobalMrURL() == null ) {
+                               topic.setGlobalMrURL(defaultGlobalMrHost);
+                       }
+               }
+               Topic ntopic = checkForBridge( topic, err );
+               if ( ntopic == null ) {
+                       topic.setStatus( DmaapObject_Status.INVALID);
+                       return null;
+               }
+
+               mr_topics.put( nFqtn, ntopic );
+
+               err.setCode(Status.OK.getStatusCode());
+               return ntopic;
+       }
+       
+               
+       public Topic updateTopic( Topic topic, ApiError err ) {
+               logger.info( "Entry: updateTopic");
+               if ( topic.getFqtn().isEmpty()) {
+                       return null;
+               }
+               Topic ntopic = checkForBridge( topic, err );
+               if ( ntopic == null ) {
+                       topic.setStatus( DmaapObject_Status.INVALID);
+                       return null;
+               }
+               mr_topics.put( ntopic.getFqtn(), ntopic );
+               err.setCode(Status.OK.getStatusCode());
+               return ntopic;
+       }
+               
+       public Topic removeTopic( String pubId, ApiError apiError ) {
+               Topic topic = mr_topics.get(pubId);
+               if ( topic == null ) {
+                       apiError.setCode(Status.NOT_FOUND.getStatusCode());
+                       apiError.setMessage("Topic " + pubId + " does not exist");
+                       apiError.setFields("fqtn");
+                       return null;
+               }
+               ArrayList<MR_Client> clients = new ArrayList<MR_Client>(clientService.getAllMrClients( pubId ));
+               for ( Iterator<MR_Client> it = clients.iterator(); it.hasNext(); ) {
+                       MR_Client c = it.next();
+                       
+       
+                       clientService.removeMr_Client(c.getMrClientId(), false, apiError);
+                       if ( ! apiError.is2xx()) {
+                               return null;
+                       }
+               }
+               apiError.setCode(Status.OK.getStatusCode());
+               return mr_topics.remove(pubId);
+       }       
+       public static ApiError setBridgeClientPerms( MR_Cluster node ) {
+               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+               String mmProvRole = p.getProperty("MM.ProvRole");
+               String mmAgentRole = p.getProperty("MM.AgentRole");
+               String[] Roles = { mmProvRole, mmAgentRole };
+               String[] actions = { "view", "pub", "sub" };
+               Topic bridgeAdminTopic = new Topic();
+               bridgeAdminTopic.setTopicName( dmaapSvc.getBridgeAdminFqtn() );
+               bridgeAdminTopic.setTopicDescription( "RESERVED topic for MirroMaker Provisioning");
+               bridgeAdminTopic.setOwner( "DBC" );
+               ArrayList<MR_Client> clients = new ArrayList<MR_Client>();
+               for( String role: Roles ) {
+                       MR_Client client = new MR_Client();
+                       client.setAction(actions);
+                       client.setClientRole(role);
+                       client.setDcaeLocationName( node.getDcaeLocationName());
+                       clients.add( client );
+               }
+               bridgeAdminTopic.setClients(clients);
+               
+               TopicService ts = new TopicService();
+               ApiError err = new ApiError();
+               ts.addTopic(bridgeAdminTopic, err);
+               
+               if ( err.is2xx() || err.getCode() == 409 ){
+                       err.setCode(200);
+                       return err;
+               }
+               
+               errorLogger.error( DmaapbcLogMessageEnum.TOPIC_CREATE_ERROR,  bridgeAdminTopic.getFqtn(), Integer.toString(err.getCode()), err.getFields(), err.getMessage());
+               return err;
+       }       
+       
+       
+       public Topic checkForBridge( Topic topic, ApiError err ) {
+               
+               if ( topic.getReplicationCase() == ReplicationType.REPLICATION_NONE ) {
+                       topic.setStatus( DmaapObject_Status.VALID);
+                       return topic;   
+               }
+               
+               boolean anythingWrong = false;                          
+               String centralFqdn = new String();
+               Graph graph = new Graph( topic.getClients(), true );
+               
+               if ( graph.isHasCentral() ) {
+                       DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+                       centralFqdn = p.getProperty("MR.CentralCname");
+                       logger.info( "CentralCname=" + centralFqdn );
+               } else {
+                       logger.warn( "Topic " + topic.getFqtn() + " wants to be " + topic.getReplicationCase() + " but has no cental clients");
+               }
+               Collection<String> locations = graph.getKeys();
+               for( String loc : locations ) {
+                       logger.info( "loc=" + loc );
+                       MR_Cluster cluster = clusters.get(loc);
+                       logger.info( "cluster=" + cluster );
+
+                       
+                               
+                       String source = null;
+                       String target = null;
+                       /*
+                        * all replication rules have 1 bridge...
+                        */
+                       switch( topic.getReplicationCase() ) {
+                       case REPLICATION_EDGE_TO_CENTRAL:
+                       case REPLICATION_EDGE_TO_CENTRAL_TO_GLOBAL:  // NOTE: this is for E2C portion only
+                               if ( graph.isHasCentral() &&  graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       break;
+                               }
+                               source = cluster.getFqdn();
+                               target = centralFqdn;
+                               break;
+                       case REPLICATION_CENTRAL_TO_EDGE:
+                               if ( graph.isHasCentral() &&  graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       continue;
+                               }
+                               source = centralFqdn;
+                               target = cluster.getFqdn();
+                               break;
+                       case REPLICATION_CENTRAL_TO_GLOBAL:
+                               if ( graph.isHasCentral() &&  ! graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       continue;
+                               }
+                               source = centralFqdn;
+                               target = topic.getGlobalMrURL();
+                               break;
+                       case REPLICATION_GLOBAL_TO_CENTRAL:
+                       case REPLICATION_GLOBAL_TO_CENTRAL_TO_EDGE:  // NOTE: this is for G2C portion only
+                               if ( graph.isHasCentral() &&  ! graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       continue;
+                               }
+                               source = topic.getGlobalMrURL();
+                               target = centralFqdn;
+                               break;
+                       default:
+                               logger.error( "Unexpected value for ReplicationType ("+ topic.getReplicationCase() + ") for topic " + topic.getFqtn() );
+                               anythingWrong = true;
+                               continue;
+                       }
+                       if ( source != null && target != null ) {
+                               try { 
+                                       logger.info( "Create a MM from " + source + " to " + target );
+                                       MirrorMaker mm = bridge.getMirrorMaker( source, target);
+                                       if ( mm == null ) {
+                                               mm = new MirrorMaker(source, target);
+                                       }
+                                       mm.addTopic(topic.getFqtn());
+                                       bridge.updateMirrorMaker(mm);
+                               } catch ( Exception ex ) {
+                                       err.setCode(500);
+                                       err.setFields( "mirror_maker.topic");
+                                       err.setMessage("Unexpected condition: " + ex );
+                                       anythingWrong = true;
+                                       break;
+                               }
+                       }
+                       
+                       
+                       /*
+                        * some replication rules have a 2nd bridge!
+                        */
+                       source = target = null;
+                       switch( topic.getReplicationCase() ) {
+                       case REPLICATION_EDGE_TO_CENTRAL:
+                       case REPLICATION_CENTRAL_TO_EDGE:
+                       case REPLICATION_CENTRAL_TO_GLOBAL:
+                       case REPLICATION_GLOBAL_TO_CENTRAL:
+                               continue;
+                       case REPLICATION_EDGE_TO_CENTRAL_TO_GLOBAL:  // NOTE: this is for C2G portion only
+                               if ( graph.isHasCentral() && ! graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       continue;
+                               }
+                               source = centralFqdn;
+                               target = topic.getGlobalMrURL();
+                               break;
+       
+                       case REPLICATION_GLOBAL_TO_CENTRAL_TO_EDGE:  // NOTE: this is for C2E portion only
+                               if ( graph.isHasCentral() &&  graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       continue;
+                               }
+                               source = centralFqdn;
+                               target = cluster.getFqdn();
+                               break;
+                       default:
+                               logger.error( "Unexpected value for ReplicationType ("+ topic.getReplicationCase() + ") for topic " + topic.getFqtn() );
+                               anythingWrong = true;
+                               break;
+                       }
+                       if ( source != null && target != null ) {
+                               try { 
+                                       logger.info( "Create a MM from " + source + " to " + target );
+                                       MirrorMaker mm = bridge.getMirrorMaker( source, target);
+                                       if ( mm == null ) {
+                                               mm = new MirrorMaker(source, target);
+                                       }
+                                       mm.addTopic(topic.getFqtn());
+                                       bridge.updateMirrorMaker(mm);
+                               } catch ( Exception ex ) {
+                                       err.setCode(500);
+                                       err.setFields( "mirror_maker.topic");
+                                       err.setMessage("Unexpected condition: " + ex );
+                                       anythingWrong = true;
+                                       break;
+                               }       
+                       }
+                       
+               }
+               if ( anythingWrong ) {
+                       topic.setStatus( DmaapObject_Status.INVALID);
+                       return null;
+               }
+       
+               topic.setStatus( DmaapObject_Status.VALID);
+               return topic;
+       }
+       
+       /*
+        * Prior to 1707, we only supported EDGE_TO_CENTRAL replication.
+        * This was determined automatically based on presence of edge publishers and central subscribers.
+        * The following method is a modification of that original logic, to preserve some backwards compatibility, 
+        * i.e. to be used when no ReplicationType is specified.
+        */
+       public ReplicationType reviewTopic( Topic topic ) {
+       
+               
+               if ( topic.getNumClients() > 1 ) {
+                       Graph graph = new Graph( topic.getClients(), false );
+                       
+                       String centralFqdn = new String();
+                       if ( graph.isHasCentral() ) {
+                               DmaapConfig p = (DmaapConfig)DmaapConfig.getConfig();
+                               centralFqdn = p.getProperty("MR.CentralCname");
+                       }
+
+                       Collection<String> locations = graph.getKeys();
+                       for( String loc : locations ) {
+                               logger.info( "loc=" + loc );
+                               MR_Cluster cluster = clusters.get(loc);
+                               if ( cluster == null ) {
+                                       logger.info( "No MR cluster for location " + loc );
+                                       continue;
+                               }
+                               if ( graph.isHasCentral() &&  ! graph.getCentralLoc().equals(cluster.getDcaeLocationName())) {
+                                       logger.info( "Detected case for EDGE_TO_CENTRAL from " + cluster.getFqdn() + " to " + centralFqdn );
+                                       return ReplicationType.REPLICATION_EDGE_TO_CENTRAL;
+                                       
+                               }
+                               
+                       }
+               }
+       
+               return ReplicationType.REPLICATION_NONE;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/DmaapConfig.java b/src/main/java/org/onap/dmaap/dbcapi/util/DmaapConfig.java
new file mode 100644 (file)
index 0000000..eaa6672
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+import java.io.*;
+import java.util.*;
+
+public class DmaapConfig extends Properties    {
+       /**
+        * 
+        */
+       private static final long serialVersionUID = 1L;
+       private static String configfname = System.getProperty("ConfigFile", "etc/dmaapbc.properties");
+       private static Properties config = new DmaapConfig();
+       public static Properties getConfig() {
+               return(config);
+       }
+       public static String getConfigFileName() {
+               return(configfname);
+       }
+       private DmaapConfig() {
+               try {
+                       InputStream is = new FileInputStream(configfname);
+                       load(is);
+                       is.close();
+               } catch (Exception e) {
+                       System.err.println("Unable to load configuration file " + configfname);
+                       org.apache.log4j.Logger.getLogger(getClass()).fatal("Unable to load configuration file " + configfname, e);
+                       System.exit(1);
+               }
+       }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/DmaapTimestamp.java b/src/main/java/org/onap/dmaap/dbcapi/util/DmaapTimestamp.java
new file mode 100644 (file)
index 0000000..f494bed
--- /dev/null
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.log4j.Logger;
+
+@XmlRootElement
+public class DmaapTimestamp {
+       static final Logger logger = Logger.getLogger(DmaapTimestamp.class);
+       private static Calendar cal = Calendar.getInstance();
+       private Date stamp;
+       
+       public DmaapTimestamp() {
+
+               stamp = cal.getTime();
+               logger.info("constructor: set val to " + stamp);
+       }
+       
+       public void mark() {
+               stamp =  cal.getTime();
+               logger.info("mark: set val to " + stamp);
+       }
+       
+       public Date getVal() {
+               return stamp;
+       }
+
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/Graph.java b/src/main/java/org/onap/dmaap/dbcapi/util/Graph.java
new file mode 100644 (file)
index 0000000..5c57ebc
--- /dev/null
@@ -0,0 +1,111 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.dmaap.dbcapi.aaf.database.DatabaseClass;
+import org.onap.dmaap.dbcapi.model.DcaeLocation;
+import org.onap.dmaap.dbcapi.model.MR_Client;
+
+
+public class Graph {
+       private HashMap<String, String> graph;
+       private boolean hasCentral;
+       
+       private Map<String, DcaeLocation> locations = DatabaseClass.getDcaeLocations();
+       
+       //TODO add to properties file
+       private static String centralDcaeLayerName = "central";
+
+       
+       public Graph(HashMap<String, String> graph) {
+               super();
+               this.graph = graph;
+       }
+
+       public Graph( List<MR_Client> clients, boolean strict ) {
+               if ( clients == null )
+                       return;
+               this.graph = new HashMap<String, String>();
+               this.hasCentral = false;
+               for( MR_Client client: clients ) {
+                       if ( ! strict || client.isStatusValid()) {
+                               String loc = client.getDcaeLocationName();
+                               for( String action : client.getAction() ){
+                                       DcaeLocation dcaeLoc = locations.get(loc);
+                                       if ( ! action.equals("view") && dcaeLoc != null ) {
+                                               graph.put(loc, dcaeLoc.getDcaeLayer());
+                                       }
+                               }
+                               String layer = graph.get(loc);
+                               if ( layer != null && layer.contains(centralDcaeLayerName) ) {
+                                       this.hasCentral = true;
+                               }
+       
+                       }               
+               }               
+       }
+       
+       public HashMap<String, String> getGraph() {
+               return graph;
+       }
+
+       public void setGraph(HashMap<String, String> graph) {
+               this.graph = graph;
+       }
+       
+       public String put( String key, String val ) {
+               return graph.put(key, val);
+       }
+       
+       public String get( String key ) {
+               return graph.get(key);
+       }
+       
+       public Collection<String> getKeys() {
+               return graph.keySet();
+       }
+       public boolean isHasCentral() {
+               return hasCentral;
+       }
+       public void setHasCentral(boolean hasCentral) {
+               this.hasCentral = hasCentral;
+       }
+       
+       public String getCentralLoc() {
+               if ( ! hasCentral ) {
+                       return null;
+               }
+               for( String loc : graph.keySet()) {
+                       if ( graph.get(loc).contains(centralDcaeLayerName)) {
+                               return loc;
+                       }
+               }
+               return null;
+       }
+       
+       
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/RandomInteger.java b/src/main/java/org/onap/dmaap/dbcapi/util/RandomInteger.java
new file mode 100644 (file)
index 0000000..2909419
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+import java.util.Date;
+// source: http://www.javapractices.com/topic/TopicAction.do?Id=62
+// with some modifications
+import java.util.Random;
+
+
+public final class RandomInteger {
+       private static Random randomGenerator;
+       private int range;
+       
+       public RandomInteger( int r ) {
+               randomGenerator = new Random();
+               randomGenerator.setSeed((new Date()).getTime());
+               range = r;
+       }
+       
+       public int next(){
+               return randomGenerator.nextInt(range);
+       }
+  
+  /** Generate 10 random integers in the range 0..99. */
+  public static final void main(String... aArgs){
+    log("Generating 10 random integers in range 0..99.");
+    RandomInteger ri = new RandomInteger(100);
+    //note a single Random object is reused here
+    
+    for (int idx = 1; idx <= 10; ++idx){
+      int randomInt = ri.next();
+      log("Generated : " + randomInt);
+    }
+    
+    log("Done.");
+  }
+  
+  private static void log(String aMessage){
+    System.out.println(aMessage);
+  }
+}
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/RandomString.java b/src/main/java/org/onap/dmaap/dbcapi/util/RandomString.java
new file mode 100644 (file)
index 0000000..b889c1c
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+import java.util.Random;
+
+// source: http://stackoverflow.com/questions/41107/how-to-generate-a-random-alpha-numeric-string
+
+public class RandomString {
+
+         private static final char[] symbols;
+
+         static {
+           StringBuilder tmp = new StringBuilder();
+           for (char ch = '0'; ch <= '9'; ++ch)
+             tmp.append(ch);
+           for (char ch = 'a'; ch <= 'z'; ++ch)
+             tmp.append(ch);
+           symbols = tmp.toString().toCharArray();
+         }   
+
+         private final Random random = new Random();
+
+         private final char[] buf;
+
+         public RandomString(int length) {
+           if (length < 1)
+             throw new IllegalArgumentException("length < 1: " + length);
+           buf = new char[length];
+         }
+
+         public String nextString() {
+           for (int idx = 0; idx < buf.length; ++idx) 
+             buf[idx] = symbols[random.nextInt(symbols.length)];
+           return new String(buf);
+         }
+       }
diff --git a/src/main/java/org/onap/dmaap/dbcapi/util/Singleton.java b/src/main/java/org/onap/dmaap/dbcapi/util/Singleton.java
new file mode 100644 (file)
index 0000000..3ef6a3d
--- /dev/null
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.dmaap
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.dmaap.dbcapi.util;
+
+public interface Singleton<T>  {
+       public T get();
+       public void init(T val);
+       public void update(T val);
+       public void remove();
+}
diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties
new file mode 100644 (file)
index 0000000..bfaeaf2
--- /dev/null
@@ -0,0 +1,29 @@
+###
+# ============LICENSE_START=======================================================
+# OpenECOMP - org.openecomp.dmaapbc
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# 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.
+# ============LICENSE_END=========================================================
+###
+
+log4j.debug=FALSE
+log4j.rootLogger=INFO,Root
+
+log4j.appender.Root=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.Root.file=logs/dmaapBC-api.log
+log4j.appender.Root.datePattern='.'yyyyMMdd
+log4j.appender.Root.append=true
+log4j.appender.Root.layout=org.apache.log4j.PatternLayout
+log4j.appender.Root.layout.ConversionPattern=%d %p %F %L %t %m%n
diff --git a/src/main/resources/schema_0.sql b/src/main/resources/schema_0.sql
new file mode 100644 (file)
index 0000000..3b59800
--- /dev/null
@@ -0,0 +1,35 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+@drop table dcae_location;
+@drop table dmaap;
+@drop table dr_node;
+@drop table dr_pub;
+@drop table dr_sub;
+@drop table mr_client;
+@drop table mr_cluster;
+@drop table feed;
+@drop table topic;
+@drop table mirror_maker;
+@drop table dmaapbc_sch_ver;
+CREATE TABLE dmaapbc_sch_ver   (
+       version INTEGER
+);
+INSERT INTO dmaapbc_sch_ver (version) VALUES (0);
diff --git a/src/main/resources/schema_1.sql b/src/main/resources/schema_1.sql
new file mode 100644 (file)
index 0000000..27ae13f
--- /dev/null
@@ -0,0 +1,136 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+@drop table dcae_location;
+create table dcae_location     (
+       dcae_location_name      VARCHAR(100),
+       clli    VARCHAR(100),
+       dcae_layer      VARCHAR(100),
+       open_stack_availability_zone    VARCHAR(100),
+       last_mod        TIMESTAMP,
+       PRIMARY KEY(dcae_location_name)
+);
+@drop table dmaap;
+create table dmaap     (
+       version VARCHAR(100),
+       topic_ns_root   VARCHAR(100),
+       dmaap_name      VARCHAR(100),
+       dr_prov_url     VARCHAR(200),
+       node_key        VARCHAR(100),
+       access_key_owner        VARCHAR(100),
+       last_mod        TIMESTAMP,
+       status          VARCHAR(100),
+       bridge_admin_topic      VARCHAR(100),
+       logging_url     VARCHAR(200)
+);
+@drop table dr_node;
+create table dr_node   (
+       fqdn    VARCHAR(100),
+       dcae_location_name      VARCHAR(100),
+       host_name       VARCHAR(100),
+       version VARCHAR(100),
+       PRIMARY KEY(fqdn)
+);
+@drop table dr_pub;
+create table dr_pub    (
+       dcae_location_name      VARCHAR(100),
+       username        VARCHAR(100),
+       userpwd VARCHAR(100),
+       feed_id VARCHAR(100),
+       pub_id  VARCHAR(100),
+       status  VARCHAR(100),
+       PRIMARY KEY(pub_id)
+);
+@drop table dr_sub;
+create table dr_sub    (
+       owner   VARCHAR(100),
+       suspended       BOOLEAN,
+       status  VARCHAR(100),
+       use100  BOOLEAN,
+       dcae_location_name      VARCHAR(100),
+       username        VARCHAR(100),
+       userpwd VARCHAR(100),
+       feed_id VARCHAR(100),
+       delivery_u_r_l  VARCHAR(200),
+       log_u_r_l       VARCHAR(200),
+       sub_id  VARCHAR(100),
+       PRIMARY KEY(sub_id)
+);
+@drop table mr_client;
+create table mr_client (
+       dcae_location_name      VARCHAR(100),
+       fqtn    VARCHAR(100),
+       client_role     VARCHAR(100),
+       action  VARCHAR(300),
+       mr_client_id    VARCHAR(100),
+       status  VARCHAR(100),
+       topic_u_r_l     VARCHAR(200),
+       last_mod        TIMESTAMP,
+       PRIMARY KEY(mr_client_id)
+);
+@drop table mr_cluster;
+create table mr_cluster        (
+       last_mod        TIMESTAMP,
+       dcae_location_name      VARCHAR(100),
+       fqdn    VARCHAR(100),
+       hosts   VARCHAR(300),
+       topic_protocol  VARCHAR(100),
+       topic_port      VARCHAR(100),
+       PRIMARY KEY(dcae_location_name)
+);
+@drop table feed;
+create table feed      (
+       suspended       BOOLEAN,
+       subscribe_u_r_l VARCHAR(200),
+       feed_id VARCHAR(100),
+       feed_name       VARCHAR(100),
+       feed_version    VARCHAR(100),
+       feed_description        VARCHAR(1000),
+       owner   VARCHAR(100),
+       aspr_classification     VARCHAR(100),
+       publish_u_r_l   VARCHAR(200),
+       log_u_r_l       VARCHAR(200),
+       status  VARCHAR(100),
+       -- pubs not stored here
+       -- subs not stored here
+       PRIMARY KEY(feed_id)
+);
+@drop table topic;
+create table topic     (
+       last_mod        TIMESTAMP,
+       fqtn    VARCHAR(100),
+       topic_name      VARCHAR(100),
+       topic_description       VARCHAR(1000),
+       tnx_enabled     VARCHAR(100),
+       owner   VARCHAR(100),
+       status  VARCHAR(100),
+       -- clients not stored here
+       PRIMARY KEY(fqtn)
+);
+@drop table mirror_maker;
+create table mirror_maker      (
+       mm_name VARCHAR(100),
+       source_cluster  VARCHAR(100),
+       target_cluster  VARCHAR(100),
+       last_mod        TIMESTAMP,
+       vectors         TEXT,
+       PRIMARY KEY(source_cluster)
+);
+update dmaapbc_sch_ver set version = 1 where version = 0;
diff --git a/src/main/resources/schema_2.sql b/src/main/resources/schema_2.sql
new file mode 100644 (file)
index 0000000..c9e5c02
--- /dev/null
@@ -0,0 +1,51 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+@alter table dcae_location     
+       add column      subnet          VARCHAR(100),
+       add column      status          VARCHAR(100)
+;
+
+@alter table dr_node
+       add column      last_mod        TIMESTAMP,
+       add column      status          VARCHAR(100)
+;
+@alter table   dr_pub
+       add column      last_mod        TIMESTAMP
+;
+@alter table dr_sub
+       add column      last_mod        TIMESTAMP
+;
+
+@alter table mr_cluster
+       add column      status          VARCHAR(100)
+;
+@alter table feed
+       add column      last_mod        TIMESTAMP,
+       add column      format_uuid     VARCHAR(100)
+;
+@alter table   topic
+       add column      format_uuid     VARCHAR(100)
+;
+
+@alter table mirror_maker
+       add column      status          VARCHAR(100)
+;
+update dmaapbc_sch_ver set version = 2 where version = 1;
diff --git a/src/main/resources/schema_3.sql b/src/main/resources/schema_3.sql
new file mode 100644 (file)
index 0000000..0f28988
--- /dev/null
@@ -0,0 +1,29 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+
+@alter table mirror_maker
+       add column      topics          TEXT
+;
+@alter table mirror_maker
+       drop column     vectors         
+;
+@delete from mirror_maker;
+update dmaapbc_sch_ver set version = 3 where version = 2;
diff --git a/src/main/resources/schema_4.sql b/src/main/resources/schema_4.sql
new file mode 100644 (file)
index 0000000..727c4bd
--- /dev/null
@@ -0,0 +1,33 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+
+@drop table mirror_maker;
+create table mirror_maker      (
+       mm_name VARCHAR(512),
+       source_cluster  VARCHAR(256),
+       target_cluster  VARCHAR(256),
+       last_mod        TIMESTAMP,
+       topics          TEXT,
+       PRIMARY KEY(source_cluster)
+);
+
+
+update dmaapbc_sch_ver set version = 4 where version = 3;
diff --git a/src/main/resources/schema_5.sql b/src/main/resources/schema_5.sql
new file mode 100644 (file)
index 0000000..cd7130b
--- /dev/null
@@ -0,0 +1,25 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+
+@delete from mirror_maker;
+
+
+update dmaapbc_sch_ver set version = 5 where version = 4;
diff --git a/src/main/resources/schema_6.sql b/src/main/resources/schema_6.sql
new file mode 100644 (file)
index 0000000..7c2bbd7
--- /dev/null
@@ -0,0 +1,33 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+
+@drop table mirror_maker;
+create table mirror_maker      (
+       mm_name VARCHAR(512),
+       source_cluster  VARCHAR(256),
+       target_cluster  VARCHAR(256),
+       last_mod        TIMESTAMP,
+       topics          TEXT,
+       PRIMARY KEY(mm_name)
+);
+
+
+update dmaapbc_sch_ver set version = 6 where version = 5;
diff --git a/src/main/resources/schema_7.sql b/src/main/resources/schema_7.sql
new file mode 100644 (file)
index 0000000..2fd1993
--- /dev/null
@@ -0,0 +1,28 @@
+---
+-- ============LICENSE_START=======================================================
+-- OpenECOMP - org.openecomp.dmaapbc
+-- ================================================================================
+-- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+-- ================================================================================
+-- 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.
+-- ============LICENSE_END=========================================================
+---
+
+
+@alter table   topic
+       add column      replication_case int,
+       add column  global_mr_u_r_l      VARCHAR(200)
+;
+
+
+update dmaapbc_sch_ver set version = 7 where version = 6;
diff --git a/src/main/webapp/HelloJetty.html b/src/main/webapp/HelloJetty.html
new file mode 100644 (file)
index 0000000..4d61636
--- /dev/null
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<!--
+  ============LICENSE_START=======================================================
+  OpenECOMP - org.openecomp.dmaapbc
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  -->
+
+<html>
+<head>
+<meta charset="ISO-8859-1">
+<title>Index</title>
+</head>
+<body>
+Hello Jetty!
+</body>
+</html>
diff --git a/src/main/webapp/WEB-INF/log4j.xml b/src/main/webapp/WEB-INF/log4j.xml
new file mode 100644 (file)
index 0000000..4e4d5e9
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  OpenECOMP - org.openecomp.dmaapbc
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  -->
+
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
+<log4j:configuration>
+        <appender name="dmaapBC" class="org.apache.log4j.RollingFileAppender">
+                <param name="File" value="dmaapBC.log"/>
+                <param name="MaxFileSize" value="1000KB"/>
+                <param name="MaxBackupIndex" value="3"/>
+                <layout class="org.apache.log4j.PatternLayout">
+                        <param name="ConversionPattern" value="[%d{HH:mm:ss:SSS}] - %-6p - %c.%M() - %m%n"/>
+                </layout>
+        </appender>
+          <appender name="media" class="org.apache.log4j.ConsoleAppender">
+             <param name="Threshold" value="FATAL"/>
+            <layout class="org.apache.log4j.PatternLayout">
+                  <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
+            </layout>
+          </appender>
+        <category name="org.openecomp.dcae.dmaapBC">
+                <appender-ref ref="dmaapBC"/>
+        </category>
+        <root>
+                <priority value="all"/>
+                <appender-ref ref="media"/>
+        </root>
+</log4j:configuration>
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..055fbf0
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  OpenECOMP - org.openecomp.dmaapbc
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  -->
+
+<!-- This web.xml file is not required when using Servlet 3.0 container,
+     see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
+  <servlet>
+    <servlet-name>Jersey Web Application</servlet-name>
+    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+    <init-param>
+      <param-name>jersey.config.server.provider.packages</param-name>
+      <param-value>org.openecomp.dmaapBC</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>Jersey Web Application</servlet-name>
+    <url-pattern>/webapi/*</url-pattern>
+  </servlet-mapping>
+</web-app>
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
new file mode 100644 (file)
index 0000000..45aa9e8
--- /dev/null
@@ -0,0 +1,28 @@
+<%--
+  ============LICENSE_START=======================================================
+  OpenECOMP - org.openecomp.dmaapbc
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  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.
+  ============LICENSE_END=========================================================
+  --%>
+
+<html>
+<body>
+    <h2>Jersey RESTful Web Application!</h2>
+    <p><a href="webapi/dmaap">Jersey resource</a>
+    <p>Visit <a href="http://jersey.java.net">Project Jersey website</a>
+    for more information on Jersey!
+</body>
+</html>