Update appc-common to Karaf 4 43/55543/7
authorRyan Young <ry303t@att.com>
Thu, 28 Jun 2018 21:22:47 +0000 (17:22 -0400)
committerTakamune Cho <tc012c@att.com>
Thu, 9 Aug 2018 21:10:37 +0000 (21:10 +0000)
update appc-common to karaf 4 feature

Change-Id: Ib0ce37032e63ffc61bef94345701f3ab58785153
Signed-off-by: Ryan Young <ry303t@att.com>
Issue-ID: APPC-1022

147 files changed:
appc-common/pom.xml
appc-core/appc-common-bundle/java/org/onap/appc/CmdLine.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/Constants.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategies.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategy.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/MetadataCache.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/LRUCache.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheFactory.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheImpl.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/concurrent/Signal.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/configuration/Configuration.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/configuration/ConfigurationFactory.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/configuration/DefaultConfiguration.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/configuration/package.html [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionTool.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/encryption/HexHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/exceptions/APPCException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidInputException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidStateException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/exceptions/UnknownProviderException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/i18n/Msg.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingConstants.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingUtils.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/metadata/MetadataService.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/Allocator.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/CacheManagement.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/CachedElement.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/Destructor.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/Pool.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolDrainedException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolExtensionException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolSpecificationException.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/rest/client/RestClientInvoker.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/JsonUtil.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/MessageFormatter.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/ObjectMapper.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/PathContext.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/StreamHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/StringHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/StructuredPropertyHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/Time.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/UnmodifiableProperties.java [new file with mode: 0644]
appc-core/appc-common-bundle/java/org/onap/appc/util/httpClient.java [new file with mode: 0644]
appc-core/appc-common-bundle/pom.xml [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/CmdLine.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/Constants.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategies.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategy.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/MetadataCache.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/LRUCache.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheFactory.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheImpl.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/concurrent/Signal.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/Configuration.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/ConfigurationFactory.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/DefaultConfiguration.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/package.html [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionTool.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/HexHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/APPCException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidInputException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidStateException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/UnknownProviderException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/i18n/Msg.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingConstants.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingUtils.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/MetadataService.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Allocator.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CacheManagement.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CachedElement.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Destructor.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Pool.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolDrainedException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolExtensionException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolSpecificationException.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/rest/client/RestClientInvoker.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/JsonUtil.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/MessageFormatter.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/ObjectMapper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/PathContext.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StreamHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StringHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StructuredPropertyHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/Time.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/UnmodifiableProperties.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/httpClient.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/MessageResources.properties [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/auth.properties [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/resources/org/onap/appc/org.ops4j.pax.logging.cfg [new file with mode: 0644]
appc-core/appc-common-bundle/src/main/resources/org/opendaylight/blueprint/blueprint.xml [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/CmdLineTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/ConstantsTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/CacheStrategiesTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/LRUCacheTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheFactoryTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheImplTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/concurrent/TestSignal.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/ConfigurationFactoryTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/DefaultConfigurationTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/EncryptionToolTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/HexHelperTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/APPCExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidInputExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidStateExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/UnknownProviderExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/i18n/MsgTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingConstantsTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingUtilsTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/impl/MetadataServiceImplTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/objects/DependencyModelIdentifierTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/CachedElementTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Element.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolDrainedExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExtensionExceptionTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Testable.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/JsonUtilTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/MessageFormatterTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/PathContextTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StreamHelperTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StringHelperTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TestStructuredPropertyHelper.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TimeTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/UnmodifiablePropertiesTest.java [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/resources/invalid.json [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestAdditionalResources.properties [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_de.properties [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_en_US.properties [new file with mode: 0644]
appc-core/appc-common-bundle/src/test/resources/valid.json [new file with mode: 0644]
appc-core/appc-core-features/onap-appc-common/pom.xml [new file with mode: 0644]
appc-core/appc-core-features/onap-appc-core/pom.xml [new file with mode: 0644]
appc-core/appc-core-features/pom.xml [new file with mode: 0644]
appc-core/appc-core-installer/pom.xml [new file with mode: 0644]
appc-core/appc-core-installer/src/assembly/assemble_installer_zip.xml [new file with mode: 0644]
appc-core/appc-core-installer/src/assembly/assemble_mvnrepo_zip.xml [new file with mode: 0644]
appc-core/appc-core-installer/src/main/resources/scripts/install-feature.sh [new file with mode: 0644]
appc-core/pom.xml [new file with mode: 0644]
pom.xml

index e20e624..830c2e7 100644 (file)
           <instructions>
             <Bundle-SymbolicName>appc-common</Bundle-SymbolicName>
             <Export-Package>
-              org.onap.appc.*, com.att.eelf.*, ch.qos.logback.*, org.jasypt.*
+              org.onap.appc.*, ch.qos.logback.*, org.jasypt.*
             </Export-Package>
             <Import-Package>*;resolution:=optional</Import-Package>
             <Embed-Dependency>eelf-core, logback-core, logback-classic, jasypt, dblib-provider</Embed-Dependency>
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/CmdLine.java b/appc-core/appc-common-bundle/java/org/onap/appc/CmdLine.java
new file mode 100644 (file)
index 0000000..383de89
--- /dev/null
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.
+ * 
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * ============LICENSE_END=========================================================
+ */
+
+    package org.onap.appc;
+
+import org.onap.appc.encryption.EncryptionTool;
+
+public class CmdLine {
+
+        public static void main(String[] args) {
+
+            if (args.length < 1) {
+                printUsage();
+                return;
+            }
+
+            String command = args[0];//first parameter
+
+            if (0 == command.compareTo("encrypt") && args.length == 2)//two parameters are required
+            {
+                String clearText = args[1];
+                String encrypted = EncryptionTool.getInstance().encrypt(clearText);
+                System.out.println(encrypted);
+                return;
+            } else {
+                printUsage();
+            }
+        }
+        
+        private static void printUsage(){
+            System.out.println("Usage: java -jar <this jar> ...");
+            System.out.println("\tencrypt <your text> \t\t(Encrypts your text)");
+        }
+}
\ No newline at end of file
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/Constants.java b/appc-core/appc-common-bundle/java/org/onap/appc/Constants.java
new file mode 100644 (file)
index 0000000..c1a306a
--- /dev/null
@@ -0,0 +1,209 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc;
+
+/**
+ * This class contains the definitions of all constant values used in the APPC provider, adapters, and other components.
+ * These constants define properties, settings, and context variables. The context variables can be referenced from
+ * within the directed graph(s) to access information placed their by the provider and adapters.
+ * <p>
+ * Context properties are set in the graph context by the various adapters and the provider, or by the graph itself.
+ * These properties may also be accessed by the graph, adapters, or the provider. It is these properties that allow
+ * communication of state through the directed graph. All context properties have a symbolic name that starts with
+ * "CONTEXT_".
+ * </p>
+ *
+ */
+
+public final class Constants {
+
+    /**
+     * The name for the error code attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_ERROR_CODE = "error_code";
+
+    /**
+     * The name for the error message attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_ERROR_MESSAGE = "error-message";
+
+    /**
+     * The name for the success message attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_SUCCESS_MESSAGE = "success-message";
+
+    public static final String DG_ATTRIBUTE_STATUS = "SvcLogic.status";
+    public static final String DG_OUTPUT_STATUS_CODE = "output.status.code";
+    public static final String DG_OUTPUT_STATUS_MESSAGE = "output.status.message";
+
+    /**
+     * The property that defines the name of the DG service logic to be loaded
+     */
+    public static final String PROPERTY_MODULE_NAME = "appc.service.logic.module.name";
+
+    /**
+     * The property that defines the topology restart DG version to be used
+     */
+    public static final String PROPERTY_TOPOLOGY_VERSION = "appc.topology.dg.version";
+
+    /**
+     * The method name of the DG that is used to perform topology restart operations
+     */
+    public static final String PROPERTY_TOPOLOGY_METHOD = "appc.topology.dg.method";
+
+    /**
+     * The property that supplies the application name
+     */
+    public static final String PROPERTY_APPLICATION_NAME = "appc.application.name";
+
+    /**
+     * The execution mode for the directed graph
+     */
+    public static final String SYNC_MODE = "sync";
+
+    /**
+     * The name of the property that contains the service request enumerated value in the graph's context
+     */
+    public static final String CONTEXT_SERVICE = "org.onap.appc.service";
+
+    /**
+     * The name of the property that contains the VM id value in the graph's context
+     */
+    public static final String CONTEXT_VMID = "org.onap.appc.vmid";
+
+    /**
+     * The name of the property that contains the VM id value in the graph's context
+     */
+    public static final String CONTEXT_IDENTITY_URL = "org.onap.appc.identity.url";
+
+    /**
+     * The name of the property that contains the service request id value in the graph's context
+     */
+    public static final String CONTEXT_REQID = "org.onap.appc.reqid";
+
+    /**
+     * The name of the property that indicates which method of the IaaS adapter to call
+     */
+    public static final String CONTEXT_ACTION = "org.onap.appc.action";
+
+    /**
+     * The enumerated value for restart of a VM. This is a constant for one possible value of CONTEXT_SERVICE.
+     */
+    public static final String SERVICE_RESTART = "RESTART";
+
+    /**
+     * The enumerated value for rebuild of a VM. This is a constant for one possible value of CONTEXT_SERVICE.
+     */
+    public static final String SERVICE_REBUILD = "REBUILD";
+
+    /**
+     * The name of the adapter. We get the name from a property file so that it can be changed easily if needed.
+     */
+    public static final String PROPERTY_ADAPTER_NAME = "org.onap.appc.provider.adaptor.name";
+
+    /**
+     * The minimum number of contexts to cache in each provider/tenant pool
+     */
+    public static final String PROPERTY_MIN_POOL_SIZE = "org.onap.appc.provider.min.pool";
+
+    /**
+     * The maximum number of contexts to cache in each provider/tenant pool
+     */
+    public static final String PROPERTY_MAX_POOL_SIZE = "org.onap.appc.provider.max.pool";
+
+    /**
+     * The amount of time, in seconds, that the application waits for a change of state of a server to a known valid
+     * state before giving up and failing the request.
+     */
+    public static final String PROPERTY_SERVER_STATE_CHANGE_TIMEOUT = "org.onap.appc.server.state.change.timeout";
+
+    /**
+     * The amount of time, in seconds, between subsequent polls to the openstack provider to update the state of a
+     * resource
+     */
+    public static final String PROPERTY_OPENSTACK_POLL_INTERVAL = "org.onap.appc.openstack.poll.interval";
+
+    /**
+     * The amount of time, in seconds, to wait between retry attempts when a connection to a provider fails.
+     */
+    public static final String PROPERTY_RETRY_DELAY = "org.onap.appc.provider.retry.delay";
+
+    /**
+     * The maximum number of times a connection retry will be attempted before the application fails the request
+     */
+    public static final String PROPERTY_RETRY_LIMIT = "org.onap.appc.provider.retry.limit";
+    /**
+     * The amount of time, in seconds, that the application waits for a change of state of a stacj to a known valid
+     * state before giving up and failing the request.
+     */
+    public static final String PROPERTY_STACK_STATE_CHANGE_TIMEOUT ="org.onap.appc.stack.state.change.timeout" ;
+
+    @SuppressWarnings("nls")
+    public static final String STATUS_GETTER = "status-getter";
+
+    @SuppressWarnings("nls")
+    public static final String VM_FUSION_STATUS_GETTER = "fusion-vm-status-getter";
+
+    /**
+     * The name for the status vm attribute to be set in the context when executing a vmstatuscheck.
+     */
+    @SuppressWarnings("nls")
+    public static final String STATUS_OF_VM = "status-vm";
+
+    /**
+     * Yang revision value to be used while generating YANG module
+     */
+    public static final String YANG_REVISION = "2017-03-03";
+    /**
+     * Yang revision format to be used while formatting YANG revision date
+     */
+    public static final String YANG_REVISION_FORMAT = "YYYY-MM-DD";
+
+    /**
+     * Base container for  yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_BASE_CONTAINER = "vnf-config-repo";
+
+    /**
+     *VNF config list for yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_VNF_CONFIG_LIST = "vnf-config-list";
+
+    /**
+     *Base container of VNF configuration data for yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_VNF_CONFIG = "vnf-config";
+
+    /**
+     * default constructor prevents instantiation
+     */
+    Constants() {
+        throw new IllegalAccessError("Constants");
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategies.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategies.java
new file mode 100644 (file)
index 0000000..12f3686
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Enum of CacheStrategies
+ */
+public enum CacheStrategies {
+    LRU
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategy.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/CacheStrategy.java
new file mode 100644 (file)
index 0000000..8976a20
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Interface of CacheStrategy
+ * @param <K> key
+ * @param <V> value
+ */
+public interface CacheStrategy <K,V> {
+    /**
+     * Get object
+     * @param key of the object
+     * @return value of the object
+     */
+    V getObject(K key);
+
+    /**
+     * Put object
+     * @param key of the object
+     * @param value of the object
+     */
+    void putObject(K key,V value);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/MetadataCache.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/MetadataCache.java
new file mode 100644 (file)
index 0000000..caf319a
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Interface of MetadataCache
+ * @param <K> key
+ * @param <V> value
+ */
+public interface MetadataCache <K,V> {
+    /**
+     * Get object
+     * @param key of the object
+     * @return value of the object
+     */
+    V getObject(K key);
+
+    /**
+     * Put object
+     * @param key of the object
+     * @param value of the object
+     */
+    void putObject(K key,V value);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/LRUCache.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/LRUCache.java
new file mode 100644 (file)
index 0000000..c88439c
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.onap.appc.cache.CacheStrategy;
+
+/**
+ * LRU cache implements CacheStategy<K, V>
+ * @param <K> Key
+ * @param <V> Value
+ */
+public class LRUCache<K,V> implements CacheStrategy<K,V> {
+
+    private Map<K,V> map;
+
+    LRUCache(final Integer capacity){
+        map = new LinkedHashMap<K,V>(capacity, 0.75F, true) {
+            @Override
+            protected boolean removeEldestEntry(Map.Entry<K, V> eldest){
+                return size() > capacity;
+            }
+        };
+    }
+
+    @Override
+    public V getObject(K key) {
+        return map.get(key);
+    }
+
+    @Override
+    public void putObject(K key, V value) {
+        map.put(key,value);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheFactory.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheFactory.java
new file mode 100644 (file)
index 0000000..b6398e8
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import org.onap.appc.cache.CacheStrategies;
+import org.onap.appc.cache.MetadataCache;
+
+/**
+ * Metadata Cache Factory
+ */
+public class MetadataCacheFactory {
+
+    private static class ReferenceHolder {
+        private ReferenceHolder() {
+            throw new IllegalAccessError("ReferenceHolder");
+        }
+
+        private static final MetadataCacheFactory FACTORY = new MetadataCacheFactory();
+    }
+
+    private MetadataCacheFactory() {
+        // do nothing
+    }
+
+    public static MetadataCacheFactory getInstance(){
+        return ReferenceHolder.FACTORY;
+    }
+
+    public MetadataCache getMetadataCache(){
+        return new MetadataCacheImpl();
+    }
+
+    /**
+     * Get MetadataCache
+     * @param cacheStrategy the CacheStrategies to be used to build MetadataCacheImpl
+     * @return a new instance of MetadataCacheImpl
+     */
+    public MetadataCache getMetadataCache(CacheStrategies cacheStrategy) {
+        return new MetadataCacheImpl(cacheStrategy);
+    }
+
+
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheImpl.java b/appc-core/appc-common-bundle/java/org/onap/appc/cache/impl/MetadataCacheImpl.java
new file mode 100644 (file)
index 0000000..92b70c9
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import org.onap.appc.cache.CacheStrategies;
+import org.onap.appc.cache.CacheStrategy;
+import org.onap.appc.cache.MetadataCache;
+
+/**
+ * Implementation of MetadataCache
+ * @param <K> Key
+ * @param <V> Value
+ */
+public class MetadataCacheImpl<K,V> implements MetadataCache<K,V> {
+
+    private CacheStrategy strategy;
+
+    MetadataCacheImpl(){
+        this(CacheStrategies.LRU);
+    }
+
+    MetadataCacheImpl(CacheStrategies strategy){
+        this.strategy = initializeStrategy(strategy);
+    }
+
+    private CacheStrategy initializeStrategy(CacheStrategies strategy) {
+        if (strategy != null) {
+            switch (strategy) {
+                case LRU:
+                    return new LRUCache<>(50);
+                default:
+                    // do nothing
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public V getObject(K key) {
+        return (V)strategy.getObject(key);
+    }
+
+    @Override
+    public void putObject(K key, V value) {
+        strategy.putObject(key, value);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/concurrent/Signal.java b/appc-core/appc-common-bundle/java/org/onap/appc/concurrent/Signal.java
new file mode 100644 (file)
index 0000000..2daa0cf
--- /dev/null
@@ -0,0 +1,230 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.concurrent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.onap.appc.util.StringHelper;
+
+/**
+ * This class is used to synchronize signaling of status between threads.
+ * <p>
+ * In complex multi-threaded applications it is often necessary to synchronize operations between threads. This is
+ * especially true in complex algorithms where processing dependencies exist between different threads and the
+ * synchronization of the operations of those threads is required. This class is a framework to enable multi-thread
+ * signaling and wait/post logic that makes the thread synchronization easier.
+ * </p>
+ * <p>
+ * Basically, in thread synchronization, one thread is the "waiter" and one or more other threads are the "notifiers".
+ * The notifiers send signals to the waiter to inform that thread that certain conditions are true, processing has been
+ * completed, or to inform the waiter of the state of the other thread(s). In the basic java framework, the waiter and
+ * notifier are simply using the wait/notify mechanism provided, which does not allow for different conditions, state,
+ * or "signals" to exist. The wait/notify mechanism, in combination with the object mutex, provides basic blocking and
+ * releasing of a thread's dispatching state.
+ * </p>
+ * <p>
+ * This class builds upon the java wait/notify mechanism and allows for "signals" to be defined. These signals are
+ * simply string constants that mean something to the waiter and notifier threads. Any number of signals may be defined,
+ * and it is possible to wait for more than one signal to be received, wait for any one of a set to be received, or to
+ * test if a signal has been received without blocking.
+ * </p>
+ * <p>
+ * Some operations are blocking operations. These stop the execution of the calling thread until the specified condition
+ * is true. These blocking methods are all named "wait...", such as {@link #waitFor(String...)} and
+ * {@link #waitForAny(String...)}. The thread making the call to these blocking methods MUST be the waiter thread (the
+ * thread registered with the signal object).
+ * </p>
+ * <p>
+ * Some operations are non-blocking. These operations allow for the testing or setting of signal conditions and do not
+ * block the caller. When calling these methods ({@link #isSignaled(String)}, {@link #signal(String)}, and
+ * {@link #setTimeout(long)} the waiter thread mutex will be held and may block the waiter thread for the duration of
+ * the method call.
+ * </p>
+ */
+public class Signal {
+
+    /**
+     * The thread must be the thread of the waiter that is waiting for the signals to be received. It is the recipient
+     * of the signaled condition. This allows any number of other threads to send signals to the recipient and have the
+     * recipient synchronize its operation with the receipt of the appropriate signal(s).
+     */
+    private Thread thread;
+
+    /**
+     * The amount of time to wait for a signal to be receieved. Set to zero to wait forever.
+     */
+    private long timeout = 0L;
+
+    /**
+     * The collection of all received signals. Note, this need not be a synchronized collection because it will always
+     * be accessed while holding the mutex of the thread, therefore it is implicitly synchronized.
+     */
+    private List<String> receivedSignals;
+
+    /**
+     * A signal object must access a thread that is waiting for the receipt of the signal(s).
+     */
+    public Signal(Thread thread) {
+        this.thread = thread;
+        receivedSignals = new ArrayList<String>();
+    }
+
+    /**
+     * Checks the waiter to see if it has been signaled
+     * 
+     * @param signal
+     *            The signal to check for
+     * @return True if the signal has been received, false otherwise
+     */
+    public boolean isSignaled(String signal) {
+        synchronized (thread) {
+            return _signaled(signal);
+        }
+    }
+
+    /**
+     * Sends the indicated signal to the waiter.
+     * 
+     * @param signal
+     *            The signal that is to be sent to the waiting thread and to notify it to process the signal.
+     */
+    public void signal(String signal) {
+        synchronized (thread) {
+            if (!_signaled(signal)) {
+                receivedSignals.add(signal);
+            }
+            thread.notify();
+        }
+    }
+
+    /**
+     * Blocks the waiting thread until all of the indicated signals have been received, or the wait times out.
+     * 
+     * @param signals
+     *            The signals to be received. The waiter is blocked forever or until all of the signals are received.
+     * @throws TimeoutException
+     *             If the wait has timed out waiting for a response
+     */
+    public void waitFor(String... signals) throws TimeoutException {
+        long limit = System.currentTimeMillis() + timeout;
+        synchronized (thread) {
+            while (true) {
+                boolean complete = true;
+                for (String signal : signals) {
+                    if (!_signaled(signal)) {
+                        complete = false;
+                    }
+                }
+
+                if (complete) {
+                    receivedSignals.removeAll(Arrays.asList(signals));
+                    return;
+                }
+
+                if (timeout > 0) {
+                    if (System.currentTimeMillis() > limit) {
+                        throw new TimeoutException(String.format("Signals %s not received in the allotted timeout.",
+                            StringHelper.asList(signals)));
+                    }
+                }
+
+                try {
+                    thread.wait(timeout);
+                } catch (InterruptedException e) {
+                    /*
+                     * Interrupted exceptions are ignored
+                     */
+                }
+            }
+        }
+    }
+
+    /**
+     * This method blocks the waiter until at least one of the indicated signals have been received.
+     * 
+     * @param signals
+     *            A list of signals, any one of which will satisfy the wait condition
+     * @return The signal that satisfied the wait
+     * @throws TimeoutException
+     *             If none of the signals have been received within the allotted time
+     */
+    public String waitForAny(String... signals) throws TimeoutException {
+        long limit = System.currentTimeMillis() + timeout;
+        synchronized (thread) {
+            while (true) {
+                for (String signal : signals) {
+                    if (!_signaled(signal)) {
+                        receivedSignals.remove(signal);
+                        return signal;
+                    }
+                }
+
+                if (timeout > 0) {
+                    if (System.currentTimeMillis() > limit) {
+                        throw new TimeoutException(
+                            String.format("One of signals \"%s\" not received in the allotted timeout.",
+                                StringHelper.asList(signals)));
+                    }
+                }
+
+                try {
+                    thread.wait(timeout);
+                } catch (InterruptedException e) {
+                    /*
+                     * Interrupted exceptions are ignored
+                     */
+                }
+            }
+        }
+    }
+
+    /**
+     * This private method is used to handle the check for signaled status. Note that this method assumes the caller
+     * holds the thread mutex.
+     * 
+     * @param signals
+     *            The list of signals to check for
+     * @return True if any one of the signals has been received.
+     */
+    private boolean _signaled(String... signals) {
+        for (String signal : signals) {
+            if (receivedSignals.contains(signal)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the timeout value for waiting for signals to be received
+     * 
+     * @param timeout
+     */
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/configuration/Configuration.java b/appc-core/appc-common-bundle/java/org/onap/appc/configuration/Configuration.java
new file mode 100644 (file)
index 0000000..0cc3f26
--- /dev/null
@@ -0,0 +1,242 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+
+
+
+/**
+ * This interface defines the common configuration support that is available to the application.
+ * <p>
+ * Where properties are common to all CDP components (server, coordinator, and EPM), the property symbolic values are
+ * defined as part of this interface. Where they are unique to each component, they must be defined within that
+ * component.
+ * </p>
+ */
+public interface Configuration {
+
+    String PROPERTY_BOOTSTRAP_FILE_NAME = "org_onap_appc_bootstrap_file"; //
+    String DEFAULT_BOOTSTRAP_FILE_NAME = "appc.properties"; 
+    String PROPERTY_BOOTSTRAP_FILE_PATH = "org_onap_appc_bootstrap_path"; //
+    String DEFAULT_BOOTSTRAP_FILE_PATH = "/opt/onap/appc/data/properties,${user.home},etc,../etc";
+    String PROPERTY_RESOURCE_BUNDLES = "org.onap.appc.resources"; 
+    String DEFAULT_RESOURCE_BUNDLES = "org/onap/appc/i18n/MessageResources";
+
+   /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
+     * {@link Boolean#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property key
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    boolean getBooleanProperty(String key);
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
+     * {@link Boolean#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property key
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    boolean getBooleanProperty(String key, boolean defaultValue);
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value (double). The standard
+     * rules for {@link Double#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property to retrieve
+     * @return The value of the property, or 0.0 if not found or invalid
+     */
+    double getDoubleProperty(String key);
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value (double). The standard
+     * rules for {@link Double#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property to retrieve
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property, or 0.0 if not found or invalid
+     */
+    double getDoubleProperty(String key, double defaultValue);
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     * 
+     * @param key
+     *            The property name to retrieve.
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     */
+    int getIntegerProperty(String key);
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     * 
+     * @param key
+     *            The property name to retrieve.
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     */
+    int getIntegerProperty(String key, int defaultValue);
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or zero if it does not.
+     * 
+     * @param key
+     *            The key of the property desired.
+     * @return The value of the property expressed as an integer long value, or zero if the property does not exist or
+     *         is not a valid integer long.
+     */
+    long getLongProperty(String key);
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or the default value if it does not exist
+     * or is invalid.
+     * 
+     * @param key
+     *            The key of the property desired.
+     * @param defaultValue
+     *            the value to be returned if the property is not valid or does not exist.
+     * @return The value of the property expressed as an integer long value, or the default value if the property does
+     *         not exist or is not a valid integer long.
+     */
+    long getLongProperty(String key, long defaultValue);
+
+    /**
+     * This method can be called to retrieve a properties object that is immutable. Any attempt to modify the properties
+     * object returned will result in an exception. This allows a caller to view the current configuration as a set of
+     * properties.
+     * 
+     * @return An unmodifiable properties object.
+     */
+    Properties getProperties();
+
+    /**
+     * This method is called to obtain a property as a string value
+     * 
+     * @param key
+     *            The key of the property
+     * @return The string value, or null if it does not exist.
+     */
+    String getProperty(String key);
+
+    /**
+     * This method is called to obtain a property as a string value
+     * 
+     * @param key
+     *            The key of the property
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     */
+    String getProperty(String key, String defaultValue);
+
+    /**
+     * Returns true if the named property is defined, false otherwise.
+     * 
+     * @param key
+     *            The key of the property we are interested in
+     * @return True if the property exists.
+     */
+    boolean isPropertyDefined(String key);
+
+    /**
+     * Returns an indication of the validity of the boolean property. A boolean property is considered to be valid only
+     * if it has the value "true" or "false" (ignoring case).
+     * 
+     * @param key
+     *            The property to be checked
+     * @return True if the value is a boolean constant, or false if it does not exist or is not a correct string
+     */
+    boolean isValidBoolean(String key);
+
+    /**
+     * Returns an indication if the indicated property represents a valid double-precision floating point number.
+     * 
+     * @param key
+     *            The property to be examined
+     * @return True if the property is a valid representation of a double, or false if it does not exist or contains
+     *         illegal characters.
+     */
+    boolean isValidDouble(String key);
+
+    /**
+     * Returns an indication if the property is a valid integer value or not.
+     * 
+     * @param key
+     *            The key of the property to check
+     * @return True if the value is a valid integer string, or false if it does not exist or contains illegal
+     *         characters.
+     */
+    boolean isValidInteger(String key);
+
+    /**
+     * Determines is the specified property exists and is a valid representation of an integer long value.
+     * 
+     * @param key
+     *            The property to be checked
+     * @return True if the property is a valid representation of an integer long value, and false if it either does not
+     *         exist or is not valid.
+     */
+    boolean isValidLong(String key);
+
+    /**
+     * This method allows the caller to set all properties from a provided properties object into the configuration
+     * property set.
+     * <p>
+     * The primary difference between this method and the factory method
+     * {@link ConfigurationFactory#getConfiguration(Properties)} is that this method does not clear and reload the
+     * configuration. Rather, this method merges the provided properties object contents into the existing properties,
+     * replacing any same-named keys with the values from this object.
+     * </p>
+     * 
+     * @param properties
+     *            The properties object to copy all properties from
+     */
+    void setProperties(Properties properties);
+
+    /**
+     * This method allows a caller to insert a new property definition into the configuration object. This allows the
+     * application to adjust or add to the current configuration. If the property already exists, it is replaced with
+     * the new value.
+     * 
+     * @param key
+     *            The key of the property to be defined
+     * @param value
+     *            The value of the property to be defined
+     */
+    void setProperty(String key, String value);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/configuration/ConfigurationFactory.java b/appc-core/appc-common-bundle/java/org/onap/appc/configuration/ConfigurationFactory.java
new file mode 100644 (file)
index 0000000..9ea5083
--- /dev/null
@@ -0,0 +1,433 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import org.onap.appc.i18n.Msg;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.i18n.EELFResourceManager;
+
+/**
+ * The configuration factory is used to obtain access to an already created and initialized
+ * singleton configuration object as well as to create and initialize the singleton if not already
+ * set up.
+ * <p>
+ * This class is responsible for the creation of the configuration object used to manage the
+ * configuration of the application. The configuration object implementation must implement the
+ * <code>Configuration</code> interface. This allows for the factory to create different
+ * specializations in the future if needed and not break any application code.
+ * </p>
+ * <p>
+ * The configuration object is basically a wrapper around a properties object. The configuration is
+ * therefore specified as a set of properties that are loaded and processed from different sources
+ * with different precedences. It is important that the configuration object always be able to
+ * supply default values for any configuration properties that must be supplied, and not rely on the
+ * user always supplying these values. This also relieves the application itself from having to
+ * interpret missing or invalid properties and applying defaults. By having all of the defaults in
+ * one place, the application code can be simpler (not having to worry about defaults or invalid
+ * properties), and the defaults can be changed much easier (they are all in one place and not
+ * distributed throughout the codebase).
+ * </p>
+ * <p>
+ * Since the configuration is managed as a property object, we can use a characteristic of the
+ * <code>Properties</code> class to our advantage. Namely, if we put a property into a
+ * <code>Properties</code> object that already exists, the <code>Properties</code> object replaces
+ * it with the new value. This does not affect any other properties that may already be defined in
+ * the properties object. This gives us the ability to initialize the properties with default values
+ * for all of the application settings, then override just those that we need to override, possibly
+ * from multiple sources and in increasing order of precedence.
+ * </p>
+ * <p>
+ * This means that properties are in effect "merged" together from multiple sources in a prescribed
+ * precedence order. In fact, the precedence order that this factory implements is defined as:
+ * </p>
+ * <ol>
+ * <li>Default values from a system resource file.</li>
+ * <li>User-supplied properties file, if any.</li>
+ * <li>Application-supplied properties, if any.</li>
+ * <li>Command-line properties (if any)</li>
+ * </ol>
+ * <p>
+ * The name and location of the properties file that is loaded can also be set, either in the
+ * defaults, overridden by the system command line via -D, or as a system environment variable.
+ * There are two properties that can be specified to define the name and path. These are:
+ * </p>
+ * <dl>
+ * <dt>org.onap.appc.bootstrap.file</dt>
+ * <dd>This property defines the name of the file that will be loaded. If not specified, the default
+ * value is "appc.properties". This can be specified in either (or both) the default properties or
+ * the command line. The command line specification will always override.</dd>
+ * <dt>org.onap.appc.bootstrap.path</dt>
+ * <dd>This is a comma-delimited (,) path of directories to be searched to locate the specified
+ * file. The first occurrence of the file is the one loaded, and no additional searching is
+ * performed. The path can be specified in either, or both, the default values and the command line
+ * specification. If specified on the command line, the value overrides the default values. If
+ * omitted, the default path is <code>$/opt/onap/appc/data/properties,${user.home},.</code></dd>
+ * </dl>
+ *
+ * @since Mar 18, 2014
+ * @version $Id$
+ */
+public final class ConfigurationFactory {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(ConfigurationFactory.class);
+
+    /**
+     * This is a string constant for the comma character. It's intended to be used a common string
+     * delimiter.
+     */
+    private static final String COMMA = ",";
+
+    /**
+     * The default Configuration object that implements the <code>Configuration</code> interface and
+     * represents our system configuration settings.
+     */
+    private static DefaultConfiguration config = null;
+
+    /**
+     * The default properties resource to be loaded
+     */
+    private static final String DEFAULT_PROPERTIES = "org/onap/appc/default.properties";
+
+    /**
+     * This collection allows for special configurations to be created and maintained, organized by
+     * some identification (such as an object reference to the StackBuilder to which they apply),
+     * and then obtained from the configuration factory when needed.
+     */
+    private static HashMap<Object, Configuration> localConfigs = new HashMap<>();
+
+    /**
+     * The reentrant shared lock used to serialize access to the properties.
+     */
+    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+    /**
+     * This is a constant array of special property names that will be copied from the configuration
+     * back to the System properties object if they are defined in the configuration AND they do not
+     * already exist in the System properties object. These are intended as a convenience for
+     * setting the AFT properties for the Discovery client where it may be difficult or impossible
+     * to set VM arguments for the container.
+     */
+    private static final String[] specialProperties =
+            {"AFT_LATITUDE", "AFT_LONGITUDE", "AFT_ENVIRONMENT", "SCLD_PLATFORM"};
+
+    private ConfigurationFactory() {}
+
+    /**
+     * This method is used to obtain the common configuration object (as well as set it up if not
+     * already).
+     *
+     * @return The configuration object implementation
+     */
+    public static Configuration getConfiguration() {
+
+        /*
+         * First, attempt to access the properties as a read lock holder
+         */
+        ReadLock readLock = lock.readLock();
+        readLock.lock();
+        try {
+
+            /*
+             * If the properties don't exist, release the read lock and acquire the write lock. Once
+             * we get the write lock, we need to re-check to see that the configuration needs to be
+             * set up (because another thread may have beat us to it). After we get a configuration
+             * set up, release the write lock and re-obtain the read lock to access the properties.
+             */
+            if (config == null) {
+                readLock.unlock();
+                WriteLock writeLock = lock.writeLock();
+                writeLock.lock();
+                try {
+                    if (config == null) {
+                        config = new DefaultConfiguration();
+                        initialize(null);
+                    }
+                } catch (Exception e){
+                    logger.error("getConfiguration", e);
+                } finally {
+                    writeLock.unlock();
+                }
+                readLock.lock();
+            }
+        } finally {
+            readLock.unlock();
+        }
+        return config;
+    }
+
+    /**
+     * This method will obtain the local configuration for the specified object if it exists, or
+     * will create it from the current global configuration. This allows the configuration to be
+     * tailored for a specific process or operation, and uniquely identified by some value (such as
+     * the object that represents the special use of the configuration).
+     *
+     * @param owner The owner or identification of the owner of the special configuration
+     * @return The special configuration object, or a clone of the global configuration so that it
+     *         can be altered if needed.
+     */
+    public static Configuration getConfiguration(final Object owner) {
+        DefaultConfiguration local;
+        ReadLock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            local = (DefaultConfiguration) localConfigs.get(owner);
+            if (local == null) {
+                readLock.unlock();
+                WriteLock writeLock = lock.writeLock();
+                writeLock.lock();
+                local = (DefaultConfiguration) localConfigs.get(owner);
+                if (local == null) {
+                    local = getClonedDefaultConfiguration(owner, local);
+                }
+                writeLock.unlock();
+            }
+            readLock.lock();
+        } finally {
+            readLock.unlock();
+        }
+        return local;
+    }
+
+    /**
+     * This method allows the caller to alter the configuration, supplying the specified
+     * configuration properties which override the application default values.
+     * <p>
+     * The configuration is re-constructed (if already constructed) or created new (if not already
+     * created) and the default properties are loaded into the configuration.
+     * </p>
+     * <p>
+     * The primary purpose of this method is to allow the application configuration properties to be
+     * reset or refreshed after the application has already been initialized. This method will lock
+     * the configuration for the duration while it is being re-built, and should not be called on a
+     * regular basis.
+     * </p>
+     *
+     * @param props The properties used to configure the application.
+     * @return Access to the configuration implementation
+     */
+    public static Configuration getConfiguration(final Properties props) {
+        WriteLock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            config = new DefaultConfiguration();
+            initialize(props);
+            return config;
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    private static DefaultConfiguration getClonedDefaultConfiguration(Object owner, DefaultConfiguration local) {
+        Optional<DefaultConfiguration> global =
+                Optional.ofNullable((DefaultConfiguration) getConfiguration());
+        try {
+            if (global.isPresent()) {
+                local = (DefaultConfiguration) global.get().clone();
+            }
+        } catch (CloneNotSupportedException e) {
+            logger.error("getClonedDefaultConfiguration", e);
+        }
+        localConfigs.put(owner, local);
+        return local;
+    }
+
+    /**
+     * This method will clear the current configuration and then re-initialize it with the default
+     * values, application-specific configuration file, user-supplied properties (if any), and then
+     * command-line settings.
+     * <p>
+     * This method <strong><em>MUST</em></strong> be called holding the configuration lock!
+     * </p>
+     * <p>
+     * This method is a little special in that logging messages generated during the method must be
+     * cached and delayed until after the logging framework has been initialized. After that, the
+     * delayed logging buffer can be dumped to the log file and cleared.
+     * </p>
+     *
+     * @param props Application-supplied configuration values, if any
+     */
+    private static void initialize(final Properties props) {
+        DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
+        Date now = new Date();
+        logger.info(
+                "------------------------------------------------------------------------------");
+
+        logger.info(Msg.CONFIGURATION_STARTED, format.format(now));
+
+        /*
+         * Clear any existing properties
+         */
+        config.clear();
+        logger.info(Msg.CONFIGURATION_CLEARED);
+
+        /*
+         * Load the defaults (if any are present)
+         */
+        InputStream in = Thread.currentThread().getContextClassLoader()
+                .getResourceAsStream(DEFAULT_PROPERTIES);
+        if (in != null) {
+            logger.info(Msg.LOADING_DEFAULTS, DEFAULT_PROPERTIES);
+            try {
+                config.setProperties(in);
+            } finally {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    logger.error("Cannot close inputStream", e);
+                }
+            }
+            for (String key : config.getProperties().stringPropertyNames()) {
+                logger.info(Msg.PROPERTY_VALUE, key, config.getProperty(key));
+            }
+        } else {
+            logger.info(Msg.NO_DEFAULTS_FOUND, DEFAULT_PROPERTIES);
+        }
+
+        /*
+         * Look for application configuration property file. By default, we will look for the file
+         * "cdp.properties" on the user home path, then on "./etc" (relative to current path), then
+         * on "../etc" (relative to current path). If we do not find any property file, then we
+         * continue. Otherwise, we load the first property file we find and then continue. In order
+         * to allow default values for the filename and paths to be searched, we first attempt to
+         * obtain these from our configuration object (which should be primed with default values
+         * and/or overridden with application-specified values). We then use the values obtained
+         * from that to get any user supplied values on the command line.
+         */
+        String filename = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME,
+                Configuration.DEFAULT_BOOTSTRAP_FILE_NAME);
+        filename = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME, filename);
+        String env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME);
+        if (env != null && env.trim().length() > 0) {
+            filename = env;
+        }
+
+        String path = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH,
+                Configuration.DEFAULT_BOOTSTRAP_FILE_PATH);
+        path = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH, path);
+        env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH);
+        if (env != null && env.trim().length() > 0) {
+            path = env;
+        }
+
+        logger.info(Msg.SEARCHING_CONFIGURATION_OVERRIDES, path, filename);
+
+        String[] pathElements = path.split(COMMA);
+        boolean found = false;
+        for (String pathElement : pathElements) {
+            File file = new File(pathElement, filename);
+            if (file.exists() && file.canRead() && !file.isDirectory()) {
+
+                logger.info(Msg.LOADING_CONFIGURATION_OVERRIDES, file.getAbsolutePath());
+                Properties fileProperties = new Properties();
+                BufferedInputStream stream = null;
+                try {
+                    stream = new BufferedInputStream(new FileInputStream(file));
+                    fileProperties.load(stream);
+                    for (String key : fileProperties.stringPropertyNames()) {
+                        logger.debug(Msg.PROPERTY_VALUE, key, fileProperties.getProperty(key));
+                        config.setProperty(key, fileProperties.getProperty(key));
+                    }
+                    found = true;
+                    break;
+                } catch (IOException e) {
+                    logger.error(EELFResourceManager.format(e));
+                } finally {
+                    try {
+                        if (stream != null) {
+                            stream.close();
+                        }
+                    } catch (IOException e) {
+                        logger.error("Unable to close stream", e);
+                    }
+                }
+            }
+        }
+
+        if (!found) {
+            logger.warn(Msg.NO_OVERRIDE_PROPERTY_FILE_LOADED, filename, path);
+        }
+
+        /*
+         * Apply any application-specified properties
+         */
+        if (props != null) {
+            logger.info(Msg.LOADING_APPLICATION_OVERRIDES);
+            for (String key : props.stringPropertyNames()) {
+                logger.debug(Msg.PROPERTY_VALUE, key, props.getProperty(key));
+                config.setProperty(key, props.getProperty(key));
+            }
+        } else {
+            logger.info(Msg.NO_APPLICATION_OVERRIDES);
+        }
+
+        /*
+         * Merge in the System.properties to pick-up any command line arguments (-Dkeyword=value)
+         */
+        logger.info(Msg.MERGING_SYSTEM_PROPERTIES);
+        config.setProperties(System.getProperties());
+
+        /*
+         * As a convenience, copy the "specialProperties" that are not defined in System.properties
+         * from the configuration back to the system properties object.
+         */
+        for (String key : config.getProperties().stringPropertyNames()) {
+            for (String specialProperty : specialProperties) {
+                if (key.equals(specialProperty) && !System.getProperties().containsKey(key)) {
+                    System.setProperty(key, config.getProperty(key));
+                    logger.info(Msg.SETTING_SPECIAL_PROPERTY, key, config.getProperty(key));
+                }
+            }
+        }
+
+        /*
+         * Initialize the resource manager by loading the requested bundles, if any are defined.
+         * Resource bundles may be specified as a comma-delimited list of names. These resource
+         * names are base names of resource bundles, do not include the language or country code, or
+         * the ".properties" extension. The actual loading of the resource bundles is done lazily
+         * when requested the first time. If the bundle does not exist, or cannot be loaded, it is
+         * ignored.
+         */
+        String resourcesList = config.getProperty(Configuration.PROPERTY_RESOURCE_BUNDLES,
+                Configuration.DEFAULT_RESOURCE_BUNDLES);
+        String[] resources = resourcesList.split(",");
+        for (String resource : resources) {
+            logger.info(Msg.LOADING_RESOURCE_BUNDLE, resource.trim());
+            EELFResourceManager.loadMessageBundle(resource.trim());
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/configuration/DefaultConfiguration.java b/appc-core/appc-common-bundle/java/org/onap/appc/configuration/DefaultConfiguration.java
new file mode 100644 (file)
index 0000000..635110c
--- /dev/null
@@ -0,0 +1,564 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.onap.appc.encryption.EncryptionTool;
+import org.onap.appc.util.UnmodifiableProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class provides the implementation of the <code>Configuration</code> interface. It is created
+ * by the ConfigurationFactory and initialized with the configuration values for the process.
+ *
+ * @since Mar 18, 2014
+ */
+public final class DefaultConfiguration implements Configuration, Cloneable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class);
+
+    /**
+     * The framework configuration properties.
+     */
+    private Properties properties = new Properties();
+
+    /**
+     * Construct the configuration object.
+     */
+    DefaultConfiguration() {}
+
+    /**
+     * Clears all properties
+     */
+    public void clear() {
+        properties.clear();
+    }
+
+    /**
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    protected Object clone() throws CloneNotSupportedException {
+        DefaultConfiguration clone = (DefaultConfiguration) super.clone();
+
+        clone.properties = new Properties(this.properties);
+        clone.properties.putAll(this.properties);
+
+        return clone;
+    }
+
+    /**
+     * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no
+     * operation on the string if it is not encrypted.
+     *
+     * @param value The value to (optionally) be decrypted
+     * @return The clear text
+     */
+    @SuppressWarnings("nls")
+    private static String decrypt(String value) {
+        if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
+            try {
+                return EncryptionTool.getInstance().decrypt(value);
+            } catch (Exception e) {
+                StringBuilder out = new StringBuilder();
+                for (Provider p : Security.getProviders()) {
+                    for (Service s : p.getServices()) {
+                        String algo = s.getAlgorithm();
+                        out.append(String.format(
+                                "\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]",
+                                algo, p.getName(), s.getClassName()));
+                    }
+                }
+                logger.debug(out.toString());
+                logger.warn(String.format("Could not decrypt the configuration value [%s]", value),
+                        e);
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Decrypts all elements in the properties object
+     */
+    private void decryptAllProperties() {
+        if (properties != null) {
+            for (Entry<Object, Object> e : properties.entrySet()) {
+                if (e.getValue() != null) {
+                    e.setValue(decrypt(e.getValue().toString()));
+                }
+            }
+        }
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (this.getClass() != obj.getClass()) {
+            return false;
+        }
+
+        DefaultConfiguration other = (DefaultConfiguration) obj;
+
+        return (this.properties.size() == other.properties.size())
+                && (this.properties.entrySet().containsAll(other.properties.entrySet()))
+                && (other.properties.entrySet().containsAll(this.properties.entrySet()));
+
+    }
+
+    /**
+     * This method will use the properties object to expand any variables that may be present in the
+     * template provided. Variables are represented by the string "${name}", where "name" is the
+     * name of a property defined in either the current configuration object, or system properties
+     * if undefined. If the value cannot be found, the variable is removed and an empty string is
+     * used to replace the variable.
+     *
+     * @param template The template to be expanded
+     * @return The expanded template where each variable is replaced with its value
+     */
+    @SuppressWarnings("nls")
+    private String expandVariables(String template) {
+        if (template == null) {
+            return null;
+        }
+
+        // Decrypt the template if needed
+        // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also,
+        // Sonar complains
+        // bitterly
+
+        StringBuilder builder = new StringBuilder(decrypt(template));
+        Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}");
+        Matcher matcher = pattern.matcher(builder);
+        while (matcher.find()) {
+            String variable = matcher.group(1);
+            String value = properties.getProperty(variable);
+            if (value == null) {
+                value = System.getProperty(variable);
+            }
+            if (value == null) {
+                value = "";
+            }
+            builder.replace(matcher.start(), matcher.end(), value);
+
+            matcher.reset();
+        }
+        return builder.toString().trim();
+    }
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The
+     * standard rules for Boolean.parseBoolean() are used.
+     *
+     * @param key The property key
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public boolean getBooleanProperty(String key) {
+        return Boolean.valueOf(getProperty(key, "false"));
+    }
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The
+     * standard rules for Boolean.valueOf(String) are used.
+     *
+     * @param key The property key
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getBooleanProperty(java.lang.String, boolean)
+     */
+    @Override
+    public boolean getBooleanProperty(String key, boolean defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getBooleanProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value
+     * (double).
+     *
+     * @param key The property to retrieve
+     * @return The value of the property, or 0.0 if not found
+     * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public double getDoubleProperty(String key) {
+        try {
+            return Double.valueOf(getProperty(key, "0.0"));
+        } catch (NumberFormatException e) {
+            return 0.0;
+        }
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String, double)
+     */
+    @Override
+    public double getDoubleProperty(String key, double defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getDoubleProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     *
+     * @param key The property name to retrieve.
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public int getIntegerProperty(String key) {
+        try {
+            return Integer.parseInt(getProperty(key, "0"), 10);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * Integer.parseInt(String, int) using a radix of 10 are used.
+     *
+     * @param key The property name to retrieve.
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String, int)
+     */
+    @Override
+    public int getIntegerProperty(String key, int defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getIntegerProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or zero if it does not.
+     *
+     * @param key The key of the property desired.
+     * @return The value of the property expressed as an integer long value, or zero if the property
+     *         does not exist or is not a valid integer long.
+     * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public long getLongProperty(String key) {
+        try {
+            return Long.parseLong(getProperty(key, "0"), 10);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or the default value if
+     * it does not exist or is invalid.
+     *
+     * @param key The key of the property desired.
+     * @param defaultValue the value to be returned if the property is not valid or does not exist.
+     * @return The value of the property expressed as an integer long value, or the default value if
+     *         the property does not exist or is not a valid integer long.
+     * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String, long)
+     */
+    @Override
+    public long getLongProperty(String key, long defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getLongProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * This method can be called to retrieve a properties object that is immutable. Any attempt to
+     * modify the properties object returned will result in an exception. This allows a caller to
+     * view the current configuration as a set of properties.
+     *
+     * @return An unmodifiable properties object.
+     * @see org.onap.appc.configuration.Configuration#getProperties()
+     */
+    @Override
+    public Properties getProperties() {
+        return new UnmodifiableProperties(properties);
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @return The string value, or null if it does not exist.
+     */
+    @Override
+    public String getProperty(String key) {
+        String value = properties.getProperty(key);
+        if (value == null) {
+            return null;
+        }
+        return expandVariables(value.trim());
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getProperty(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getProperty(key);
+        }
+
+        if (defaultValue == null) {
+            return null;
+        }
+
+        return expandVariables(defaultValue.trim());
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return properties == null ? 0 : properties.hashCode();
+    }
+
+    /**
+     * Returns true if the named property is defined, false otherwise.
+     *
+     * @param key The key of the property we are interested in
+     * @return True if the property exists.
+     */
+    @Override
+    public boolean isPropertyDefined(String key) {
+        return properties.containsKey(key);
+    }
+
+    /**
+     * Returns an indication of the validity of the boolean property. A boolean property is
+     * considered to be valid only if it has the value "true" or "false" (ignoring case).
+     *
+     * @param key The property to be checked
+     * @return True if the value is a boolean constant, or false if it does not exist or is not a
+     *         correct string
+     * @see org.onap.appc.configuration.Configuration#isValidBoolean(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public boolean isValidBoolean(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            value = value.toLowerCase();
+            return value.matches("true|false");
+        }
+        return false;
+    }
+
+    /**
+     * Returns an indication if the indicated property represents a valid double-precision floating
+     * point number.
+     *
+     * @param key The property to be examined
+     * @return True if the property is a valid representation of a double, or false if it does not
+     *         exist or contains illegal characters.
+     * @see org.onap.appc.configuration.Configuration#isValidDouble(java.lang.String)
+     */
+    @Override
+    public boolean isValidDouble(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Double.valueOf(value);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an indication if the property is a valid integer value or not.
+     *
+     * @param key The key of the property to check
+     * @return True if the value is a valid integer string, or false if it does not exist or
+     *         contains illegal characters.
+     * @see org.onap.appc.configuration.Configuration#isValidInteger(java.lang.String)
+     */
+    @Override
+    public boolean isValidInteger(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Integer.parseInt(value.trim(), 10);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines is the specified property exists and is a valid representation of an integer long
+     * value.
+     *
+     * @param key The property to be checked
+     * @return True if the property is a valid representation of an integer long value, and false if
+     *         it either does not exist or is not valid.
+     * @see org.onap.appc.configuration.Configuration#isValidLong(java.lang.String)
+     */
+    @Override
+    public boolean isValidLong(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Long.parseLong(value.trim(), 10);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method allows an implementation to load configuration properties that may override
+     * default values.
+     *
+     * @param is An input stream that contains the properties to be loaded
+     */
+    public void setProperties(InputStream is) {
+        try {
+            properties.load(is);
+        } catch (IOException e) {
+            logger.warn("setProperties with inputStream got exception", e);
+        }
+    }
+
+    /**
+     * This method allows an implementation to load configuration properties that may override
+     * default values.
+     *
+     * @param props An optional Properties object to be merged into the configuration, replacing any
+     *        same-named properties.
+     * @see org.onap.appc.configuration.Configuration#setProperties(java.util.Properties)
+     */
+    @Override
+    public void setProperties(Properties props) {
+        properties.putAll(props);
+        decryptAllProperties();
+    }
+
+    /**
+     * This method allows a caller to insert a new property definition into the configuration
+     * object. This allows the application to adjust or add to the current configuration. If the
+     * property already exists, it is replaced with the new value.
+     *
+     * @param key The key of the property to be defined
+     * @param value The value of the property to be defined
+     * @see org.onap.appc.configuration.Configuration#setProperty(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public void setProperty(String key, String value) {
+        properties.setProperty(key, decrypt(value));
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public String toString() {
+        return String.format("Configuration: %d properties, keys:[%s]", properties.size(),
+                properties.keySet().toString());
+    }
+
+    /**
+     * This is a helper method to read the manifest of the jar file that this class was loaded from.
+     * Note that this will only work if the code is packaged in a jar file. If it is an open
+     * deployment, such as under eclipse, this will not work and there is code added to detect that
+     * case.
+     *
+     * @return The manifest object from the jar file, or null if the code is not packaged in a jar
+     *         file.
+     */
+    @SuppressWarnings({"unused", "nls"})
+    private Manifest getManifest() {
+        ProtectionDomain domain = getClass().getProtectionDomain();
+        CodeSource source = domain.getCodeSource();
+        URL location = source.getLocation();
+        String path = location.getPath();
+        int index = path.indexOf('!');
+        if (index != -1) {
+            path = path.substring(0, index);
+        }
+        if (path.endsWith(".jar")) {
+            try (JarFile jar = new JarFile(location.getFile())) {
+                return jar.getManifest();
+            } catch (IOException e) {
+                logger.error("getManifest", e);
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/configuration/package.html b/appc-core/appc-common-bundle/java/org/onap/appc/configuration/package.html
new file mode 100644 (file)
index 0000000..c6889da
--- /dev/null
@@ -0,0 +1,174 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP : APPC
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Copyright (C) 2017 Amdocs
+  =============================================================================
+  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.
+  
+  ECOMP is a trademark and service mark of AT&T Intellectual Property.
+  ============LICENSE_END=========================================================
+  -->
+
+<html>
+<head>
+<title>Configuration</title>
+</head>
+
+<body>
+  <p style="margin-left: 30.0px;">
+    CDP Configuration support is provided by a common framework to load
+    and manage configuration properties from multiple sources. The basic
+    concept is to load a set of default properties from a known resource
+    file located on the class path, and then override these defaults
+    with optional settings that can be provided by a user through either
+    additional property files or via the command line (as VM arguments).
+    The loading of defaults from a resource property file (named <strong>com/att/cdp/default.properties</strong>)
+    ensures that values are defined for properties the application needs
+    in order to operate.
+  </p>
+  <p style="margin-left: 30.0px;">
+    One of these default values that can be set is the name of the
+    property file that allows the user to supply settings, as well as
+    the path where the file can be found. In general, the default name
+    of the property file will be &quot;<strong>cdp.properties</strong>&quot;,
+    and the path that will be searched is &quot;<strong>${user.home};etc;../etc</strong>&quot;.
+    However, these values can be changed through the use of the
+    default.properties resource file. The property that specifies the
+    property file name is named <strong>com.att.cdp.bootstrap.file</strong>,
+    while the property named <strong>com.att.cdp.bootstrap.path</strong>
+    specifies the search path.
+  </p>
+  <p style="margin-left: 30.0px;">
+    After the default.properties are loaded, but prior to searching for
+    the application configuration file, the configuration factory checks
+    for properties <strong>com.att.cdp.bootstrap.path</strong> and <strong>com.att.cdp.bootstrap.file
+    </strong>in the System properties object (meaning they were set by the
+    command line). If these values are defined in the system properties
+    object, they are used. If not, these values are obtained from the
+    default properties just loaded. This allows the specification of
+    either the file name or path, or both, to be overridden during start
+    up by using command-line arguments.
+  </p>
+  <p style="margin-left: 30.0px;">The search path is scanned for the
+    first occurrence of the specified property file. The first
+    occurrence is loaded and scanning is stopped at that point. The
+    configuration factory does not load all occurrences it finds, only
+    the first occurrence it finds.</p>
+  <p style="margin-left: 30.0px;">The configuration properties are
+    loaded and processed according to a defined precedence order, such
+    that properties defined with a higher precedence override the same
+    property at a lower precedence. The precedence order is defined as
+    follows:</p>
+  <h2>Precedence Order</h2>
+  <ol>
+    <li>Default properties are initially loaded into the
+      configuration. These default properties are the lowest level
+      precedence, and will be overridden by any properties specified at
+      higher levels. These are loaded from resources that are packaged
+      as part of the various application components. Each component
+      (Server, Coordinator, EPM, or CLI) may have different default
+      properties. The default properties are loaded from a resource
+      named <strong>com/att/cdp/default.properties</strong>. The default
+      properties can specify the name of the application property file
+      to be used to configure the application, as well as the path to
+      search. Additionally, these properties can be supplied via the
+      command line to override the default settings if needed.<br /> <br />
+    </li>
+    <li>The configuration factory allows for the application to
+      supply an initial properties object to initialize the
+      configuration. This properties object could be loaded or created
+      in any way necessary for the application. This is totally up to
+      the application to define, if it is needed. If no
+      application-specific property object is supplied, this step is
+      skipped. If a property object is supplied, it is used to replace
+      or set any properties that may have been defined by the defaults.<br />
+      <br />
+    </li>
+    <li>The configuration factory will then search for a bootstrap
+      file on a bootstrap path. The actual bootstrap file name and path
+      can be specified as properties on the command line, or will
+      default to a file name of <strong>cdp.properties</strong> and a
+      path of <strong>${user.home};etc;../etc</strong>. If desired, the
+      user can specify the exact name of the property file to be loaded
+      as well as the path using <strong>-Dcom.att.cdp.bootstrap.file=&lt;filename&gt;</strong>
+      and <strong>-Dcom.att.cdp.bootstrap.path=&lt;path&gt;</strong>.
+      These properties are set to default values by the default
+      properties loaded in step #1 above. The first occurrence of a
+      property file is the file loaded and used. Any other occurrences
+      are not processed.<br /> <br />
+    </li>
+    <li>The System properties are then merged into the
+      configuration. This allows the highest level of precedence,
+      command-line VM arguments (-D<strong>name=value</strong>) to be
+      merged into the configuration property object. These settings
+      override all lower level settings of the same name, as well as
+      merge all system properties into the configuration object.
+    </li>
+  </ol>
+  <h2>Variables</h2>
+  <p style="margin-left: 30.0px;">
+    The configuration support allows for variables to be inserted into
+    any property that is defined. Variables are named using the format <strong>${name}</strong>,
+    where the &quot;name&quot; is the name of a property that is defined
+    in the configuration, or a system property (such as <strong>user.home</strong>).
+    Variables can nest, such that a variable can be replaced with
+    another variable, which is then reevaluated to obtain the value.
+    This allows for indirection as well as variable substitution, if
+    needed.
+  </p>
+  <h2>Using the Configuration Support</h2>
+  <p style="margin-left: 30.0px;">
+    The configuration support was designed to be easy to use. The
+    configuration implementation is abstracted away from the application
+    so that it could be changed easily in the future if needed, or if we
+    needed to load different implementations for different reasons. This
+    means that the application always accesses the configuration through
+    an interface, named <strong>Configuration</strong>. The
+    implementation of that configuration interface is obtained by a
+    static method on the <strong>ConfigurationFactory</strong> class.
+    The configuration factory will both create the configuration if not
+    already created on the first access, as well as return the current
+    configuration if already created. Additionally, the
+    ConfigurationFactory provides mechanisms to recreate the
+    configuration after the application is initialized should the need
+    arise to update its configuration.
+  </p>
+  <p style="margin-left: 30.0px;">An example of the code needed to
+    obtain access to the configuration is:</p>
+  <pre style="margin-left: 30.0px;">Configuration config = ConfigurationFactory.getConfiguration();</pre>
+  <p style="margin-left: 30.0px;">Please refer to the javadoc or the
+    source code in cdp-common for other ways that the configuration and
+    configuration factory can be used.</p>
+  <h2>Reloading Properties</h2>
+  <p style="margin-left: 30.0px;">The configuration support allows
+    for properties to be re-loaded and re-evaluated after the
+    application is running. This is designed to allow a configuration to
+    be refreshed should the need arise. This could allow on-demand
+    refresh (via a command, for example), or automatically based on
+    sensing a change in the configuration file.</p>
+  <p style="margin-left: 30.0px;">
+    When the <strong>ConfigurationFactory</strong> method <strong>getConfiguration(Propert</strong><strong>ies)</strong>
+    is called, the current configuration is cleared and rebuilt using
+    the process defined above. The supplied property object is used in
+    step #2 of the process. While the properties are being re-built, no
+    access to the properties are allowed. Any attempt to access
+    properties while the re-build operation is in effect will block the
+    caller until completed. This is accomplished using read and write
+    shared locks.
+  </p>
+</body>
+</html>
+>>>>>>> app-controller/master:appc-common/src/main/java/org/onap/appc/configuration/package.html
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionException.java b/appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionException.java
new file mode 100644 (file)
index 0000000..804fe6a
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+public class EncryptionException extends Exception {
+
+    public EncryptionException(String message) {
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionTool.java b/appc-core/appc-common-bundle/java/org/onap/appc/encryption/EncryptionTool.java
new file mode 100644 (file)
index 0000000..480b15e
--- /dev/null
@@ -0,0 +1,214 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+
+import javax.crypto.Cipher;
+
+import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64;
+import org.jasypt.util.text.BasicTextEncryptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to encapsulate the encryption and decryption support in one place and to provide a utility to
+ * encrypt and decrypt data.
+ */
+public class EncryptionTool {
+
+    /**
+     * This lock object is used ONLY if the singleton has not been set up.
+     */
+    private static final Object lock = new Object();
+
+    /**
+     * The salt is used to initialize the PBE (password Based Encrpytion) algorithm.
+     */
+    private static final byte[] DEFAULT_SALT = {
+        (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99
+    };
+
+    /**
+     * The prefix we insert onto any data we encrypt so that we can tell if it is encrpyted later and therefore decrypt
+     * it
+     */
+    @SuppressWarnings("nls")
+    public static final String ENCRYPTED_VALUE_PREFIX = "enc:";
+
+    /**
+     * The instance of the encryption utility object
+     */
+    private static EncryptionTool instance = null;
+
+    /**
+     * The iteration count used to initialize the PBE algorithm and to generate the key spec
+     */
+    private static final int ITERATION_COUNT = 20;
+
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(EncryptionTool.class);
+
+    /**
+     * The secret passphrase (PBE) that we use to perform encryption and decryption. The algorithm we are using is a
+     * symmetrical cipher.
+     */
+    private static char[] secret = {
+        'C', '_', 'z', 'l', '!', 'K', '!', '4', '?', 'O', 'z', 'E', 'K', 'E', '>', 'U', 'R', '/', '%', 'Y', '\\', 'f',
+        'b', '"', 'e', 'n', '{', '"', 'l', 'U', 'F', '+', 'E', '\'', 'R', 'T', 'p', '1', 'V', '4', 'l', 'a', '9', 'w',
+        'v', '5', 'Z', '#', 'i', 'V', '"', 'd', 'l', '!', 'L', 'M', 'g', 'L', 'Q', '{', 'v', 'v', 'K', 'V'
+    };
+
+    /**
+     * The algorithm to encrypt and decrpyt data is "Password (or passphrase) Based Encryption with Message Digest #5
+     * and the Data Encryption Standard", i.e., PBEWithMD5AndDES.
+     */
+    @SuppressWarnings("nls")
+    private static final String SECURITY_ALGORITHM = "PBEWITHMD5AND256BITAES";// "PBEWithMD5AndDES";
+
+    /**
+     * The decryption cipher object
+     */
+    private Cipher decryptCipher = null;
+
+    /**
+     * The encryption cipher object
+     */
+    private Cipher encryptCipher = null;
+
+    private BasicTextEncryptor encryptor;
+
+    /**
+     * Get an instance of the EncryptionTool
+     *
+     * @return The encryption tool to be used
+     */
+    public static final EncryptionTool getInstance() {
+        if (instance == null) {
+            synchronized (lock) {
+                if (instance == null) {
+                    instance = new EncryptionTool();
+                }
+            }
+        }
+        return instance;
+    }
+
+    /**
+     * Create the EncryptionTool instance
+     */
+    @SuppressWarnings("nls")
+    private EncryptionTool() {
+        String out = "Found the following security algorithms:";
+        for (Provider p : Security.getProviders()) {
+            for (Service s : p.getServices()) {
+                String algo = s.getAlgorithm();
+                out +=
+                    String.format("%n  -Algorithm [ %s ] in provider [ %s ] and service [ %s ]", algo, p.getName(),
+                        s.getClassName());
+            }
+        }
+        LOG.debug(out);
+    }
+
+    /**
+     * Decrypt the provided encrypted text
+     *
+     * @param cipherText
+     *            THe cipher text to be decrypted. If the ciphertext is not encrypted, then it is returned as is.
+     * @return the clear test of the (possibly) encrypted value. The original value if the string is not encrypted.
+     */
+    @SuppressWarnings("nls")
+    public synchronized String decrypt(String cipherText) {
+        if (isEncrypted(cipherText)) {
+            String encValue = cipherText.substring(ENCRYPTED_VALUE_PREFIX.length());
+            byte[] plainByte = Base64.decodeBase64(encValue.getBytes());
+            byte[] decryptByte = xorWithSecret(plainByte);
+            return new String(decryptByte);
+        } else {
+            return cipherText;
+        }
+
+    }
+
+    /**
+     * Encrypt the provided clear text
+     *
+     * @param clearText
+     *            The clear text to be encrypted
+     * @return the encrypted text. If the clear text is empty (null or zero length), then an empty string is returned.
+     *         If the clear text is already encrypted, it is not encrypted again and is returned as is. Otherwise, the
+     *         clear text is encrypted and returned.
+     */
+    @SuppressWarnings("nls")
+    public synchronized String encrypt(String clearText) {
+        if (clearText != null) {
+            byte[] encByte = xorWithSecret(clearText.getBytes());
+            String encryptedValue = new String(Base64.encodeBase64(encByte));
+            return ENCRYPTED_VALUE_PREFIX + encryptedValue;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Is a value encrypted? A value is considered to be encrypted if it begins with the
+     * {@linkplain #ENCRYPTED_VALUE_PREFIX encrypted value prefix}.
+     *
+     * @param value
+     *            the value to check.
+     * @return true/false;
+     */
+    private static boolean isEncrypted(final String value) {
+        return value != null && value.startsWith(ENCRYPTED_VALUE_PREFIX);
+    }
+
+    /**
+     * XORs the input byte array with the secret key, padding 0x0 to the end of the secret key if the input is longer
+     * and returns a byte array the same size as input
+     *
+     * @param inp
+     *            The byte array to be XORed with secret
+     * @return A byte array the same size as inp or null if input is null.
+     */
+    private byte[] xorWithSecret(byte[] inp) {
+        if (inp == null) {
+            return null;
+        }
+
+        byte[] secretBytes = new String(secret).getBytes();
+        int size = inp.length;
+
+        byte[] out = new byte[size];
+        for (int i = 0; i < size; i++) {
+            out[i] = (byte) ((inp[i]) ^ (secretBytes[i % secretBytes.length]));
+        }
+        return out;
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/encryption/HexHelper.java b/appc-core/appc-common-bundle/java/org/onap/appc/encryption/HexHelper.java
new file mode 100644 (file)
index 0000000..9e975f8
--- /dev/null
@@ -0,0 +1,162 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * HexHelper utility used for encryption/decryption
+ */
+public final class HexHelper {
+
+    @SuppressWarnings({
+        "javadoc", "nls"
+    })
+    public static final String CM_PATH = "@(#) [viewpath]/[item]";
+
+    @SuppressWarnings({
+        "nls", "javadoc"
+    })
+    public static final String CM_PROJECT = "@(#) [environment] [baseline]";
+
+    @SuppressWarnings({
+        "javadoc", "nls"
+    })
+    public static final String CM_VERSION = "@(#) [version] [crtime]";
+
+    private static final char[] HEX_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+        'E', 'F'};
+
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(HexHelper.class);
+
+    private static Map<Character, Integer> textToHex;
+
+    static {
+        textToHex = new HashMap<>();
+        textToHex.put('0', 0);
+        textToHex.put('1', 1);
+        textToHex.put('2', 2);
+        textToHex.put('3', 3);
+        textToHex.put('4', 4);
+        textToHex.put('5', 5);
+        textToHex.put('6', 6);
+        textToHex.put('7', 7);
+        textToHex.put('8', 8);
+        textToHex.put('9', 9);
+        textToHex.put('A', 10);
+        textToHex.put('B', 11);
+        textToHex.put('C', 12);
+        textToHex.put('D', 13);
+        textToHex.put('E', 14);
+        textToHex.put('F', 15);
+    }
+
+    /**
+     * Default private constructor prevents instantiation
+     */
+    private HexHelper() {
+        // no-op
+    }
+
+    /**
+     * Converts an array of bytes to the equivalent string representation using hexadecimal notation
+     *
+     * @param bytes The bytes to be converted to a hexadecimal string
+     * @return The string representation
+     */
+    public static String convertBytesToHex(byte[] bytes) throws EncryptionException{
+
+        if (bytes == null)
+            throw new EncryptionException("Given byte array is null");
+
+        StringBuilder builder = new StringBuilder(bytes.length * 2);
+        for (byte aByte : bytes) {
+            char tempChar;
+            // Get the first 4 bits (high) Do bitwise logical AND to get rid of
+            // low nibble. Shift results to right by 4 and get char
+            // representation
+            tempChar = HEX_TABLE[(aByte & 0xf0) >>> 4];
+            builder.append(tempChar);
+
+            // Get the last 4 bits (low) Do bitwise logical AND to get rid of
+            // high nibble. Get char representation
+            tempChar = HEX_TABLE[aByte & 0x0f];
+            builder.append(tempChar);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Converts a hexadecimal string representation of a binary value to an array of bytes
+     *
+     * @param hexValue The hex representation string to be converted
+     * @return The array of bytes that contains the binary value
+     */
+    @SuppressWarnings("nls")
+    public static byte[] convertHexToBytes(String hexValue) throws EncryptionException {
+
+        if (hexValue ==null)
+            throw new EncryptionException("Given hex value is null");
+
+        byte[] bytes;
+        byte high;
+        byte low;
+        char hexChar;
+
+        StringBuilder builder = new StringBuilder(hexValue.toUpperCase());
+        if (builder.length() % 2 != 0) {
+            LOG.warn("Invalid HEX value length. The length of the value has to be a multiple of 2."
+                + " Prepending '0' value.");
+            builder.insert(0, '0');
+        }
+        int hexLength = builder.length();
+        int byteLength = hexLength / 2;
+
+        bytes = new byte[byteLength];
+        try {
+            for (int index = 0; index < hexLength; index += 2) {
+                hexChar = builder.charAt(index);
+                high = textToHex.get(hexChar).byteValue();
+                high = (byte) (high << 4);
+                hexChar = builder.charAt(index + 1);
+                low = textToHex.get(hexChar).byteValue();
+                high = (byte) (high | low);
+                bytes[index / 2] = high;
+            }
+        }
+        catch (NullPointerException e){
+            LOG.error("Given string contains not hexadecimal values", e);
+            throw new EncryptionException("Given string contains not hexadecimal values");
+        }
+
+        return bytes;
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/APPCException.java b/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/APPCException.java
new file mode 100644 (file)
index 0000000..90dfa67
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+/**
+ * This is a base class for all APPC defined exceptions.
+ */
+
+public class APPCException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with null as its detail message. The cause is not initialized, and may subsequently be
+     * initialized by a call to initCause.
+     */
+    public APPCException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+     * be initialized by a call to initCause.
+     * 
+     * @param message
+     *            the detail message. The detail message is saved for later retrieval by the getMessage() method.
+     */
+    public APPCException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail message of (cause==null ? null :
+     * cause.toString()) (which typically contains the class and detail message of cause). This constructor is useful
+     * for exceptions that are little more than wrappers for other throwables (for example,
+     * java.security.PrivilegedActionException).
+     * 
+     * @param cause
+     *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+     *            and indicates that the cause is nonexistent or unknown.)
+     */
+    public APPCException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * 
+     Constructs a new exception with the specified detail message and cause.
+     * <p>
+     * Note that the detail message associated with cause is not automatically incorporated in this exception's detail
+     * message.
+     * </p>
+     * 
+     * @param message
+     *            the detail message (which is saved for later retrieval by the getMessage() method).
+     * @param cause
+     *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+     *            and indicates that the cause is nonexistent or unknown.)
+     */
+    public APPCException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * 
+     Constructs a new exception with the specified detail message, cause, suppression enabled or disabled, and
+     * writable stack trace enabled or disabled.
+     * 
+     * @param message
+     *            the detail message.
+     * @param cause
+     *            the cause. (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression
+     *            whether or not suppression is enabled or disabled
+     * @param writableStackTrace
+     *            whether or not the stack trace should be writable
+     */
+    public APPCException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidInputException.java b/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidInputException.java
new file mode 100644 (file)
index 0000000..32a6cde
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+public class InvalidInputException extends Exception {
+    public InvalidInputException(String message){
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidStateException.java b/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/InvalidStateException.java
new file mode 100644 (file)
index 0000000..61a8770
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+public class InvalidStateException extends Exception {
+    public InvalidStateException(String message) {
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/UnknownProviderException.java b/appc-core/appc-common-bundle/java/org/onap/appc/exceptions/UnknownProviderException.java
new file mode 100644 (file)
index 0000000..d23c802
--- /dev/null
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+/**
+ * This exception indicates that the named provider could not be found or was unidentifiable.
+ */
+public class UnknownProviderException extends APPCException {
+
+    /**
+    *
+    */
+   private static final long serialVersionUID = 1L;
+
+   /**
+    * Constructs a new exception with null as its detail message. The cause is not initialized, and may subsequently be
+    * initialized by a call to initCause.
+    */
+   public UnknownProviderException() {
+   }
+
+   /**
+    * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+    * be initialized by a call to initCause.
+    * 
+    * @param message
+    *            the detail message. The detail message is saved for later retrieval by the getMessage() method.
+    */
+   public UnknownProviderException(String message) {
+       super(message);
+   }
+
+   /**
+    * Constructs a new exception with the specified cause and a detail message of (cause==null ? null :
+    * cause.toString()) (which typically contains the class and detail message of cause). This constructor is useful
+    * for exceptions that are little more than wrappers for other throwables (for example,
+    * java.security.PrivilegedActionException).
+    * 
+    * @param cause
+    *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+    *            and indicates that the cause is nonexistent or unknown.)
+    */
+   public UnknownProviderException(Throwable cause) {
+       super(cause);
+   }
+
+   /**
+    * 
+    Constructs a new exception with the specified detail message and cause.
+    * <p>
+    * Note that the detail message associated with cause is not automatically incorporated in this exception's detail
+    * message.
+    * </p>
+    * 
+    * @param message
+    *            the detail message (which is saved for later retrieval by the getMessage() method).
+    * @param cause
+    *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+    *            and indicates that the cause is nonexistent or unknown.)
+    */
+   public UnknownProviderException(String message, Throwable cause) {
+       super(message, cause);
+   }
+
+   /**
+    * 
+    Constructs a new exception with the specified detail message, cause, suppression enabled or disabled, and
+    * writable stack trace enabled or disabled.
+    * 
+    * @param message
+    *            the detail message.
+    * @param cause
+    *            the cause. (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+    * @param enableSuppression
+    *            whether or not suppression is enabled or disabled
+    * @param writableStackTrace
+    *            whether or not the stack trace should be writable
+    */
+   public UnknownProviderException(String message,
+                                   Throwable cause,
+                                   boolean enableSuppression,
+                                   boolean writableStackTrace) {
+       super(message, cause, enableSuppression, writableStackTrace);
+   }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/i18n/Msg.java b/appc-core/appc-common-bundle/java/org/onap/appc/i18n/Msg.java
new file mode 100644 (file)
index 0000000..d60e259
--- /dev/null
@@ -0,0 +1,842 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.i18n;
+
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+import com.att.eelf.i18n.EELFResourceManager;
+
+/**
+ * The messages issued by APPC components.
+ * <p>
+ * This message definition is shared by all APPC components.
+ * </p>
+ *
+ */
+@SuppressWarnings("nls")
+public enum Msg implements EELFResolvableErrorEnum {
+
+    /**
+     * ECOMP Application Controller (APP-C) initialization started at {0}
+     */
+    CONFIGURATION_STARTED,
+
+    /**
+     * Prior configuration has been cleared
+     */
+    CONFIGURATION_CLEARED,
+
+    /**
+     * Loading configuration properties from file "{0}"
+     */
+    LOADING_CONFIGURATION_OVERRIDES,
+
+    /**
+     * Configuration defaults loaded from resource file "{0}"
+     */
+    LOADING_DEFAULTS,
+
+    /**
+     * No default property resource "{0}" was found!
+     */
+    NO_DEFAULTS_FOUND,
+
+    /**
+     * Property "{0}" ="{1}"
+     */
+    PROPERTY_VALUE,
+
+    /**
+     * No configuration file named [{0}] was found on the configuration search path [{1}]. \ If a configuration file
+     * should have been loaded, check the file name and search path specified. CDP will proceed using the \ default
+     * values and command-line overrides (if any).
+     */
+    NO_OVERRIDE_PROPERTY_FILE_LOADED,
+
+    /**
+     * Searching path "{0}" for configuration settings "{1}"
+     */
+    SEARCHING_CONFIGURATION_OVERRIDES,
+
+    /**
+     * Loading application-specific override properties
+     */
+    LOADING_APPLICATION_OVERRIDES,
+
+    /**
+     * No application-specific override properties were provided!
+     */
+    NO_APPLICATION_OVERRIDES,
+
+    /**
+     * Merging system properties into configuration
+     */
+    MERGING_SYSTEM_PROPERTIES,
+
+    /**
+     * Setting property "{0}={1}" in system properties
+     */
+    SETTING_SPECIAL_PROPERTY,
+
+    /**
+     * Loading resource bundle "{0}"
+     */
+    LOADING_RESOURCE_BUNDLE,
+
+    /**
+     * Logging has already been initialized, check the container logging definitions to ensure they represent your
+     * desired logging configuration.
+     */
+    LOGGING_ALREADY_INITIALIZED,
+
+    /**
+     * Searching path "{0}" for log configuration file "{1}"
+     */
+    SEARCHING_LOG_CONFIGURATION,
+
+    /**
+     * Loading default logging configuration from system resource file "{0}"
+     */
+    LOADING_DEFAULT_LOG_CONFIGURATION,
+
+    /**
+     * No log configuration could be found or defaulted!
+     */
+    NO_LOG_CONFIGURATION,
+
+    /**
+     * An unsupported logging framework is bound to SLF4J. Only Logback or Log4J are supported.
+     */
+    UNSUPPORTED_LOGGING_FRAMEWORK,
+
+    /**
+     * Loading logging configuration from file "{0}"
+     */
+    LOADING_LOG_CONFIGURATION,
+
+    /**
+     * Provider {0} cannot be found or cannot be resolved to a valid provider.
+     */
+    UNKNOWN_PROVIDER,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" and region "{3}" did not change state within the alloted time.
+     * Current state is "{4}" and the desired state(s) are "{5}"
+     */
+    SERVER_STATE_CHANGE_TIMEOUT,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" has a state of deleted and cannot be {3}.
+     */
+    SERVER_DELETED,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" has an unknown state of "{3}".
+     */
+    UNKNOWN_SERVER_STATE,
+
+    /**
+     * {0} component {1} is being initialized...
+     */
+    COMPONENT_INITIALIZING,
+
+    /**
+     * {0} component {1} has completed initialization
+     */
+    COMPONENT_INITIALIZED,
+
+    /**
+     * {0} component {1} is terminating...
+     */
+    COMPONENT_TERMINATING,
+
+    /**
+     * {0} component {1} has terminated
+     */
+    COMPONENT_TERMINATED,
+
+    /**
+     * Operation {0} is not supported or implemented at this time.
+     */
+    IAAS_ADAPTER_UNSUPPORTED_OPERATION,
+
+    /**
+     * Operation {0} called. Input document:\n{1}
+     */
+    IAAS_ADAPTER_RPC_CALLED,
+
+    /**
+     * Unable to locate the {0} service in the OSGi container
+     */
+    NO_SERVICE_FOUND,
+
+    /**
+     * Dump of context parameters for module {0}, RPC {1}, and version {2}
+     */
+    CONTEXT_PARAMETERS_DISPLAY,
+
+    /**
+     * Response properties from execution of module '{0}', RPC '{1}', and version '{2}' are:
+     */
+    RESPONSE_PARAMETERS_DISPLAY,
+
+    /**
+     * Service {0}:{1} was provided a null (empty) or invalid argument, '{2}' = '{3}'
+     */
+    NULL_OR_INVALID_ARGUMENT,
+
+    /**
+     * Service {0}:{1} is processing service '{2}' with request id '{3}'
+     */
+    PROCESSING_REQUEST,
+
+    /**
+     * Service {0}:{1} received request for service '{2}' but that service is invalid or unknown.
+     */
+    INVALID_SERVICE_REQUEST,
+
+    /**
+     * {0} registering service {1} using class {2}
+     */
+    REGISTERING_SERVICE,
+
+    /**
+     * {0} unregistering service {1}
+     */
+    UNREGISTERING_SERVICE,
+
+    /**
+     * {0} IAAS Adapter initializing provider {1} as {2}
+     */
+    LOADING_PROVIDER_DEFINITIONS,
+
+    /**
+     * {0} IAAS Adapter restart of server requested
+     */
+    RESTARTING_SERVER,
+
+    /**
+     * {0} IAAS Adapter rebuild of server requested
+     */
+    REBUILDING_SERVER,
+
+    /**
+     * {0} IAAS Adapter migrate of server requested
+     */
+    MIGRATING_SERVER,
+
+    /**
+     * {0} IAAS Adapter evacuate of server requested
+     */
+    EVACUATING_SERVER,
+
+    /**
+     * {0} IAAS Adapter create snapshot of server requested
+     */
+    SNAPSHOTING_SERVER,
+
+    /**
+     * {0} IAAS Adapter look for server requested
+     */
+    LOOKING_SERVER_UP,
+
+    /**
+     * {0} IAAS Adapter cannot perform requested service, VM url '{1}' is invalid
+     */
+    INVALID_SELF_LINK_URL,
+
+    /**
+     * Located server '{0}' on tenant '{1}' and in state '{2}'
+     */
+    SERVER_FOUND,
+
+    /**
+     * No server found in provider with self-link URL [{0}]
+     */
+    SERVER_NOT_FOUND,
+
+    /**
+     * Exception {0} was caught attempting {1} of server [{2}] on tenant [{3}]
+     */
+    SERVER_OPERATION_EXCEPTION,
+
+    /**
+     * One or more properties for [{0}] are missing, null, or empty. They are:
+     */
+    MISSING_REQUIRED_PROPERTIES,
+
+    /**
+     * The server [{0}] (id={1}) in tenant {2} is in error state, {3} is not allowed
+     */
+    SERVER_ERROR_STATE,
+
+    /**
+     * The image {0} could not be located for {1}
+     */
+    IMAGE_NOT_FOUND,
+
+    /**
+     * Time out waiting for {0} with name {1} (and id {2}) to reach one of {3} states, current state is {4}
+     */
+    STATE_CHANGE_TIMEOUT,
+
+    /**
+     * Exception {0} waiting for {1} with name {2} (and id {3}) to reach one of {4} states, current state is {5}
+     * cause={6}
+     */
+    STATE_CHANGE_EXCEPTION,
+
+    /**
+     * Server {0} is being stopped...
+     */
+    STOP_SERVER,
+
+    /**
+     * Server {0} is being started...
+     */
+    START_SERVER,
+
+    /**
+     * Server {0} is being resumed...
+     */
+    RESUME_SERVER,
+
+    /**
+     * Server {0} is being unpaused...
+     */
+    UNPAUSE_SERVER,
+
+    /**
+     * Server {0} is being rebuilt...
+     */
+    REBUILD_SERVER,
+
+    /**
+     * Connection to provider {0} at identity {1} using tenant name {2} (id {3}) failed, reason={4}, retrying in {5}
+     * seconds, attempt {6} of {7}.
+     */
+    CONNECTION_FAILED_RETRY,
+
+    /**
+     * Connection to provider {0} at service {1} failed after all retry attempts.
+     */
+    CONNECTION_FAILED,
+
+    /**
+     * {0} IAAS Adapter stop server requested
+     */
+    STOPPING_SERVER,
+
+    /**
+     * {0} IAAS Adapter start server requested
+     */
+    STARTING_SERVER,
+
+    /**
+     * Server {0} (id {1}) failed to rebuild, reason {2}
+     */
+    REBUILD_SERVER_FAILED,
+
+    /**
+     * Application {0} graph {1} response did not set the {2} parameter. This parameter is required for synchronization
+     * with the controller. Absence of this parameter is assumed to be a failure. Please correct the DG.
+     */
+    PARAMETER_IS_MISSING,
+
+    /**
+     * Application {0} graph {1} did not set parameter {2} to a valid numeric value ({3}). Please correct the DG.
+     */
+    PARAMETER_NOT_NUMERIC,
+
+    /**
+     * Application {0} graph {1} completed with failure: error code = {2}, message = {3}
+     */
+    DG_FAILED_RESPONSE,
+
+    /**
+     * Application {0} received exception {1} attempting to call graph {2}, exception message = {3}
+     */
+    EXCEPTION_CALLING_DG,
+
+    /**
+     * Application {0} was unable to locate graph {1}
+     */
+    GRAPH_NOT_FOUND,
+
+    /**
+     * Application {0} graph {1} responded with {3} properties
+     */
+    DEBUG_GRAPH_RESPONSE_HEADER,
+
+    /**
+     * {0}:{1} - {2} = {3}
+     */
+    DEBUG_GRAPH_RESPONSE_DETAIL,
+
+    /**
+     * Application {0} request {1} was supplied a property '{2}' with the value '{3}' that does not meet the required
+     * form(s):
+     */
+    INVALID_REQUIRED_PROPERTY,
+
+    /**
+     * Server {0} (id {1}) failed to migrate during {2} phase, reason {3}
+     */
+    MIGRATE_SERVER_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to evacuate, reason {2}
+     */
+    EVACUATE_SERVER_FAILED,
+    
+    /**
+     * Server {0} evacuate from host {1} to host {2} failed during the rebuild on host {2}, reason {3}
+     */
+    EVACUATE_SERVER_REBUILD_FAILED,
+
+    /**
+     * APP-C instance is too busy
+     */
+    APPC_TOO_BUSY,
+
+    /**
+     * Concurrent access to server "{0}"
+     */
+    VF_SERVER_BUSY,
+
+    /**
+     * Server "{0}" does not support command "{1}" in the current state "{2}"
+     */
+    VF_ILLEGAL_COMMAND,
+
+    /**
+     * Server "{0}" cannot handle command "{1}" because of its doubtful state
+     */
+    VF_UNDEFINED_STATE,
+
+    /**
+     * No resource found with ID "{0}" in A&AI system
+     */
+    APPC_NO_RESOURCE_FOUND,
+
+    /**
+     * The request "{0}" for server "{1}" has exceeded its TTL limit of "{3}" seconds
+     */
+    APPC_EXPIRED_REQUEST,
+
+    /**
+     * Workflow for vnfType = "{0}" and command = "{1}" not found.
+     */
+    APPC_WORKFLOW_NOT_FOUND,
+
+    /**
+     * Null vnfId and command provided
+     */
+    APPC_INVALID_INPUT,
+
+    /**
+     * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' was started at '{4}' and ended at '{5}'
+     * with status code '{6}'
+     */
+    APPC_AUDIT_MSG,
+
+    /**
+     * APP-C is unable to communicate with A&AI
+     */
+    AAI_CONNECTION_FAILED,
+
+    /**
+     * APP-C is unable to update COMPONENT_ID {0} to {1} for reason {2}
+     */
+    AAI_UPDATE_FAILED,
+
+    /**
+     * APP-C is unable to retrieve VF/VFC {0} data for Transaction ID{1}as a result of A&AI communication failure or its
+     * internal error.
+     */
+    AAI_GET_DATA_FAILED,
+
+    /**
+     * A&AI at identity {0} using VNF_ID {1} failed, reason={2}, retrying in {3} seconds, attempt {4} of {5}
+     */
+    AAI_CONNECTION_FAILED_RETRY,
+
+    /**
+     * APP-C is unable to delete COMPONENT_ID {0} for reason {1}
+     */
+    AAI_DELETE_FAILED,
+
+    /**
+     * APP-C is unable to query AAI for VNF_ID {0}
+     */
+    AAI_QUERY_FAILED,
+
+    /**
+     * VNF {0} is configured
+     */
+    VNF_CONFIGURED,
+
+    /**
+     * VNF {0} is being configured
+     */
+    VNF_CONFIGURATION_STARTED,
+
+    /**
+     * VNF {0} configuration failed for reason {1}
+     */
+    VNF_CONFIGURATION_FAILED,
+
+    /**
+     * VNF {0} is being tested
+     */
+    VNF_TEST_STARTED,
+
+    /**
+     * VNF {0} was tested
+     */
+    VNF_TESTED,
+
+    /**
+     * VNF {0} test failed for reason {1}
+     */
+    VNF_TEST_FAILED,
+
+    /**
+     * VNF {0} test failed for reason {1}
+     */
+    VNF_NOT_FOUND,
+
+    /**
+     * VNF {0} Healthcheck operation failed for reason {1}
+     */
+    VNF_HEALTHCECK_FAILED,
+
+    /**
+     * VM {0} Healthcheck operation failed for reason {1}
+     */
+    VM_HEALTHCECK_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to stop during {2} phase, reason {3}
+     */
+    STOP_SERVER_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to terminate during {2} phase, reason {3}
+     */
+    TERMINATE_SERVER_FAILED,
+
+    /**
+     * {0} IAAS Adapter terminate server requested
+     */
+    TERMINATING_SERVER,
+
+    /**
+     * Server {0} is being terminated...
+     */
+    TERMINATE_SERVER,
+
+    /**
+     * Migrate {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    MIGRATE_COMPLETE,
+
+    /**
+     * Restart {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    RESTART_COMPLETE,
+
+    /**
+     * Rebuild {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    REBUILD_COMPLETE,
+
+    /**
+     * Located stack '{0}' on tenant '{1}' and in state '{2}'
+     */
+    STACK_FOUND,
+
+    /**
+     * {0} IAAS Adapter terminate stack requested
+     */
+
+    TERMINATING_STACK,
+
+    /**
+     * stack {0} is being terminated...
+     */
+    TERMINATE_STACK,
+    /**
+     * No stack found in provider with self-link URL [{0}]
+     */
+
+    STACK_NOT_FOUND,
+
+    /**
+     * Exception {0} was caught attempting {1} of stack [{2}] on tenant [{3}]
+     */
+    STACK_OPERATION_EXCEPTION,
+
+    /**
+     * Stack {0} (id {1}) failed to terminate during {2} phase, reason {3}
+     */
+
+    TERMINATE_STACK_FAILED,
+
+    /**
+     * Exception {0} was caught attempting to close provider context for {1}.
+     */
+
+    CLOSE_CONTEXT_FAILED,
+
+    /**
+     * {0} IAAS Adapter snapshoting stack
+     */
+    SNAPSHOTING_STACK,
+
+    /**
+     * Stack {0} snapshoted, snapshot ID = [{1}].
+     */
+    STACK_SNAPSHOTED,
+
+    /**
+     * {0} IAAS Adapter restoring stack
+     */
+    RESTORING_STACK,
+
+    /**
+     * Stack {0} is restored to snapshot {1}.
+     */
+    STACK_RESTORED,
+
+    /**
+     * {0} IAAS Adapter checking server
+     */
+    CHECKING_SERVER,
+
+    /**
+     * Parameter {0} is missing in svc request of {1}.
+     */
+    MISSING_PARAMETER_IN_REQUEST,
+
+    /**
+     * Cannot establish connection to server {0} port {1} with user {2}.
+     */
+    CANNOT_ESTABLISH_CONNECTION,
+
+    /**
+     * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' on '{4}' with action '{5}'
+     * ended in {6}ms with result '{7}'
+     */
+    APPC_METRIC_MSG,
+
+    /**
+     * Parsing failied for{0}
+     */
+    INPUT_PAYLOAD_PARSING_FAILED,
+
+    /**
+     * Error occurred for due to {0}
+     */
+    APPC_EXCEPTION,
+
+    /**
+     * SSH Data Exception occurred due to {0}
+     */
+    SSH_DATA_EXCEPTION,
+
+    /**
+     * Json processing exception occurred due to {0}
+     */
+    JSON_PROCESSING_EXCEPTION,
+
+   /**
+     * Operation {0} succeed for {1}
+     */
+    SUCCESS_EVENT_MESSAGE,
+
+    /**
+     * Dependency model not found for VNF type {0} due to {1}
+     */
+    DEPENDENCY_MODEL_NOT_FOUND,
+
+    /**
+     * Invalid Dependency model for VNF Type {0} due to {1}
+     */
+    INVALID_DEPENDENCY_MODEL,
+
+    /**
+     * Failed to retrieve VNFC DG
+     */
+    FAILURE_RETRIEVE_VNFC_DG,
+
+    /**
+     * Network check for Server {0} failed for Port {1}
+     *
+     */
+    SERVER_NETWORK_ERROR,
+
+    /**
+     * Hypervisor check for Server {0} failed. Status is DOWN or UNKNOWN
+     *
+     */
+    HYPERVISOR_DOWN_ERROR,
+    
+    /**
+     * Unable to determine Hypervisor status for Server {0}. failed.
+     *
+     */
+    HYPERVISOR_STATUS_UKNOWN,
+
+    /**
+     * Hypervisor Network check for Server {0} failed. Not reachable by APPC
+     *
+     */
+    HYPERVISOR_NETWORK_ERROR,
+
+    /**
+     * Restart application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_RESTART_FAILED,
+
+    /**
+     * Start application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_START_FAILED,
+
+    /**
+     * Start application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_STOP_FAILED,
+
+    /**
+     * Application on server {0} is being restarted...
+     */
+    RESTART_APPLICATION,
+
+    /**
+     * Application on server {0} is being started...
+     */
+    START_APPLICATION,
+
+    /**
+     * Application on server {0} is being started...
+     */
+    STOP_APPLICATION,
+
+    /**
+     * APPC LCM operations are disabled
+     */
+    LCM_OPERATIONS_DISABLED,
+
+    /**
+     * Application {0} received exception {1} while attempting to execute oam operation {2}, exception message = {3}|\
+     */
+    OAM_OPERATION_EXCEPTION,
+
+    /**
+     *   Application {0} is {1}
+     */
+    OAM_OPERATION_ENTERING_MAINTENANCE_MODE,
+
+    /**
+     * Application {0} is in {1}
+     */
+    OAM_OPERATION_MAINTENANCE_MODE,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STARTING,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STARTED,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STOPPING,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STOPPED,
+    /**
+     * A {1} API is not allowed when {0} is in the {2} state
+     */
+    INVALID_STATE_TRANSITION,
+
+    /**
+     * Application {0} was unable to find the Request Handler service
+     */
+    REQUEST_HANDLER_UNAVAILABLE,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_RESTARTING,
+
+    /**
+     * Application {0} is {1} for restart
+     */
+    OAM_OPERATION_RESTARTED,
+
+    /**
+     * {0}
+     */
+    OAM_OPERATION_INVALID_INPUT,
+
+    ATTACHINGVOLUME_SERVER,
+
+    DETTACHINGVOLUME_SERVER,
+
+    /**
+     * Unsupported identity service version, unable to retrieve ServiceCatalog
+     * for identity service {0}
+     */
+    IAAS_UNSUPPORTED_IDENTITY_SERVICE,
+
+    /**
+     * Sftp data transfer failed on connection to host {0} with user {1} for {2} operation, reason : {3}
+     */
+    SFTP_TRANSFER_FAILED,
+
+    /**
+     * Ssh session with host {0} has timed out during command {1} execution
+     */
+    SSH_CONNECTION_TIMEOUT,
+
+    /**
+     * Could not configure existing ssh session, reason: {0}
+     */
+    SSH_SESSION_CONFIG_ERROR
+    ;
+    /*
+     * Static initializer to ensure the resource bundles for this class are loaded...
+     */
+    static {
+        EELFResourceManager.loadMessageBundle("org/onap/appc/i18n/MessageResources");
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingConstants.java b/appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingConstants.java
new file mode 100644 (file)
index 0000000..4178f6b
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.logging;
+
+/**
+ * Constant definition of logging
+ */
+public class LoggingConstants {
+    private LoggingConstants() {
+        throw new IllegalAccessError("LoggingConstants");
+    }
+
+    /**
+     * Constants of MDC property keys
+     */
+    public static class MDCKeys {
+        private MDCKeys() {
+            throw new IllegalAccessError("MDCKeys");
+        }
+
+        public static final String ERROR_CODE = "ErrorCode";
+        public static final String ERROR_DESCRIPTION = "ErrorDescription";
+        public static final String STATUS_CODE = "StatusCode";
+        public static final String RESPONSE_CODE = "ResponseCode";
+        public static final String RESPONSE_DESCRIPTION = "ResponseDescription";
+        public static final String TARGET_ENTITY = "TargetEntity";
+        public static final String TARGET_SERVICE_NAME = "TargetServiceName";
+        public static final String PARTNER_NAME = "PartnerName";
+        public static final String SERVER_NAME = "ServerName";
+        public static final String BEGIN_TIMESTAMP = "BeginTimestamp";
+        public static final String END_TIMESTAMP = "EndTimestamp";
+        public static final String ELAPSED_TIME = "ElapsedTime";
+        public static final String CLASS_NAME = "ClassName";
+        public static final String TARGET_VIRTUAL_ENTITY = "TargetVirtualEntity";
+    }
+
+    /**
+     * Constants of status code values
+     */
+    public static class StatusCodes {
+        private StatusCodes() {
+            throw new IllegalAccessError("StatusCodes");
+        }
+        public static final String COMPLETE = "COMPLETE";
+        public static final String ERROR = "ERROR";
+    }
+
+    /**
+     * Constants of APPC target names
+     */
+    public static class TargetNames {
+        private TargetNames() {
+            throw new IllegalAccessError("TargetNames");
+        }
+        public static final String APPC = "APPC";
+        public static final String AAI = "A&AI";
+        public static final String DB = "DataBase";
+        public static final String APPC_PROVIDER = "APPC Provider";
+        public static final String APPC_OAM_PROVIDER = "APPC OAM Provider";
+        public static final String STATE_MACHINE = "StateMachine";
+        public static final String WORKFLOW_MANAGER = "WorkflowManager";
+        public static final String REQUEST_VALIDATOR = "RequestValidator";
+        public static final String LOCK_MANAGER = "LockManager";
+        public static final String REQUEST_HANDLER = "RequestHandler";
+    }
+
+    /**
+     * Constants of targeted service names
+     */
+    public static class TargetServiceNames {
+        private TargetServiceNames() {
+            throw new IllegalAccessError("TargetServiceNames");
+        }
+
+        /**
+         * Constants of AAI service names
+         */
+        public static class AAIServiceNames {
+            private AAIServiceNames() {
+                throw new IllegalAccessError("AAIServiceNames");
+            }
+            public static final String QUERY = "query";
+            public static final String GET_VNF_DATA = "getVnfData";
+        }
+
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingUtils.java b/appc-core/appc-common-bundle/java/org/onap/appc/logging/LoggingUtils.java
new file mode 100644 (file)
index 0000000..cfb98da
--- /dev/null
@@ -0,0 +1,235 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.logging;
+
+import org.onap.appc.i18n.Msg;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+import com.att.eelf.i18n.EELFResourceManager;
+import org.slf4j.MDC;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Logging utilities
+ */
+public class LoggingUtils {
+
+    private static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+    private static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+    private static final EELFLogger metricLogger = EELFManager.getInstance().getMetricsLogger();
+
+    private LoggingUtils() {
+        throw new IllegalAccessError("LoggingUtils");
+    }
+
+    public static void logErrorMessage(String errorCode, String errorDescription,
+            String targetEntity, String targetServiceName, String additionalMessage,
+            String className) {
+        logError(errorCode, errorDescription, targetEntity, targetServiceName, additionalMessage,
+                className);
+    }
+
+    public static void logErrorMessage(String targetEntity, String targetServiceName,
+            String additionalMessage, String className) {
+        logError("", "", targetEntity, targetServiceName, additionalMessage, className);
+    }
+
+    public static void logErrorMessage(String targetServiceName, String additionalMessage,
+            String className) {
+        logError("", "", LoggingConstants.TargetNames.APPC, targetServiceName, additionalMessage,
+                className);
+    }
+
+    private static void logError(String errorCode, String errorDescription, String targetEntity,
+            String targetServiceName, String additionalMessage, String className) {
+        populateErrorLogContext(errorCode, errorDescription, targetEntity, targetServiceName,
+                className);
+        errorLogger.error(additionalMessage == null ? "" : additionalMessage);
+        cleanErrorLogContext();
+    }
+
+    public static void logAuditMessage(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.info(EELFResourceManager.format(Msg.APPC_AUDIT_MSG, MDC.get(MDC_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID),
+                MDC.get(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP),
+                MDC.get(LoggingConstants.MDCKeys.END_TIMESTAMP),
+                MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)));
+        cleanAuditErrorContext();
+    }
+
+    public static void auditInfo(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className, EELFResolvableErrorEnum resourceId,
+            String... arguments) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.info(resourceId, arguments);
+        cleanAuditErrorContext();
+    }
+
+    public static void auditWarn(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className, EELFResolvableErrorEnum resourceId,
+            String... arguments) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.warn(resourceId, arguments);
+        cleanAuditErrorContext();
+    }
+
+    public static void logMetricsMessage(Instant beginTimeStamp, Instant endTimeStamp,
+            String targetEntity, String targetServiceName, String statusCode, String responseCode,
+            String responseDescription, String className) {
+        populateMetricLogContext(beginTimeStamp, endTimeStamp, targetEntity, targetServiceName,
+                statusCode, responseCode, responseDescription, className);
+        metricLogger.info(EELFResourceManager.format(Msg.APPC_METRIC_MSG, MDC.get(MDC_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.ELAPSED_TIME),
+                MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)));
+        cleanMetricContext();
+    }
+
+    private static void populateAuditLogContext(Instant beginTimeStamp, Instant endTimeStamp,
+            String code, String responseDescription, String className) {
+        populateTimeContext(beginTimeStamp, endTimeStamp);
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, code);
+        MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, "100".equals(code) || "400".equals(code)
+                ? LoggingConstants.StatusCodes.COMPLETE : LoggingConstants.StatusCodes.ERROR);
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION,
+                responseDescription != null ? responseDescription : "");
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanAuditErrorContext() {
+        cleanTimeContext();
+        MDC.remove(LoggingConstants.MDCKeys.STATUS_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION);
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateErrorLogContext(String errorCode, String errorDescription,
+            String targetEntity, String targetServiceName, String className) {
+        populateErrorContext(errorCode, errorDescription);
+        populateTargetContext(targetEntity, targetServiceName != null ? targetServiceName : "");
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanErrorLogContext() {
+        cleanErrorContext();
+        cleanTargetContext();
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateMetricLogContext(Instant beginTimeStamp, Instant endTimeStamp,
+            String targetEntity, String targetServiceName, String statusCode, String responseCode,
+            String responseDescription, String className) {
+        populateTimeContext(beginTimeStamp, endTimeStamp);
+        populateTargetContext(targetEntity, targetServiceName);
+        populateResponseContext(statusCode, responseCode, responseDescription);
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanMetricContext() {
+        cleanTimeContext();
+        cleanTargetContext();
+        cleanResponseContext();
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateTargetContext(String targetEntity, String targetServiceName) {
+        MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, targetEntity != null ? targetEntity : "");
+        MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME,
+                targetServiceName != null ? targetServiceName : "");
+    }
+
+    private static void cleanTargetContext() {
+        MDC.remove(LoggingConstants.MDCKeys.TARGET_ENTITY);
+        MDC.remove(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME);
+    }
+
+    private static void populateTimeContext(Instant beginTimeStamp, Instant endTimeStamp) {
+        String beginTime = "";
+        String endTime = "";
+        String elapsedTime = "";
+
+        if (beginTimeStamp != null && endTimeStamp != null) {
+            elapsedTime = String.valueOf(ChronoUnit.MILLIS.between(beginTimeStamp, endTimeStamp));
+            beginTime = generateTimestampStr(beginTimeStamp);
+            endTime = generateTimestampStr(endTimeStamp);
+        }
+
+        MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, beginTime);
+        MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, endTime);
+        MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, elapsedTime);
+    }
+
+    private static String generateTimestampStr(Instant timeStamp) {
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
+        TimeZone tz = TimeZone.getTimeZone("UTC");
+        df.setTimeZone(tz);
+        return df.format(Date.from(timeStamp));
+    }
+
+    private static void cleanTimeContext() {
+        MDC.remove(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP);
+        MDC.remove(LoggingConstants.MDCKeys.END_TIMESTAMP);
+        MDC.remove(LoggingConstants.MDCKeys.ELAPSED_TIME);
+    }
+
+    private static void populateResponseContext(String statusCode, String responseCode,
+            String responseDescription) {
+        MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, statusCode != null ? statusCode : "");
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, responseCode);
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION,
+                responseDescription != null ? responseDescription : "");
+    }
+
+    private static void cleanResponseContext() {
+        MDC.remove(LoggingConstants.MDCKeys.STATUS_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION);
+    }
+
+    private static void populateErrorContext(String errorCode, String errorDescription) {
+        MDC.put(LoggingConstants.MDCKeys.ERROR_CODE, errorCode);
+        MDC.put(LoggingConstants.MDCKeys.ERROR_DESCRIPTION, errorDescription);
+    }
+
+    private static void cleanErrorContext() {
+        MDC.remove(LoggingConstants.MDCKeys.ERROR_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.ERROR_DESCRIPTION);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/metadata/MetadataService.java b/appc-core/appc-common-bundle/java/org/onap/appc/metadata/MetadataService.java
new file mode 100644 (file)
index 0000000..dfaa462
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata;
+
+import org.onap.appc.metadata.objects.DependencyModelIdentifier;
+
+
+public interface MetadataService {
+    String getVnfModel(DependencyModelIdentifier modelIdentifier);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java b/appc-core/appc-common-bundle/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java
new file mode 100644 (file)
index 0000000..70d2e63
--- /dev/null
@@ -0,0 +1,123 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata.impl;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.ccsdk.sli.core.dblib.DbLibService;
+
+import javax.sql.rowset.CachedRowSet;
+
+import org.onap.appc.cache.MetadataCache;
+import org.onap.appc.cache.impl.MetadataCacheFactory;
+import org.onap.appc.metadata.MetadataService;
+import org.onap.appc.metadata.objects.DependencyModelIdentifier;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+
+public class MetadataServiceImpl implements MetadataService {
+
+    private DbLibService dbLibService;
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(MetadataServiceImpl.class);
+
+    private MetadataCache<DependencyModelIdentifier, String> cache;
+
+    public MetadataServiceImpl() {
+        initialize();
+    }
+
+    private void initialize() {
+        cache = MetadataCacheFactory.getInstance().getMetadataCache();
+        // TODO initialze dbLibService
+    }
+
+    public void setDbLibService(DbLibService dbLibService) {
+        this.dbLibService = dbLibService;
+    }
+
+    void setCache(MetadataCache<DependencyModelIdentifier, String> cache) {
+        this.cache = cache;
+    }
+
+    @Override
+    public String getVnfModel(DependencyModelIdentifier modelIdentifier) {
+        logger.debug("Reading Vnf Model data from cache for vnfType : " + modelIdentifier.getVnfType()
+            + " and catalog version : " + modelIdentifier.getCatalogVersion());
+        String vnfModel = cache.getObject(modelIdentifier);
+        if (vnfModel == null || vnfModel.length() == 0) {
+            logger.debug("Vnf Model not available in cache. Reading from database.");
+            vnfModel = readVnfModel(modelIdentifier);
+            if (vnfModel != null && vnfModel.length() > 0) {
+                logger.debug("Adding retrieved Vnf Model to cache.");
+                addVnfModel(modelIdentifier, vnfModel);
+            }
+        }
+        return vnfModel;
+    }
+
+    private void addVnfModel(DependencyModelIdentifier modelIdentifier, String vnfModel) {
+        cache.putObject(modelIdentifier, vnfModel);
+    }
+
+    private String readVnfModel(DependencyModelIdentifier modelIdentifier) {
+
+        logger.debug("Reading Vnf Model data from database for RESOURCE_NAME : " + modelIdentifier.getVnfType()
+            + " and RESOURCE_VERSION : " + modelIdentifier.getCatalogVersion());
+        StringBuilder query = new StringBuilder();
+        String vnfModel = null;
+        query.append("SELECT ARTIFACT_CONTENT FROM sdnctl.ASDC_ARTIFACTS WHERE RESOURCE_NAME = ? ");
+        ArrayList<String> argList = new ArrayList<>();
+        argList.add(modelIdentifier.getVnfType());
+
+        if (modelIdentifier.getCatalogVersion() == null) {
+            query.append(" ORDER BY  SUBSTRING_INDEX(RESOURCE_VERSION, '.', 1)*1  DESC , " +
+                "SUBSTRING_INDEX(SUBSTRING_INDEX(RESOURCE_VERSION, '.', 2),'.', -1) *1 DESC , " +
+                "SUBSTRING_INDEX(RESOURCE_VERSION, '.', -1)*1 DESC ;");
+        } else {
+            query.append("AND RESOURCE_VERSION = ? ;");
+            argList.add(modelIdentifier.getCatalogVersion());
+        }
+        try {
+            final CachedRowSet data = dbLibService.getData(query.toString(), argList, "sdnctl");
+            if (data.first()) {
+                vnfModel = data.getString("ARTIFACT_CONTENT");
+                if (vnfModel == null || vnfModel.isEmpty()) {
+                    logger.error("Invalid dependency model for vnf type : " + modelIdentifier.getVnfType()
+                        + " and catalog version : " + modelIdentifier.getCatalogVersion());
+                    throw new RuntimeException("Invalid or Empty VNF Model");
+                }
+                logger.debug("Retrieved Vnf Model : " + vnfModel);
+            } else {
+                logger.warn("VNF Model not found in datastore for RESOURCE_NAME : " + modelIdentifier.getVnfType()
+                    + " AND RESOURCE_VERSION : " + modelIdentifier.getCatalogVersion());
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException("Database error occurred");
+        }
+        return vnfModel;
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java b/appc-core/appc-common-bundle/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java
new file mode 100644 (file)
index 0000000..070e200
--- /dev/null
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata.objects;
+
+/**
+ * Object of identifier for dependency model. Currently uses VNF type and catalog version
+ */
+public class DependencyModelIdentifier {
+    static final String TO_STRING_FORMAT =
+            "DependencyModelIdentifier : vnfType = %s , catalogVersion = %s";
+    static final int prime = 31;
+
+    private String vnfType;
+    private String catalogVersion;
+
+    /**
+     * Constructor
+     * 
+     * @param vnfType String of the VNF type
+     * @param catalogVersion String of the catalog version
+     */
+    public DependencyModelIdentifier(String vnfType, String catalogVersion) {
+        this.vnfType = vnfType;
+        this.catalogVersion = catalogVersion;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = result * prime + (this.vnfType == null ? 0 : this.vnfType.hashCode());
+        result = result * prime
+                + (this.catalogVersion == null ? 0 : this.catalogVersion.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof DependencyModelIdentifier)) {
+            return false;
+        }
+
+        DependencyModelIdentifier modelIdentifier = (DependencyModelIdentifier) obj;
+        if (this.vnfType == null) {
+            if (modelIdentifier.vnfType != null) {
+                return false;
+            }
+        } else if (!this.vnfType.equals(modelIdentifier.vnfType)) {
+            return false;
+        }
+
+        if (this.catalogVersion == null) {
+            if (modelIdentifier.catalogVersion != null) {
+                return false;
+            }
+        } else if (!this.catalogVersion.equals(modelIdentifier.catalogVersion)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(TO_STRING_FORMAT, vnfType, catalogVersion);
+    }
+
+    public String getVnfType() {
+        return vnfType;
+    }
+
+    public String getCatalogVersion() {
+        return catalogVersion;
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/Allocator.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/Allocator.java
new file mode 100644 (file)
index 0000000..9992e89
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+
+/**
+ * This interface is used to supply an object that will be called by the pool manager whenever a new widget must be
+ * allocated.
+ * @param <T>
+ *            The generic type that we are caching.
+ */
+
+public interface Allocator<T extends Closeable> {
+
+    /**
+     * Allocate an object of type <T> and return it to the pool
+     *
+     * @param pool
+     *            The pool that the object is to be allocated to
+     * @return An object of type T
+     */
+    T allocate(Pool<T> pool);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/CacheManagement.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/CacheManagement.java
new file mode 100644 (file)
index 0000000..d0051a8
--- /dev/null
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+public interface CacheManagement {
+
+    /**
+     * @return The object that is actually being wrapped and cached
+     */
+    Object getWrappedObject();
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/CachedElement.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/CachedElement.java
new file mode 100644 (file)
index 0000000..e9b2ffe
--- /dev/null
@@ -0,0 +1,214 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class is used as a "wrapper" for any closeable elements that are cached in a pool. It is
+ * implemented as a dynamic proxy, so that it appears to be the same class of object to the client
+ * as the interface being cached. The generic type being cached MUST be an interface.
+ * 
+ * @param <T> The generic type that we create a cached element for. This type is used to wrap
+ *        instances of this type and expose access to the {@link java.io.Closeable} interface by
+ *        using a dynamic proxy.
+ */
+
+public class CachedElement<T extends Closeable>
+        implements Closeable, InvocationHandler, CacheManagement {
+
+    /**
+     * The pool that is managing this cached element
+     */
+    private Pool<T> pool;
+
+    /**
+     * The element that we are caching in the pool
+     */
+    private T element;
+
+    /**
+     * A thread-safe atomic indicator that tells us that the wrapped element has been released to
+     * the pool already, and not to do it again.
+     */
+    private AtomicBoolean released = new AtomicBoolean(false);
+
+    /**
+     * Create a new instance of a cached element dynamic proxy for use in the pool.
+     * <p>
+     * This returns an instance of the proxy to the caller that appears to be the same interface(s)
+     * as the object being cached. The dynamic proxy then intercepts all open and close semantics
+     * and directs that element to the pool.
+     * </p>
+     * <p>
+     * If the object being proxied does not implement the {@link CacheManagement} interface, then
+     * that interface is added to the dynamic proxy being created. This interface is actually
+     * implemented by the invocation handler (this object) for the proxy and allows direct access to
+     * the wrapped object inside the proxy.
+     * </p>
+     *
+     * @param pool The pool that we are caching these elements within
+     * @param element The element actually being cached
+     * @param interfaces The interface list of interfaces the element must implement (usually one)
+     * @return The dynamic proxy
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Closeable> T newInstance(Pool<T> pool, T element,
+            Class<?>[] interfaces) {
+        ClassLoader cl = element.getClass().getClassLoader();
+        CachedElement<T> ce = new CachedElement<>(pool, element);
+        boolean found = false;
+        for (Class<?> intf : interfaces) {
+            if (intf.getName().equals(CacheManagement.class.getName())) {
+                found = true;
+                break;
+            }
+        }
+
+        int length = found ? interfaces.length : interfaces.length + 1;
+        Class<?>[] proxyInterfaces = new Class[length];
+        System.arraycopy(interfaces, 0, proxyInterfaces, 0, interfaces.length);
+
+        if (!found) {
+            proxyInterfaces[interfaces.length] = CacheManagement.class;
+        }
+
+        return (T) Proxy.newProxyInstance(cl, proxyInterfaces, ce);
+    }
+
+    /**
+     * Construct a cached element and assign it to the pool as a free element
+     *
+     * @param pool The pool that the element will be managed within
+     * @param element The element we are caching
+     */
+    @SuppressWarnings("unchecked")
+    public CachedElement(Pool<T> pool, T element) {
+        this.pool = pool;
+        this.element = element;
+
+        try {
+            pool.release((T) this);
+        } catch (PoolDrainedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * This method delegates the close call to the actual wrapped element.
+     * <p>
+     * NOTE: This is not the same method that is called by the dynamic proxy. This method is in
+     * place to satisfy the signature of the {@link java.io.Closeable} interface. If it were to be
+     * called directly, then we will delegate the close to the underlying context. However, when the
+     * cached element is called as a synamic proxy, entry is in the
+     * {@link #invoke(Object, Method, Object[])} method.
+     * </p>
+     * 
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() throws IOException {
+        element.close();
+    }
+
+    /**
+     * This method is the magic part of dynamic proxies. When the caller makes a method call based
+     * on the interface being proxied, this method is given control. This informs us of the method
+     * and arguments of the call. The object reference is that of the dynamic proxy itself, which is
+     * us.
+     * <p>
+     * Here we will check to see if the user is trying to close the "element" (the dynamic proxy
+     * acts like the wrapped element). If he is, then we don't really close it, but instead release
+     * the element that we are wrapping back to the free pool. Once this has happened, we mark the
+     * element as "closed" (from the perspective of this dynamic proxy) so that we wont try to
+     * release it again.
+     * </p>
+     * <p>
+     * If the method is the <code>equals</code> method then we assume that we are comparing the
+     * cached element in one dynamic proxy to the cached element in another. We execute the
+     * comparison between the cached elements, and not the dynamic proxies themselves. This
+     * preserves the allusion to the caller that the dynamic proxy is the object being wrapped.
+     * </p>
+     * <p>
+     * For convenience, we also implement the <code>getWrappedObject</code> method so that the
+     * dynamic proxy can be called to obtain the actual wrapped object if desired. Note, to use this
+     * method, the caller would have to invoke it through reflection.
+     * </p>
+     * <p>
+     * If the method being invoked is not one that we intercept, then we simply delegate that method
+     * onto the wrapped object.
+     * </p>
+     * 
+     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method,
+     *      java.lang.Object[])
+     */
+    @SuppressWarnings({"unchecked", "nls"})
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
+        Object result = null;
+
+        switch (method.getName()) {
+            case "close":
+                if (released.compareAndSet(false, true)) {
+                    if (!pool.isDrained()) {
+                        pool.release((T) proxy);
+                    }
+                }
+                break;
+            case "equals":
+                CacheManagement cm = (CacheManagement) proxy;
+                T other = (T) cm.getWrappedObject();
+                result = element.equals(other);
+                break;
+            case "getWrappedObject":
+                return element;
+            default:
+                result = method.invoke(element, args);
+                break;
+        }
+
+        return result;
+    }
+
+    /**
+     * This method is used to be able to access the wrapped object underneath the dynamic proxy
+     * 
+     * @see org.onap.appc.pool.CacheManagement#getWrappedObject()
+     */
+    @Override
+    public T getWrappedObject() {
+        return element;
+    }
+
+    @SuppressWarnings("nls")
+    @Override
+    public String toString() {
+        return element == null ? "null" : element.toString();
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/Destructor.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/Destructor.java
new file mode 100644 (file)
index 0000000..6c7e7d4
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+
+/**
+ * @param <T>
+ *            The generic type we are caching
+ */
+
+public interface Destructor<T extends Closeable> {
+
+    /**
+     * Called to destroy the object when it is no longer being used by the pool
+     *
+     * @param obj
+     *            The object to be destroyed
+     * @param pool
+     *            The pool that the object is being removed from
+     */
+    void destroy(T obj, Pool<T> pool);
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/Pool.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/Pool.java
new file mode 100644 (file)
index 0000000..1faf0fe
--- /dev/null
@@ -0,0 +1,371 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class is used to manage a pool of things.
+ * <p>
+ * The class is parameterized so that the type of objects maintained in the pool is definable by some provided type.
+ * This type must implement the <code>Comparable</code> interface so that it can be managed in the pool.
+ * </p>
+ * 
+ * @param <T>
+ *            The type of element being pooled
+ */
+
+public class Pool<T extends Closeable> {
+    private Deque<T> free;
+    private List<T> allocated;
+    private int minPool;
+    private int maxPool;
+    private Allocator<T> allocator;
+    private Destructor<T> destructor;
+    private ReadWriteLock lock;
+    private AtomicBoolean drained;
+    private Properties properties;
+
+    /**
+     * Create the pool
+     *
+     * @param minPool
+     *            The minimum size of the pool
+     * @param maxPool
+     *            The maximum size of the pool, set to zero (0) for unbounded
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    public Pool(int minPool, int maxPool) throws PoolSpecificationException {
+
+        if (minPool < 0) {
+            throw new PoolSpecificationException(String.format("The minimum pool size must be a "
+                + "positive value or zero, %d is not valid.", minPool));
+        }
+        if (maxPool != 0 && maxPool < minPool) {
+            throw new PoolSpecificationException(String.format("The maximum pool size must be a "
+                + "positive value greater than the minimum size, or zero. %d is not valid.", maxPool));
+        }
+
+        this.minPool = minPool;
+        this.maxPool = maxPool;
+
+        properties = new Properties();
+        free = new ArrayDeque<T>();
+        allocated = new ArrayList<T>();
+        lock = new ReentrantReadWriteLock();
+        drained = new AtomicBoolean(false);
+    }
+
+    /**
+     * Returns the amount of objects on the free collection
+     *
+     * @return The number of objects on the free collection
+     */
+    public int getFreeSize() {
+        Lock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            return free.size();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the value for a specified property of this pool, if defined.
+     * 
+     * @param key
+     *            The key of the desired property
+     * @return The value of the property, or null if not defined
+     */
+    public String getProperty(String key) {
+        return properties.getProperty(key);
+    }
+
+    /**
+     * Sets the value of the specified property or replaces it if it already exists
+     * 
+     * @param key
+     *            The key of the property to be set
+     * @param value
+     *            The value to set the property to
+     */
+    public void setProperty(String key, String value) {
+        properties.setProperty(key, value);
+    }
+
+    /**
+     * @return The properties object for the pool
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Returns the number of objects that are currently allocated
+     *
+     * @return The allocate collection size
+     */
+    public int getAllocatedSize() {
+        Lock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            return allocated.size();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * @return the value of allocator
+     */
+    public Allocator<T> getAllocator() {
+        return allocator;
+    }
+
+    /**
+     * @param allocator
+     *            the value for allocator
+     */
+    public void setAllocator(Allocator<T> allocator) {
+        this.allocator = allocator;
+    }
+
+    /**
+     * @return the value of destructor
+     */
+    public Destructor<T> getDestructor() {
+        return destructor;
+    }
+
+    /**
+     * @return the value of minPool
+     */
+    public int getMinPool() {
+        return minPool;
+    }
+
+    /**
+     * @return the value of maxPool
+     */
+    public int getMaxPool() {
+        return maxPool;
+    }
+
+    /**
+     * @param destructor
+     *            the value for destructor
+     */
+    public void setDestructor(Destructor<T> destructor) {
+        this.destructor = destructor;
+    }
+
+    /**
+     * Drains the pool, releasing and destroying all pooled objects, even if they are currently allocated.
+     */
+    public void drain() {
+        if (drained.compareAndSet(false, true)) {
+            Lock writeLock = lock.writeLock();
+            writeLock.lock();
+            try {
+                int size = getAllocatedSize();
+                /*
+                 * We can't use the "release" method call here because we are modifying the list we are iterating
+                 */
+                ListIterator<T> it = allocated.listIterator();
+                while (it.hasNext()) {
+                    T obj = it.next();
+                    it.remove();
+                    free.addFirst(obj);
+                }
+                size = getFreeSize();
+                trim(size);
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Returns an indication if the pool has been drained
+     *
+     * @return True indicates that the pool has been drained. Once a pool has been drained, it can no longer be used.
+     */
+    public boolean isDrained() {
+        return drained.get();
+    }
+
+    /**
+     * Reserves an object of type T from the pool for the caller and returns it
+     *
+     * @return The object of type T to be used by the caller
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @SuppressWarnings("unchecked")
+    public T reserve() throws PoolExtensionException, PoolDrainedException {
+        if (isDrained()) {
+            throw new PoolDrainedException("The pool has been drained and cannot be used.");
+        }
+
+        T obj = null;
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            int freeSize = getFreeSize();
+            int allocatedSize = getAllocatedSize();
+
+            if (freeSize == 0) {
+                if (allocatedSize == 0) {
+                    extend(minPool == 0 ? 1 : minPool);
+                } else if (allocatedSize >= maxPool && maxPool > 0) {
+                    throw new PoolExtensionException(String.format("Unable to add "
+                        + "more elements, pool is at maximum size of %d", maxPool));
+                } else {
+                    extend(1);
+                }
+            }
+
+            obj = free.removeFirst();
+            allocated.add(obj);
+        } finally {
+            writeLock.unlock();
+        }
+
+        /*
+         * Now that we have the real object, lets wrap it in a dynamic proxy so that we can intercept the close call and
+         * just return the context to the free pool. obj.getClass().getInterfaces(). We need to find ALL interfaces that
+         * the object (and all superclasses) implement and have the proxy implement them too
+         */
+        Class<?> cls = obj.getClass();
+        Class<?>[] array;
+        List<Class<?>> interfaces = new ArrayList<Class<?>>();
+        while (!cls.equals(Object.class)) {
+            array = cls.getInterfaces();
+            for (Class<?> item : array) {
+                if (!interfaces.contains(item)) {
+                    interfaces.add(item);
+                }
+            }
+            cls = cls.getSuperclass();
+        }
+        array = new Class<?>[interfaces.size()];
+        array = interfaces.toArray(array);
+        return CachedElement.newInstance(this, obj, array);
+    }
+
+    /**
+     * releases the allocated object back to the free pool to be used by another request.
+     *
+     * @param obj
+     *            The object to be returned to the pool
+     * @throws PoolDrainedException
+     *             If the caller is trying to release an element to a drained pool
+     */
+    public void release(T obj) throws PoolDrainedException {
+        if (isDrained()) {
+            throw new PoolDrainedException("The pool has been drained and cannot be used.");
+        }
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            if (allocated.remove(obj)) {
+                free.addFirst(obj);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Extend the free pool by some number of elements
+     *
+     * @param count
+     *            The number of elements to add to the pool
+     * @throws PoolExtensionException
+     *             if the pool cannot be extended because no allocator has been specified.
+     */
+    private void extend(int count) throws PoolExtensionException {
+        if (allocator == null) {
+            throw new PoolExtensionException(String.format("Unable to extend pool "
+                + "because no allocator has been specified"));
+        }
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            for (int index = 0; index < count; index++) {
+                T obj = allocator.allocate(this);
+                if (obj == null) {
+                    throw new PoolExtensionException(
+                        "The allocator failed to allocate a new context to extend the pool.");
+                }
+                free.push(obj);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Used to trim the free collection by some specified number of elements, or the free element count, whichever is
+     * less. The elements are removed from the end of the free element deque, thus trimming the oldest elements first.
+     *
+     * @param count
+     *            The number of elements to trim
+     */
+    private void trim(int count) {
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            int trimCount = count;
+            if (getFreeSize() < count) {
+                trimCount = getFreeSize();
+            }
+            for (int i = 0; i < trimCount; i++) {
+                T obj = free.removeLast();
+                if (destructor != null) {
+                    destructor.destroy(obj, this);
+                }
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolDrainedException.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolDrainedException.java
new file mode 100644 (file)
index 0000000..0831366
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * This exception is thrown whenever an attempt is made to access a pool of resources where the pool has been drained.
+ * Once drained, the pool is no longer usable.
+ *
+ */
+public class PoolDrainedException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolDrainedException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolDrainedException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolException.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolException.java
new file mode 100644 (file)
index 0000000..9b22eee
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * A pool exception is a specialization of checked exceptions that define various pool abnormal states or requests.
+ *
+ */
+public class PoolException extends Exception {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolException constructor
+     */
+    public PoolException() {
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     */
+    public PoolException(String message) {
+        super(message);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param cause
+     *            The cause of the exception
+     */
+    public PoolException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     * @param cause
+     *            The cause of the exception
+     */
+    public PoolException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     * @param cause
+     *            The cause of the exception
+     * @param enableSuppression
+     *            whether or not suppression is enabled or disabled
+     * @param writableStackTrace
+     *            whether or not the stack trace should be writable
+     */
+    public PoolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolExtensionException.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolExtensionException.java
new file mode 100644 (file)
index 0000000..9daaca1
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * An error occurred trying to extend the pool
+ *
+ */
+public class PoolExtensionException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolExtensionException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolExtensionException(String msg) {
+        super(msg);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolSpecificationException.java b/appc-core/appc-common-bundle/java/org/onap/appc/pool/PoolSpecificationException.java
new file mode 100644 (file)
index 0000000..d1f2189
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * This exception is thrown whenever the pool is not specified correctly
+ * 
+ */
+public class PoolSpecificationException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolSpecificationException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolSpecificationException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/rest/client/RestClientInvoker.java b/appc-core/appc-common-bundle/java/org/onap/appc/rest/client/RestClientInvoker.java
new file mode 100644 (file)
index 0000000..41a0a85
--- /dev/null
@@ -0,0 +1,258 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.rest.client;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.onap.appc.exceptions.APPCException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+@SuppressWarnings("deprecation")
+public class RestClientInvoker {
+
+    private static final EELFLogger LOG = EELFManager.getInstance().getLogger(RestClientInvoker.class);
+    private static final String OPERATION_HTTPS = "https";
+    private static final String OPERATION_APPLICATION_JSON = " application/json";
+    private static final String BASIC = "Basic ";
+
+    private URL url = null;
+    private String basicAuth = null;
+
+    public RestClientInvoker(URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Sets the basic authentication header for the given user and password. If either entry is null
+     * then does not set basic auth
+     *
+     * @param user The user with optional domain name (for AAF)
+     * @param password The password for the user
+     */
+    public void setAuthentication(String user, String password) {
+        if (user != null && password != null) {
+            String authStr = user + ":" + password;
+            basicAuth = new String(Base64.encodeBase64(authStr.getBytes()));
+        }
+    }
+
+    public HttpResponse doPost(String path, String body) throws APPCException {
+        HttpPost post;
+
+        try {
+
+            URL postUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            post = new HttpPost(postUrl.toExternalForm());
+            post.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            post.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                post.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+            StringEntity entity = new StringEntity(body);
+            entity.setContentType(OPERATION_APPLICATION_JSON);
+            post.setEntity(new StringEntity(body));
+        } catch (MalformedURLException | UnsupportedEncodingException e) {
+            throw new APPCException(e);
+        }
+        HttpClient client = getHttpClient();
+
+        try {
+            return client.execute(post);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    /**
+     * This is Generic method that can be used to perform REST Put operation
+     *
+     * @param path - path for put
+     * @param body - payload for put action which will be sent as request body.
+     * @return - HttpResponse object which is returned from put REST call.
+     * @throws APPCException when error occurs
+     */
+    public HttpResponse doPut(String path, String body) throws APPCException {
+        HttpPut put;
+        try {
+            URL putUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            put = new HttpPut(putUrl.toExternalForm());
+            put.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            put.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                put.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+            StringEntity entity = new StringEntity(body);
+            entity.setContentType(OPERATION_APPLICATION_JSON);
+            put.setEntity(new StringEntity(body));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        HttpClient client = getHttpClient();
+
+        try {
+            return client.execute(put);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    public HttpResponse doGet(String path) throws APPCException {
+        HttpGet get;
+        try {
+            URL getUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            get = new HttpGet(getUrl.toExternalForm());
+            get.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            get.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                get.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+        } catch (Exception e) {
+            throw new APPCException(e);
+        }
+
+        try (CloseableHttpClient client = getHttpClient()) {
+            return client.execute(get);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    private CloseableHttpClient getHttpClient() throws APPCException {
+        switch (url.getProtocol()) {
+            case OPERATION_HTTPS:
+                return createHttpsClient();
+            case "http":
+                return new DefaultHttpClient();
+            default:
+                throw new APPCException("The url did not start with http[s]");
+        }
+    }
+
+
+    private CloseableHttpClient createHttpsClient() {
+        try {
+            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            trustStore.load(null, null);
+            MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
+            sf.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+            HttpParams params = new BasicHttpParams();
+            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+            registry.register(new Scheme(OPERATION_HTTPS, sf, 443));
+            registry.register(new Scheme(OPERATION_HTTPS, sf, 8443));
+            registry.register(new Scheme("http", sf, 8181));
+
+            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+            return new DefaultHttpClient(ccm, params);
+        } catch (Exception e) {
+            LOG.error("Error creating HTTPs Client. Creating default client.", e);
+            return new DefaultHttpClient();
+        }
+    }
+
+    private static class MySSLSocketFactory extends SSLSocketFactory {
+        private SSLContext sslContext = SSLContext.getInstance("TLS");
+
+        private MySSLSocketFactory(KeyStore truststore)
+                throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+            super(truststore);
+
+            TrustManager tm = new X509TrustManager() {
+                @Override
+                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                    LOG.debug("Inside checkClientTrusted");
+                }
+
+                @Override
+                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                    LOG.debug("Inside checkServerTrusted");
+                }
+
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return new X509Certificate[1];
+                }
+            };
+
+            sslContext.init(null, new TrustManager[] {tm}, null);
+        }
+
+        @Override
+        public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
+            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
+        }
+
+        @Override
+        public Socket createSocket() throws IOException {
+            return sslContext.getSocketFactory().createSocket();
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/JsonUtil.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/JsonUtil.java
new file mode 100644 (file)
index 0000000..1478459
--- /dev/null
@@ -0,0 +1,126 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class JsonUtil {
+
+    static ObjectMapper MAPPER = null;
+    static {
+        MAPPER = new ObjectMapper();
+        MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
+        MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // allow translation even
+                                                                           // if extra attrs exist
+                                                                           // in the json
+        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+        // Uncomment below when Jackson is upgraded to version 2.7 or above
+        // MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
+    }
+
+    /**
+     * @param valueAsString a valid json Map represented as String
+     * @return a flat map that each entry key derived from hierarchy path in the json object and
+     *         flatted to a dotted separated string. e.g.
+     *         "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}"; will be
+     *         represented as {A=A-value, B.C=B.C-value, B.D=B.D-value} when it required that the
+     *         input will not be flatted the json string should be formatted as below example: e.g.
+     *         "{\"A\":\"A-value\",\"B\":\"{\\\"C\\\":\\\"C-value\\\",\\\"D\\\":\\\"D-value\\\"}\"}"
+     *         will be represented as {A=A-value, B={"C":"C-value","D":"D-value"}}
+     * @throws IOException when the object is not valid json Map
+     */
+    public static Map<String, String> convertJsonStringToFlatMap(String valueAsString)
+            throws IOException {
+        Map readValueMap = MAPPER.readValue(valueAsString, Map.class);
+        return org.onap.appc.util.ObjectMapper.map(readValueMap);
+    }
+
+    /**
+     * 0 is the getStackTrace method 1 is the current method 2 is the parent method, 3 is the
+     * grandparent method or the parent class in this case.
+     */
+    private static final int PARENT_CLASS_INDEX = 3;
+
+
+    /**
+     * @see #readInputJson(String, Class, Class)
+     */
+    public static <T> T readInputJson(String location, Class<T> returnClass) throws IOException {
+        return readInputJson(location, returnClass, getCallingClass(PARENT_CLASS_INDEX));
+    }
+
+    /**
+     * @param location The location or name of the file we are trying to read e.g. JsonBody.json
+     * @param returnClass The class *this* Json is suppose to represent.
+     * @param locationClass The starting point for json lookup. the value specified by location is
+     *        relative to this class.
+     * @return The object being returned
+     * @throws IOException Can't find the specified json file at Location.
+     */
+    public static <T> T readInputJson(String location, Class<T> returnClass, Class<?> locationClass)
+            throws IOException {
+        try (InputStream is = locationClass.getResourceAsStream(location)) {
+            validateInput(is, location);
+            return MAPPER.readValue(is, returnClass);
+        }
+    }
+
+    /**
+     * Note that this method is sensitive to the depth of the call stack. For example if a public
+     * method calls a private method, that calls this method likely the desired classIndex value is
+     * 4 rather than 3. However, it's convenient to reduce the input required by callers of this
+     * class.
+     *
+     * @param classIndex How far up the stack trace to find the class we want.
+     * @return The class that called one of the public methods of this class.
+     */
+    private static Class<?> getCallingClass(int classIndex) {
+        String className = Thread.currentThread().getStackTrace()[classIndex].getClassName();
+        try {
+            return Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            // Theoretically impossible.
+            throw new IllegalStateException(
+                    "Could not do class lookup for class in our stack trace?!?");
+        }
+    }
+
+    private static void validateInput(InputStream is, String location)
+            throws FileNotFoundException {
+        if (is == null) {
+            throw new FileNotFoundException(String.format("Could not find file at '%s'", location));
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/MessageFormatter.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/MessageFormatter.java
new file mode 100644 (file)
index 0000000..a46047e
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import org.apache.commons.lang3.StringUtils;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class MessageFormatter {
+    private final static String paramNameRegexGroupName = "paramName";
+
+    /**
+     * start with ${ and after there is one or more characters that are not $ and not } and ended with }
+     */
+    private final static String paramRegex = "\\$\\{(?<paramName>[^}$]+)\\}";
+
+    public static String format(String messageTemplate, Map<String, Object> params) {
+        if (StringUtils.isEmpty(messageTemplate))
+            return "";
+        if (params == null || params.isEmpty())
+            return messageTemplate;
+
+        String formattedMessage = messageTemplate;
+        if (formattedMessage.contains("$")) {
+            for (Map.Entry<String, Object> entry : params.entrySet()) {
+                formattedMessage = formattedMessage.replaceAll("\\$\\{" + entry.getKey() + "\\}",
+                        escapeDollarChar(String.valueOf(entry.getValue())));
+            }
+        }
+
+        return formattedMessage;
+    }
+
+    private static String escapeDollarChar(String msg) {
+        String formatedMsg = msg;
+        if (formatedMsg.contains("$")) {
+            formatedMsg = formatedMsg.replaceAll("\\$", "\\\\\\$");
+
+        }
+        return formatedMsg;
+    }
+
+    public static List<String> getParamsNamesList(String messageTemplate) {
+        List<String> paramsNames = null;
+        if (!StringUtils.isEmpty(messageTemplate)) {
+            paramsNames = new ArrayList<>();
+            Matcher m = Pattern.compile(paramRegex).matcher(messageTemplate);
+            while (m.find()) {
+                String paramName = m.group(paramNameRegexGroupName);
+                paramsNames.add(paramName);
+            }
+        }
+        return paramsNames;
+    }
+
+    public static Set<String> getParamsNamesSet(String messageTemplate) {
+        List<String> paramsNamesList = getParamsNamesList(messageTemplate);
+        Set<String> paramsNamesSet = null;
+        if (paramsNamesList != null && !paramsNamesList.isEmpty()) {
+            paramsNamesSet = new HashSet<String>();
+            for (String paramName : paramsNamesList) {
+                paramsNamesSet.add(paramName);
+            }
+        }
+        return paramsNamesSet;
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/ObjectMapper.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/ObjectMapper.java
new file mode 100644 (file)
index 0000000..e4b76dd
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.lang.reflect.Array;
+import java.util.Map;
+
+public class ObjectMapper {
+
+       private ObjectMapper() {
+       }
+
+       private static void dispatch(PathContext context, Object obj) {
+
+               if (obj == null) {
+                       return;
+               }
+
+               final Class<?> cls = obj.getClass();
+
+               if (cls.isPrimitive()
+                               || String.class.isAssignableFrom(cls)
+                               || Number.class.isAssignableFrom(cls)
+                               || Boolean.class.isAssignableFrom(cls)) {
+                       handlePrimitive(context, obj);
+               } else if (cls.isArray()) {
+                       handleArray(context, obj);
+               } else if (Map.class.isAssignableFrom(cls)) {
+                       handleMap(context, (Map<?, ?>) obj);
+               } else if (Iterable.class.isAssignableFrom(cls)) {
+                       handleCollection(context, Iterable.class.cast(obj));
+               } else {
+                       throw new IllegalArgumentException(obj.getClass().getName());
+               }
+       }
+
+       public static Map<String, String> map(Object obj) {
+               PathContext context = new PathContext();
+               dispatch(context, obj);
+               return context.entries();
+       }
+
+       private static void handleMap(PathContext context, Map<?, ?> val) {
+               for (Map.Entry<?, ?> entry : val.entrySet()) {
+                       context.pushToken(entry.getKey().toString());
+                       dispatch(context, entry.getValue());
+                       context.popToken();
+               }
+       }
+
+       private static void handleCollection(PathContext context, Iterable<?> val) {
+               int index = 0;
+               for (Object elem : val) {
+                       handleElement(context, index++, elem);
+               }
+       }
+
+       private static void handleArray(PathContext context, Object val) {
+               for (int i = 0, n = Array.getLength(val); i < n; i++) {
+                       handleElement(context, i, Array.get(val, i));
+               }
+       }
+
+       private static void handleElement(PathContext context, int index, Object val) {
+               if (val == null) {
+                       return;
+               }
+
+               String modifier = new StringBuilder().append('[').append(Integer.valueOf(index)).append(']').toString();
+
+               context.pushModifier(modifier);
+               dispatch(context, val);
+               context.popModifier();
+       }
+
+       private static void handlePrimitive(PathContext context, Object val) {
+               context.entry(context.getPath(), val.toString());
+       }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/PathContext.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/PathContext.java
new file mode 100644 (file)
index 0000000..d57837c
--- /dev/null
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+class PathContext {
+
+       private StringBuilder path = new StringBuilder(128);
+
+       private LinkedList<Integer> indexes = new LinkedList<>();
+       private Map<String, String> entries = new LinkedHashMap<>();
+       private int offset = 0;
+
+       private final String delimiter;
+
+       PathContext() {
+               this(".");
+       }
+
+       PathContext(String delimiter) {
+               this.delimiter = delimiter;
+       }
+
+       private void push(String elem, boolean delimit) {
+               if (elem == null) {
+                       throw new IllegalArgumentException();
+               }
+
+               int length = elem.length();
+
+               if (delimit && !indexes.isEmpty()) {
+                       path.append(delimiter);
+                       length += delimiter.length();
+               }
+
+               path.append(elem);
+               offset += length;
+               indexes.addLast(Integer.valueOf(length));
+       }
+
+       private void pop() {
+               if (indexes.isEmpty()) {
+                       throw new IllegalStateException();
+               }
+               offset -= indexes.removeLast();
+               path.setLength(offset);
+       }
+
+       void pushToken(String token) {
+               push(token, true);
+       }
+
+       void popToken() {
+               pop();
+       }
+
+       void pushModifier(String modifier) {
+               push(modifier, false);
+       }
+
+       void popModifier() {
+               pop();
+       }
+
+       String getPath() {
+               return path.substring(0, offset);
+       }
+
+       void entry(String name, String value) {
+               entries.put(name, value);
+       }
+
+       Map<String, String> entries() {
+               return Collections.unmodifiableMap(entries);
+       }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/StreamHelper.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/StreamHelper.java
new file mode 100644 (file)
index 0000000..4468c84
--- /dev/null
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+public class StreamHelper {
+
+    /**
+     * private default constructor prevents instantiation
+     */
+    private StreamHelper() {
+    }
+
+    /**
+     * @param inputStream
+     * @return Input stream converted to string
+     */
+    public static String getStringFromInputStream(InputStream inputStream) {
+        StringBuffer buffer = new StringBuffer();
+        byte[] array = new byte[4096];
+
+        if (inputStream != null) {
+            try {
+                int len = inputStream.read(array);
+                while (len != -1) {
+                    buffer.append(new String(array, 0, len, Charset.forName("UTF-8")));
+                    len = inputStream.read(array);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return buffer.toString();
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/StringHelper.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/StringHelper.java
new file mode 100644 (file)
index 0000000..920ce42
--- /dev/null
@@ -0,0 +1,604 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class contains several static helper methods that can be used to perform string manipulation algorithms.
+ */
+
+public final class StringHelper {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(StringHelper.class);
+
+    public static final String DASH = "-";
+    public static final String DOT = ".";
+    public static final String ELLIPSES = "...";
+    public static final String LINE_FEED = "\n";
+    public static final String SLASH = "/";
+    public static final String COMMA = ",";
+
+    /**
+     * Converts the specified string pattern to a regular expression string. If the supplied string is null or empty,
+     * then a regular expression that matches all strings (.*) is returned.
+     * <p>
+     * The expression passed to this method should not already be a regular expression. If it contains problematic
+     * meta-characters for this routine (such as period, asterisk, and plus), they will be escaped and matched literally
+     * in the resulting regular expression returned.
+     * </p>
+     *
+     * @param value
+     *            The pattern that we need to convert to a regular expression
+     * @return The regular expression that is equivalent to the pattern
+     */
+    public static String convertToRegex(String value) {
+        if (value == null || value.trim().length() == 0) {
+            return ".*";
+        }
+
+        StringBuilder builder = new StringBuilder(value.trim());
+
+        /*
+         * If there are any period characters, we need to escape them so that they are exactly matched
+         */
+        Pattern pattern = Pattern.compile("\\.");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.replace(matcher.start(), matcher.end(), "\\.");
+            position = matcher.end() + 1;
+        }
+
+        /*
+         * If there are any asterisks or pluses, which we need to interpret as wildcard characters, we need to convert
+         * them into .* or .
+         */
+        pattern = Pattern.compile("\\*|\\+");
+        matcher = pattern.matcher(builder);
+
+        /*
+         * If the string contains a .* meta-character sequence anywhere in the middle of the string (i.e., there are
+         * other characters following the .* meta-characters), OR the string ends with the .+ sequence, then we need to
+         * append the "end-of-line" boundary condition to the end of the string to get predictable results.
+         */
+        if (resolveAppendingEOL(builder, matcher)) {
+            builder.append("$");
+        }
+        return builder.toString();
+    }
+
+    private static boolean resolveAppendingEOL(StringBuilder builder, Matcher matcher) {
+        int position = 0;
+        boolean appendEOL = false;
+
+        while (matcher.find(position)) {
+            String metachar = builder.substring(matcher.start(), matcher.end());
+            if ("*".equals(metachar)) {
+                builder.replace(matcher.start(), matcher.end(), ".*");
+                position = matcher.end() + 1;
+                if (matcher.end() < builder.length() - 1) {
+                    appendEOL = true;
+                }
+            } else if ("+".equals(metachar)) {
+                builder.replace(matcher.start(), matcher.end(), ".");
+                position = matcher.end();
+                if (matcher.end() == builder.length()) {
+                    appendEOL = true;
+                }
+            }
+        }
+        return appendEOL;
+    }
+
+    /**
+     * Takes a string that may possibly be very long and return a string that is at most maxLength. If the string is
+     * longer than maxLength, the last three characters will be the ellipses (...) to indicate that the string was
+     * shortened.
+     *
+     * @param possiblyLongString
+     * @param maxLength
+     *            must be at least 4 (one character plus ellipses)
+     * @return possibly shortened string
+     */
+    public static String getShortenedString(String possiblyLongString, int maxLength) {
+        if ((possiblyLongString != null) && (maxLength > ELLIPSES.length())
+            && (possiblyLongString.length() > maxLength)) {
+            return possiblyLongString.substring(0, maxLength - ELLIPSES.length()) + ELLIPSES;
+
+        }
+        return possiblyLongString;
+    }
+
+    /**
+     * Determines that a provided string is not null and not empty (length = 0 after trimming)
+     *
+     * @param theString
+     *            The string to be tested
+     * @return true if the string IS NOT null and is NOT empty
+     */
+    public static boolean isNotNullNotEmpty(String theString) {
+        return theString != null && !theString.trim().isEmpty();
+    }
+
+    /**
+     * Determines that a provided string IS null or an empty string (length = 0 after trimming)
+     *
+     * @param theString
+     *            The string to be tested
+     * @return true if the string IS null OR is empty
+     */
+    public static boolean isNullOrEmpty(String theString) {
+        return theString == null || theString.trim().isEmpty();
+    }
+
+    /**
+     * Returns an indication if the first string is equal to the second string, allowing for either or both strings to
+     * be null.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @return True if both strings are null, or both strings are non-null AND they are equal. False otherwise.
+     */
+    public static boolean areEqual(String a, String b) {
+        return areEqual(a, b, false);
+    }
+
+    /**
+     * Returns an indication if the first string is equal to the second string, allowing for either or both strings to
+     * be null, and ignoring case.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @return True if both strings are null, or both strings are non-null AND they are equal (without regard to case).
+     *         False otherwise.
+     */
+    public static boolean equalsIgnoreCase(String a, String b) {
+        return areEqual(a, b, true);
+    }
+
+    /**
+     * Compares two strings (allowing either or both to be null), and allowing for optional case sensitive or
+     * insensitive comparison.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @param caseInsensitive
+     *            True if the comparison is to be case in-sensitive.
+     * @return True if both strings are null, or both strings are non-null and they are equal
+     */
+    private static boolean areEqual(String a, String b, boolean caseInsensitive) {
+        if (a == null && b == null) {
+            return true;
+        }
+        if (a != null && b != null) {
+            if (caseInsensitive) {
+                return a.equalsIgnoreCase(b);
+            } else {
+                return a.equals(b);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * This method is used to mangle a name.
+     * <p>
+     * This method will first remove all unacceptable characters from the name and translate all characters to lower
+     * case. This is done to eliminate any potentially troublesome characters. If the resulting string is empty, then a
+     * random string of characters for the minimum desired length is returned. If the string is too short to meet the
+     * minimum length requirement, it is padded with random characters.
+     * </p>
+     * <p>
+     * Once the string has been scrubbed and possibly padded, it may be truncated (if longer than the maximum value) and
+     * the result is returned. To make the string as unique as possible, the algorithm removes excess letters from the
+     * center of the string, concatenating the first nad last parts of the name together. The assumption is that users
+     * tend to start the names of multiple things in similar ways, and get more descriptive as the name progresses. If
+     * for example, several objects were named "A test Object", "A test Object1", and "A test Object2", shortening the
+     * name only from the left does not generate a unique name.
+     * </p>
+     *
+     * @param name
+     *            The name to be mangled
+     * @param minLen
+     *            minimum number of characters for the name
+     * @param maxLen
+     *            maximum number of characters for the name
+     * @return The mangled name, or an empty string if the value is null or an empty string.
+     */
+    public static String mangleName(String name, int minLen, int maxLen) {
+        StringBuilder builder = new StringBuilder(name == null ? "" : name);
+        Pattern pattern = Pattern.compile("[^a-z0-9]+", Pattern.CASE_INSENSITIVE);
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.delete(matcher.start(), matcher.end());
+            position = matcher.start();
+        }
+
+        if (builder.length() < minLen) {
+            for (int i = builder.length(); i <= minLen; i++) {
+                builder.append("A");
+            }
+        }
+
+        /*
+         * Remove out of the center of the name to preserve start and end and result in a string of max len
+         */
+        if (builder.length() > maxLen) {
+            int excess = builder.length() - maxLen;
+            int left = maxLen / 2;
+
+            builder.delete(left, excess + left);
+        }
+
+        return builder.toString().toLowerCase();
+    }
+
+    /**
+     * This method is used to normalize a string value.
+     * <p>
+     * This method will ensure that the string value is trimmed of all leading and trailing whitespace if not null. If
+     * it is null or an empty string, then it will return null.
+     * </p>
+     *
+     * @param value
+     *            The value to be normalized
+     * @return The normalized (no leading or trailing whitespace) value, or null if the string was null or an empty
+     *         string (or all whitespace). This method will never return an empty string.
+     */
+    public static String normalizeString(String value) {
+        if (value != null) {
+            String temp = value.trim();
+            if (temp.length() > 0) {
+                return temp;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method is used to strip all carriage returns and line feed characters from a string
+     *
+     * @param value
+     * @return The original value less all carriage returns and line feeds
+     */
+    public static String stripCRLF(String value) {
+
+        if (value == null) {
+            return null;
+        }
+        String[] tokens = value.split("\r\n|\n\r|\r|\n");
+        StringBuilder builder = new StringBuilder();
+        for (String token : tokens) {
+            builder.append(token.trim());
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Converts UNIX-style line endings to DOS-style. Replaces LF with CR+LF as long as the LF does not already exist
+     * paired with a CR.
+     *
+     * @param content
+     *            The content to be converted
+     * @return The converted content.
+     */
+    public static String toDOSLines(String content) {
+        if (content == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(content);
+        Pattern pattern = Pattern.compile("^(\n)[^\r]|[^\r](\n)[^\r]|[^\r](\n)$");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            int index = matcher.start(1);
+            if (index == -1) {
+                index = matcher.start(2);
+            }
+            if (index == -1) {
+                index = matcher.start(3);
+            }
+
+            builder.replace(index, index + 1, "\r\n");
+            position = index + 1;
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * This method will convert a string contents to use the UNIX-style line endings. That is, all occurrences of CR
+     * (Carriage Return) and LF (Line Feed) are reduced to just use LF.
+     *
+     * @param content
+     *            The buffer to be processed
+     * @return The converted contents
+     */
+    public static String toUnixLines(String content) {
+        if (content == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(content);
+        Pattern pattern = Pattern.compile("\r\n|\n\r");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.replace(matcher.start(), matcher.end(), "\n");
+            position = matcher.start();
+        }
+
+        return builder.toString();
+    }
+
+     /**
+     * This method is used to translate characters in the input sequence that match the characters in the match list to
+     * the corresponding character in the replacement list. If the replacement list is shorter than the match list, then
+     * the character from the replacement list is taken as the modulo of the match character position and the length of
+     * the replacement list.
+     *
+     * @param sequence
+     *            The input sequence to be processed
+     * @param match
+     *            The list of matching characters to be searched
+     * @param replacement
+     *            The list of replacement characters, positional coincident with the match list. If shorter than the
+     *            match list, then the position "wraps" around on the replacement list.
+     * @return The translated string contents.
+     */
+    public static Object translate(String sequence, String match, String replacement) {
+
+        if (sequence == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(sequence);
+
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+
+            int position = match.indexOf(ch);
+            if (position == -1) {
+                continue;
+            }
+
+            if (position >= replacement.length()) {
+                position %= replacement.length();
+            }
+            builder.setCharAt(index, replacement.charAt(position));
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Ensures that the name provided is a valid identifier. This means that no spaces are allowed as well as special
+     * characters. This method translates all spaces and illegal characters to underscores (_).
+     *
+     * @param name
+     *            The name to be checked and converted to an identifier if needed
+     * @return The valid identifier from the name
+     */
+    public static String validIdentifier(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        StringBuilder builder = new StringBuilder(name);
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+
+            if ((index == 0 && !Character.isJavaIdentifierStart(ch)) || (!Character.isJavaIdentifierPart(ch))) {
+                builder.setCharAt(index, '_');
+            }
+        }
+        return builder.toString();
+    }
+
+
+    /**
+     * Private constructor to prevent instantiation of this class - All methods are static!
+     */
+    private StringHelper() {
+
+    }
+
+    /**
+     * This method verifies that the provided string only contains characters from the legal set, and replaces any
+     * character not in the legal set with the specified replacement character.
+     *
+     * @param sequence
+     *            The sequence to be verified
+     * @param legal
+     *            The set of all legal characters
+     * @param replacement
+     *            The replacement character if a character is not in the legal set
+     * @return The verified *and possibly updated) string
+     */
+    public static String verify(String sequence, String legal, char replacement) {
+        if (sequence == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(sequence);
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+            if (legal.indexOf(ch) == -1) {
+                builder.setCharAt(index, replacement);
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param list
+     *            The list of elements
+     * @return The list of elements formatted as a comma-delimited list
+     */
+    public static String asList(List<String> list) {
+        StringBuilder builder = new StringBuilder();
+
+        if (list != null) {
+            if (list.size() == 1) {
+                builder.append(list.get(0));
+            } else {
+                for (String element : list) {
+                    builder.append(element);
+                    builder.append(", ");
+                }
+
+                if (builder.length() > 2) {
+                    builder.delete(builder.length() - 2, builder.length());
+                }
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param map
+     *            A map of strings
+     * @return A map expressed as a comma-delimited list of name=value tuples
+     */
+    public static String asList(Map<String, String> map) {
+        StringBuilder builder = new StringBuilder();
+        if (map != null) {
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                builder.append(String.format("%s=%s, ", key, map.get(key)));
+            }
+
+            if (builder.length() > 2) {
+                builder.delete(builder.length() - 2, builder.length());
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param values
+     *            An array or varargs of Strings to be concatenated into a comma-separated list
+     * @return The comma-seprated list of values
+     */
+    public static String asList(String... values) {
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        if (values != null && values.length > 0) {
+            int count = values.length;
+            for (int index = 0; index < count - 1; index++) {
+                builder.append(values[index]);
+                builder.append(',');
+            }
+            builder.append(values[count - 1]);
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static Object resolveToType(String input) {
+        String intRegex = "^(\\-)?[0-9]+$";
+        String doubleRegex = "^(\\-)?[0-9\\.]+$";
+        String boolRegex = "(^(?i)((true)|(false))$)";
+
+        // Check for null
+        if (input == null) {
+            return null;
+        }
+
+        // Check int first
+        if (input.matches(intRegex)) {
+            try {
+                return Integer.parseInt(input);
+            } catch (NumberFormatException nfe) {
+                // Should not happen
+                logger.error(nfe.getMessage());
+            }
+        }
+
+        // Check double (int + decimal point)
+        if (input.matches(doubleRegex)) {
+            try {
+                return Double.parseDouble(input);
+            } catch (NumberFormatException | NullPointerException e) {
+                // NPE won't happen bc of regex check
+                logger.error("Parsing input failed", e);
+            }
+        }
+
+        // Check boolean
+        if (input.matches(boolRegex)) {
+            return Boolean.parseBoolean(input);
+        }
+
+        // Try to parse a date
+        Date date = Time.utcParse(input);
+        if (date != null) {
+            return date;
+        }
+
+        // No special type, return string
+        return input;
+    }
+
+    /**
+     * Converts a properties object to a string in the format of <pre>[ key=value, key=value, ... ]</pre>
+     *
+     * @param props
+     *            The properties object to format
+     * @return A string in the format <pre>[ key=value, ... ]</pre> or null if the input was null
+     */
+    public static String propertiesToString(Properties props) {
+        if (props == null) {
+            return null;
+        }
+        StringBuilder out = new StringBuilder();
+        out.append("[");
+        for (Object key : props.keySet()) {
+            out.append(String.format(" %s = %s,", key.toString(), props.getProperty(key.toString())));
+        }
+        if (props.size() > 0) {
+            out.deleteCharAt(out.lastIndexOf(","));
+        }
+        out.append(" ]");
+        return out.toString();
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/StructuredPropertyHelper.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/StructuredPropertyHelper.java
new file mode 100644 (file)
index 0000000..5c18f3a
--- /dev/null
@@ -0,0 +1,259 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class is used to assemble properties that are defined using a structured name into groups, and allow them to be
+ * processed as sets of definitions.
+ * <p>
+ * For example, a structured name uses a dotted-notation, like "provider.name". Further, the nodes of the structured
+ * name may be serialized using a suffix ordinal number (e.g., "provider1.name"). These structured properties form a
+ * hierarchical name space where the names are grouped together and can be retrieved as a set.
+ * </p>
+ * 
+ */
+
+public class StructuredPropertyHelper {
+
+    /**
+     * This method scans the properties object for all properties that match the root name and constructs a list of
+     * structured property node graphs that represents the namespaces of the properties.
+     * <p>
+     * For example, assume that there are structured properties of the form "provider1.name", "provider2.name",
+     * "provider3.name", and so forth. There may also be other subordinate properties as well (e.g., "provider1.type").
+     * This method would construct a list of graphs of nodes, where each node represents one value of the structured
+     * name. The roots would be the values "provider1", "provider2", "provider3", and so forth. The values of the
+     * subordinate nodes would be the second, third, and so forth name nodes of the compound name. The value of the
+     * property is associated with nodes that are representative of the leaf of the name space.
+     * </p>
+     * 
+     * @param properties
+     *            The properties to be processed
+     * @param prefix
+     *            The prefix of the root structured property name
+     * @return The node graph of the properties
+     */
+    public static List<Node> getStructuredProperties(Properties properties, String prefix) {
+        List<Node> roots = new ArrayList<>();
+
+        for (String name : properties.stringPropertyNames()) {
+            if (name.startsWith(prefix)) {
+                String value = properties.getProperty(name);
+                processNamespace(roots, name, value);
+            }
+        }
+
+        return roots;
+    }
+
+    /**
+     * This method recursively walks the name space of the structured property and constructs the node graph to
+     * represent the property
+     * 
+     * @param nodes
+     *            The collection of nodes for the current level of the name space
+     * @param propertyName
+     *            The name of the node
+     * @param value
+     *            The value, if any
+     * @return The node for this level in the namespace
+     */
+    @SuppressWarnings("nls")
+    private static Node processNamespace(List<Node> nodes, String propertyName, String value) {
+        String[] tokens = propertyName.split("\\.", 2);
+        String nodeName = normalizeNodeName(tokens[0]);
+
+        Node namespaceNode = null;
+        for (Node node : nodes) {
+            if (node.getName().equals(nodeName)) {
+                namespaceNode = node;
+                break;
+            }
+        }
+        if (namespaceNode == null) {
+            namespaceNode = new Node();
+            namespaceNode.setName(nodeName);
+            nodes.add(namespaceNode);
+        }
+
+        if (tokens.length == 1 || tokens[1] == null || tokens[1].length() == 0) {
+            namespaceNode.setValue(value);
+        } else {
+            processNamespace(namespaceNode.getChildren(), tokens[1], value);
+        }
+
+        return namespaceNode;
+    }
+
+    /**
+     * This method normalizes a node name of the structured property name by removing leading and trailing whitespace,
+     * and by converting any ordinal position to a simple expression without leading zeroes.
+     * 
+     * @param token
+     *            The token to be normalized
+     * @return The normalized name, or null if the token was null;
+     */
+    @SuppressWarnings("nls")
+    private static String normalizeNodeName(String token) {
+        if (token == null) {
+            return null;
+        }
+
+        StringBuffer buffer = new StringBuffer(token.trim());
+        Pattern pattern = Pattern.compile("([^0-9]+)([0-9]*)");
+        Matcher matcher = pattern.matcher(buffer);
+        if (matcher.matches()) {
+            String nameRoot = matcher.group(1);
+            String ordinal = matcher.group(2);
+            if (ordinal != null && ordinal.length() > 0) {
+                int i = Integer.parseInt(ordinal);
+                buffer.setLength(0);
+                buffer.append(nameRoot);
+                buffer.append(Integer.toString(i));
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * This class represents a node in the structured property name space
+     *
+     */
+    public static class Node implements Comparable<Node> {
+
+        /**
+         * The name of the structured property node
+         */
+        private String name;
+
+        /**
+         * If the node is a leaf, then the value of the property
+         */
+        private String value;
+
+        /**
+         * If the node is not a leaf, then the sub-nodes of the property
+         */
+        private List<Node> children;
+
+        /**
+         * @return the value of name
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name
+         *            the value for name
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * @return the value of value
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * @param value
+         *            the value for value
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value of children
+         */
+        public List<Node> getChildren() {
+            if (children == null) {
+                children = new ArrayList<>();
+            }
+            return children;
+        }
+
+        /**
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return name.hashCode() + (value != null ? value.hashCode() : children.hashCode());
+        }
+
+        /**
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null)
+                return false;
+            if (this.getClass() != obj.getClass())
+                return false;
+
+            Node other = (Node) obj;
+            boolean result = name.equals(other.name);
+
+            if (value == null) {
+                result &= other.value == null;
+            } else {
+                result &= value.equals(other.value);
+            }
+            if (children == null) {
+                result &= other.children == null;
+            } else {
+                result &= children.equals(other.children);
+            }
+            return result;
+        }
+
+        /**
+         * @see java.lang.Object#toString()
+         */
+        @SuppressWarnings("nls")
+        @Override
+        public String toString() {
+            if (value != null) {
+                return String.format("%s = %s", name, value);
+            }
+            return String.format("%s.%s", name, children.toString());
+        }
+
+        @Override
+        public int compareTo(StructuredPropertyHelper.Node o) {
+            return name.compareTo(o.name);
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/Time.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/Time.java
new file mode 100644 (file)
index 0000000..5e39770
--- /dev/null
@@ -0,0 +1,599 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is a general purpose helper class to augment standard Java time support.
+ *
+ */
+
+public final class Time {
+
+    /**
+     * Logger to log operations
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(Time.class);
+
+    /**
+     * A formatter to be used to format values
+     */
+    private static SimpleDateFormat dateformatter = null;
+
+    /**
+     * The UTC timezone (for UTC or GMT time)
+     */
+    @SuppressWarnings("nls")
+    private static final TimeZone utcTZ = TimeZone.getTimeZone("UTC");
+
+    /**
+     * The cached reference to the datatype factory
+     */
+    private static DatatypeFactory xmlDatatypeFactory = null;
+
+    /**
+     * Private default constructor prevents instantiation
+     */
+    private Time() {
+        //
+    }
+
+    /**
+     * Increments a date by the indicated months, days, hours, minutes, and seconds, and returns the
+     * updated date.
+     *
+     * @param date The date to be manipulated
+     * @param months The number of months to be added to the date
+     * @param days The number of days to be added to the date
+     * @param hours The number of hours to be added to the date
+     * @param minutes The number of minutes to be added to the date
+     * @param seconds The number of seconds to be added to the date
+     * @return The updated date.
+     */
+    public static Date addTime(final Date date, final int months, final int days, final int hours,
+            final int minutes, final int seconds) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.add(Calendar.MONTH, months);
+        cal.add(Calendar.DATE, days);
+        cal.add(Calendar.HOUR_OF_DAY, hours);
+        cal.add(Calendar.MINUTE, minutes);
+        cal.add(Calendar.SECOND, seconds);
+        return cal.getTime();
+    }
+
+    /**
+     * Clears the time components of a calendar to zero, leaving the date components unchanged.
+     *
+     * @param cal the calendar to be updated
+     * @return The updated calendar object
+     */
+    public static Calendar dateOnly(final Calendar cal) {
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal;
+    }
+
+    /**
+     * This method returns the local time that corresponds to the end of the current day
+     *
+     * @return The time that corresponds to the end of the current day, expressed as local time
+     */
+    public static Date endOfDayLocal() {
+        return endOfDayLocal(new Date());
+    }
+
+    /**
+     * This method returns the last moment of the day for the supplied local time. This is defined
+     * as the millisecond before midnight of the current date represented by the local time.
+     *
+     * @param localTime The local time for which the last moment of the day is desired.
+     * @return The millisecond prior to midnight, local time.
+     */
+    public static Date endOfDayLocal(final Date localTime) {
+        // @sonar:off
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTime(localTime);
+        calendar.set(Calendar.HOUR, 11);
+        calendar.set(Calendar.AM_PM, Calendar.PM);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        // @sonar:on
+
+        return calendar.getTime();
+    }
+
+    /**
+     * The end of the current day and in the current time zone expressed as a UTC time.
+     *
+     * @return The UTC time that corresponds to the end of the current day
+     */
+    public static Date endOfDayUTC() {
+        return endOfDayUTC(new Date());
+    }
+
+    /**
+     * Returns the UTC time that corresponds to the end of the day for the local time specified,
+     * using the current (default) time zone.
+     *
+     * @param localTime The local time for which we are requesting the UTC time that corresponds to
+     *        the end of the day
+     * @return The UTC time that corresponds to the end of the local day specified by the local
+     *         time.
+     */
+    public static Date endOfDayUTC(final Date localTime) {
+        return endOfDayUTC(localTime, TimeZone.getDefault());
+    }
+
+    /**
+     * Returns the time expressed in UTC time of the end of the day specified in local time and
+     * within the local time zone.
+     *
+     * @param localTime The local time for which we will compute the end of the local day, and then
+     *        convert to UTC time.
+     * @param localTimeZone The time zone that the local time is within.
+     * @return The UTC date that corresponds to the end of the day local time and in the local time
+     *         zone.
+     */
+    public static Date endOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
+        Date endOfDay = endOfDayLocal(localTime);
+        return utcDate(endOfDay, localTimeZone);
+    }
+
+    /**
+     * returns current Date in 'UTC' Timezone
+     *
+     * @return The current date, expressed in the UTC timezone.
+     */
+    @SuppressWarnings("nls")
+    public static Date getCurrentUTCDate() {
+
+        // This code incorrectly changes the default timezone for the entire JVM in order to compute
+        // the UTC
+        // date for the current time.
+
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+        calendar.setTimeInMillis(utcTime());
+        return calendar.getTime();
+    }
+
+    /**
+     * This method loads and caches the reference to the XML data type factory object.
+     *
+     * @return The XML Data Type Factory object
+     */
+    public static DatatypeFactory getDatatypeFactory() {
+        if (xmlDatatypeFactory == null) {
+            try {
+                xmlDatatypeFactory = DatatypeFactory.newInstance();
+            } catch (DatatypeConfigurationException e) {
+                e.printStackTrace(System.err);
+            }
+        }
+        return xmlDatatypeFactory;
+    }
+
+    /**
+     * Gives the date-time String based on given Locale and Timezone
+     *
+     * @param date The date to be formatted
+     * @param locale The locale that we want to format the value for
+     * @param timezone The time zone that the date is within
+     * @return The formatted value
+     */
+    public static String getDateByLocaleAndTimeZone(final Date date, final Locale locale,
+            final TimeZone timezone) {
+        String strDate = null;
+        DateFormat df =
+                DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
+        df.setTimeZone(timezone);
+        synchronized (df) {
+            strDate = df.format(date);
+        }
+        return strDate;
+    }
+
+    /**
+     * Returns singleton UTC date formatter.
+     *
+     * @return
+     */
+    @SuppressWarnings("nls")
+    private static SimpleDateFormat getDateFormatter() {
+        if (dateformatter == null) {
+            dateformatter = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+            dateformatter.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
+        }
+        return dateformatter;
+    }
+
+    /**
+     * This method returns the local time that corresponds to a given UTC time in the current time
+     * zone.
+     *
+     * @param utcTime The UTC time for which we desire the equivalent local time in the current time
+     *        zone.
+     * @return The local time that is equivalent to the given UTC time for the current time zone
+     */
+    public static long localTime(final long utcTime) {
+        return localTime(utcTime, TimeZone.getDefault());
+    }
+
+    /**
+     * This method can be used to get the local time that corresponds to a specific UTC time.
+     * <p>
+     * This method has a problem since the offset can only be determined by having a local time. So,
+     * we take the UTC time and add the raw offset to it to come up with an approximation of the
+     * local time. This gives us a local time that we can use to determine what the offset should
+     * be, which is what we actually add to the UTC time to get the local time.
+     * </p>
+     *
+     * @param utcTime The UTC time for which we want to obtain the equivalent local time
+     * @param localTZ The time zone that we want the local time to be within
+     * @return The local time for the specified time zone and the given UTC time
+     */
+    public static long localTime(final long utcTime, final TimeZone localTZ) {
+        int offset = localTZ.getOffset(utcTime + localTZ.getRawOffset());
+        long result = utcTime + offset;
+
+        return result;
+    }
+
+    /**
+     * Sets the date components of a calendar to the specified values, leaving the time components
+     * unchanged.
+     *
+     * @param cal The calendar to be updated
+     * @param year The year to be set
+     * @param month The month to be set
+     * @param day The day to be set
+     * @return The updated calendar object
+     */
+    public static Calendar setDate(final Calendar cal, final int year, final int month,
+            final int day) {
+        cal.set(Calendar.YEAR, year);
+        cal.set(Calendar.MONTH, month);
+        cal.set(Calendar.DAY_OF_MONTH, day);
+        return cal;
+    }
+
+    /**
+     * Returns the start of the day expressed in local time for the current local time.
+     *
+     * @return The start of the day
+     */
+    public static Date startOfDayLocal() {
+        return startOfDayLocal(new Date());
+    }
+
+    /**
+     * This method returns the date that corresponds to the start of the day local time. The date
+     * returned represents midnight of the previous day represented in local time. If the UTC time
+     * is desired, use the methods {@link #startOfDayUTC(Date, TimeZone)},
+     * {@link #startOfDayUTC(Date)}, or {@link #startOfDayUTC()}
+     *
+     * @param localTime The local date that we wish to compute the start of day for.
+     * @return The date that corresponds to the start of the local day
+     */
+    public static Date startOfDayLocal(final Date localTime) {
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTime(localTime);
+        calendar.set(Calendar.HOUR, 0);
+        calendar.set(Calendar.AM_PM, Calendar.AM);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+
+        return calendar.getTime();
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day based on the
+     * current time and the default time zone (the time zone we are running in).
+     *
+     * @return The start of the local day expressed as a UTC time.
+     */
+    public static Date startOfDayUTC() {
+        return startOfDayUTC(new Date());
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day specified in
+     * the current time zone.
+     *
+     * @param localTime The local time to be used to compute the start of the day
+     * @return The start of the local day expressed as a UTC time.
+     */
+    public static Date startOfDayUTC(final Date localTime) {
+        return startOfDayUTC(localTime, TimeZone.getDefault());
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day specified in
+     * the local timezone.
+     *
+     * @param localTime The local time to be used to compute start of day
+     * @param localTimeZone The time zone that the local time was recorded within
+     * @return The corresponding UTC date
+     */
+    public static Date startOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
+        Date startOfDay = startOfDayLocal(localTime);
+        return utcDate(startOfDay, localTimeZone);
+    }
+
+    /**
+     * This method creates and returns an XML timestamp expressed as the current UTC value for the
+     * system. The caller does not specify the time value or time zone using this method. This
+     * ensures that the timestamp value is always expressed as UTC time.
+     *
+     * @return The XMLGregorianCalendar that can be used to record the timestamp
+     */
+
+    public static XMLGregorianCalendar timestamp() {
+        getDatatypeFactory();
+        XMLGregorianCalendar ts = xmlDatatypeFactory.newXMLGregorianCalendar();
+        GregorianCalendar utc = new GregorianCalendar();
+        utc.setTime(utcDate());
+        ts.setTimezone(0);
+        ts.setYear(utc.get(Calendar.YEAR));
+        // Calendar Months are from 0-11 need to +1
+        ts.setMonth(utc.get(Calendar.MONTH) + 1);
+        ts.setDay(utc.get(Calendar.DAY_OF_MONTH));
+        ts.setHour(utc.get(Calendar.HOUR_OF_DAY));
+        ts.setMinute(utc.get(Calendar.MINUTE));
+        ts.setSecond(utc.get(Calendar.SECOND));
+        ts.setMillisecond(utc.get(Calendar.MILLISECOND));
+        return ts;
+    }
+
+    /**
+     * Converts XMLGregorianCalendar to java.util.Date in Java
+     *
+     * @param calendar the calendar object to be converted
+     * @return The equivalent Date object
+     */
+    public static Date toDate(final XMLGregorianCalendar calendar) {
+        if (calendar == null) {
+            return null;
+        }
+        return calendar.toGregorianCalendar().getTime();
+    }
+
+    /**
+     * Converts java Date to XMLGregorianCalendar.
+     *
+     * @param date The date to convert
+     * @return The XMLGregorianCalendar for the specified date
+     */
+    @SuppressWarnings("nls")
+    public static XMLGregorianCalendar toXMLCalendar(final Date date) {
+        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
+        cal.setTime(date);
+
+        XMLGregorianCalendar xmlCal = null;
+        try {
+            xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
+        } catch (DatatypeConfigurationException e) {
+            LOG.error("toXMLCalendar", e);
+        }
+        return xmlCal;
+    }
+
+    /**
+     * Truncates the provided date so that only the date, hours, and minutes portions are
+     * significant. This method returns the date with the seconds and milliseconds forced to zero.
+     *
+     * @param date The date to truncate
+     * @return The date with only the year, month, day, hours, and minutes significant.
+     */
+    public static Date truncDate(final Date date) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
+
+    /**
+     * The UTC date that corresponds to the current date in the local time zone.
+     *
+     * @return The UTC date for now in the current time zone.
+     */
+    public static Date utcDate() {
+        return new Date();
+    }
+
+    /**
+     * The UTC date for the specified date in the current (default) time zone.
+     *
+     * @param date The local date for which the UTC date is desired.
+     * @return The UTC date that corresponds to the date in the current time zone.
+     */
+    public static Date utcDate(final Date date) {
+        TimeZone tz = TimeZone.getDefault();
+        return utcDate(date, tz);
+    }
+
+    /**
+     * Returns the UTC date for the specified date in the specified time zone.
+     *
+     * @param date The date for which the UTC date is desired in the specified zone
+     * @param tz The time zone that corresponds to the date to be converted to UTC
+     * @return The UTC date that corresponds to the local date in the local time zone.
+     */
+    public static Date utcDate(final Date date, final TimeZone tz) {
+        return new Date(utcTime(date.getTime(), tz));
+    }
+
+    /**
+     * Format incoming date as string in GMT or UTC.
+     *
+     * @param dt The date to be formatted
+     * @return The date formatted for UTC timezone
+     */
+    public static String utcFormat(final Date dt) {
+        String strDate = null;
+        DateFormat df = getDateFormatter();
+        synchronized (df) {
+            strDate = df.format(dt);
+        }
+        return strDate;
+    }
+
+    /**
+     * Parse previously formated Date object back to a Date object.
+     *
+     * @param dateStr The representation of a UTC date as a string
+     * @return The date object containing the parsed representation, or null if the representation
+     *         cannot be parsed
+     */
+    @SuppressWarnings("nls")
+    public static Date utcParse(final String dateStr) {
+        String[] adtl = {"yyyy-MM-dd"};
+        return utcParse(dateStr, adtl);
+    }
+
+    /**
+     * Parse previously formated Date object back to a Date object.
+     *
+     * @param dateStr The representation of a UTC date as a string
+     * @param adtlFormatStrings A list of strings that represent additional date format
+     *        representations to try and parse.
+     * @return The date object containing the parsed representation, or null if the representation
+     *         cannot be parsed
+     */
+    @SuppressWarnings("nls")
+    public static Date utcParse(final String dateStr, String... adtlFormatStrings) {
+        if (dateStr != null) {
+            // Build the list of formatters starting with the default defined in the class
+            List<DateFormat> formats = new ArrayList<>();
+            formats.add(getDateFormatter());
+
+            if (adtlFormatStrings != null) {
+                for (String s : adtlFormatStrings) {
+                    formats.add(new SimpleDateFormat(s));
+                }
+            }
+
+            // Return the first matching date formatter's result
+            for (DateFormat df : formats) {
+                df.setTimeZone(utcTZ);
+                try {
+                    return df.parse(dateStr);
+                } catch (ParseException e) {
+                    LOG.debug(String.format("IGNORE - Date string [%s] does not fit pattern [%s]",
+                            dateStr, df.toString()));
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method returns the current time for the UTC timezone
+     *
+     * @return The time in the UTC time zone that corresponds to the current local time.
+     */
+    public static long utcTime() {
+        return new Date().getTime();
+    }
+
+    /**
+     * Get the UTC time that corresponds to the given time in the default time zone (current time
+     * zone for the system).
+     *
+     * @param localTime The time in the current time zone for which the UTC time is desired.
+     * @return The UTC time
+     */
+    public static long utcTime(final long localTime) {
+        TimeZone tz = TimeZone.getDefault();
+        return utcTime(localTime, tz);
+    }
+
+    /**
+     * Get the UTC time that corresponds to the given time in the specified timezone.
+     * <p>
+     * Note that the java <code>getOffset()</code> method works a little counter-intuitive. It
+     * returns the offset that would be added to the current UTC time to get the LOCAL time
+     * represented by the local time zone. That means to get the UTC time, we need to SUBTRACT this
+     * offset from the local time.
+     * </p>
+     *
+     * @param localTime The time in the specified time zone for which the UTC time is desired.
+     * @param localTZ The time zone which the local time is in.
+     * @return The UTC time for the specified local time in the specified local time zone.
+     */
+    public static long utcTime(final long localTime, final TimeZone localTZ) {
+        int offset = localTZ.getOffset(localTime);
+        return localTime - offset;
+
+    }
+
+    /**
+     * Creates a timestamp value from a time
+     *
+     * @param utcTime The UTC time to convert to a timestamp
+     * @return The timestamp
+     */
+    public static Timestamp utcTimestamp(final long utcTime) {
+        TimeZone tz = TimeZone.getDefault();
+        return new Timestamp(utcTime(utcTime, tz));
+    }
+
+    public static String dateToStringConverterMillis(Date date) {
+        SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
+        if (date != null) {
+            return customDate.format(date);
+        }
+        return null;
+    }
+
+    public static Date stringToDateConverterMillis(String dateString) throws ParseException {
+        SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
+        return customDate.parse(dateString);
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/UnmodifiableProperties.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/UnmodifiableProperties.java
new file mode 100644 (file)
index 0000000..6d20b64
--- /dev/null
@@ -0,0 +1,355 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * This utility class is used to wrap a properties object and to delegate all read operations to the property object,
+ * while disallowing any write or modification to the property object.
+ * 
+ */
+public class UnmodifiableProperties extends Properties implements Cloneable {
+
+    /**
+     * Serial number
+     */
+    private static final long serialVersionUID = 1L;
+
+    private static final String PROPERTY_CANNOT_BE_MODIFIED_MSG = "Property cannot be modified!";
+
+    /**
+     * The properties object which we are wrapping
+     */
+    private Properties properties;
+
+    /**
+     * Create the unmodifiable wrapper around the provided properties object
+     * 
+     * @param properties
+     *            The properties to be wrapped and protected from modification
+     */
+    public UnmodifiableProperties(Properties properties) {
+        this.properties = properties;
+    }
+
+    /**
+     * @see java.util.Hashtable#clear()
+     */
+    @Override
+    public synchronized void clear() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#clone()
+     */
+    // @sonar:off
+    @Override
+    public synchronized Object clone() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    // @sonar:on
+
+    /**
+     * @see java.util.Hashtable#contains(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean contains(Object value) {
+        return properties.contains(value);
+    }
+
+    /**
+     * @see java.util.Hashtable#containsKey(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean containsKey(Object key) {
+        return properties.containsKey(key);
+    }
+
+    /**
+     * @see java.util.Hashtable#containsValue(java.lang.Object)
+     */
+    @Override
+    public boolean containsValue(Object value) {
+        return properties.containsValue(value);
+    }
+
+    /**
+     * @see java.util.Hashtable#elements()
+     */
+    @Override
+    public synchronized Enumeration<Object> elements() {
+        return properties.elements();
+    }
+
+    /**
+     * @see java.util.Hashtable#entrySet()
+     */
+    @Override
+    public Set<java.util.Map.Entry<Object, Object>> entrySet() {
+        return Collections.unmodifiableSet(properties.entrySet());
+    }
+
+    /**
+     * @see java.util.Hashtable#equals(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean equals(Object o) {
+        return properties.equals(o);
+    }
+
+    /**
+     * @see java.util.Hashtable#get(java.lang.Object)
+     */
+    @Override
+    public synchronized Object get(Object key) {
+        return properties.get(key);
+    }
+
+    /**
+     * @see java.util.Properties#getProperty(java.lang.String)
+     */
+    @Override
+    public String getProperty(String key) {
+        return properties.getProperty(key);
+    }
+
+    /**
+     * @see java.util.Properties#getProperty(java.lang.String, java.lang.String)
+     */
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        return properties.getProperty(key, defaultValue);
+    }
+
+    /**
+     * @see java.util.Hashtable#hashCode()
+     */
+    @Override
+    public synchronized int hashCode() {
+        return properties.hashCode();
+    }
+
+    /**
+     * @see java.util.Hashtable#isEmpty()
+     */
+    @Override
+    public synchronized boolean isEmpty() {
+        return properties.isEmpty();
+    }
+
+    /**
+     * @see java.util.Hashtable#keys()
+     */
+    @Override
+    public synchronized Enumeration<Object> keys() {
+        return properties.keys();
+    }
+
+    /**
+     * @see java.util.Hashtable#keySet()
+     */
+    @Override
+    public Set<Object> keySet() {
+        return Collections.unmodifiableSet(properties.keySet());
+    }
+
+    /**
+     * @see java.util.Properties#list(java.io.PrintStream)
+     */
+    @Override
+    public void list(PrintStream out) {
+        properties.list(out);
+    }
+
+    /**
+     * @see java.util.Properties#list(java.io.PrintWriter)
+     */
+    @Override
+    public void list(PrintWriter out) {
+        properties.list(out);
+    }
+
+    /**
+     * @see java.util.Properties#load(java.io.InputStream)
+     */
+    @Override
+    public synchronized void load(InputStream inStream) throws IOException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#load(java.io.Reader)
+     */
+    @Override
+    public synchronized void load(Reader reader) throws IOException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#loadFromXML(java.io.InputStream)
+     */
+    @Override
+    public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#propertyNames()
+     */
+    @Override
+    public Enumeration<?> propertyNames() {
+        return properties.propertyNames();
+    }
+
+    /**
+     * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#putAll(java.util.Map)
+     */
+    @Override
+    public synchronized void putAll(Map<? extends Object, ? extends Object> t) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#rehash()
+     */
+    @Override
+    protected void rehash() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#remove(java.lang.Object)
+     */
+    @Override
+    public synchronized Object remove(Object key) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#save(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    @Deprecated
+    public synchronized void save(OutputStream out, String comments) {
+        properties.save(out, comments);
+    }
+
+    /**
+     * @see java.util.Properties#setProperty(java.lang.String, java.lang.String)
+     */
+    @Override
+    public synchronized Object setProperty(String key, String value) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#size()
+     */
+    @Override
+    public synchronized int size() {
+        return properties.size();
+    }
+
+    /**
+     * @see java.util.Properties#store(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    public void store(OutputStream out, String comments) throws IOException {
+        properties.store(out, comments);
+    }
+
+    /**
+     * @see java.util.Properties#store(java.io.Writer, java.lang.String)
+     */
+    @Override
+    public void store(Writer writer, String comments) throws IOException {
+        properties.store(writer, comments);
+    }
+
+    /**
+     * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    public synchronized void storeToXML(OutputStream os, String comment) throws IOException {
+        properties.storeToXML(os, comment);
+    }
+
+    /**
+     * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String, java.lang.String)
+     */
+    @Override
+    public synchronized void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
+        properties.storeToXML(os, comment, encoding);
+    }
+
+    /**
+     * @see java.util.Properties#stringPropertyNames()
+     */
+    @Override
+    public Set<String> stringPropertyNames() {
+        return properties.stringPropertyNames();
+    }
+
+    /**
+     * @see java.util.Hashtable#toString()
+     */
+    @Override
+    public synchronized String toString() {
+        return properties.toString();
+    }
+
+    /**
+     * @see java.util.Hashtable#values()
+     */
+    @Override
+    public Collection<Object> values() {
+        return Collections.unmodifiableCollection(properties.values());
+    }
+}
diff --git a/appc-core/appc-common-bundle/java/org/onap/appc/util/httpClient.java b/appc-core/appc-common-bundle/java/org/onap/appc/util/httpClient.java
new file mode 100644 (file)
index 0000000..a2ce8af
--- /dev/null
@@ -0,0 +1,205 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.onap.appc.configuration.Configuration;
+import org.onap.appc.configuration.ConfigurationFactory;
+import org.onap.appc.exceptions.APPCException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+
+public class httpClient {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(httpClient.class);
+
+    private static Configuration configuration = ConfigurationFactory.getConfiguration();
+
+    @SuppressWarnings("deprecation")
+    public static int postMethod(String protocol, String ip, int port, String path, String payload,
+            String contentType) throws APPCException {
+
+        logger.info("Sending POST request to " + path);
+
+        HttpPost post;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            post = new HttpPost(serviceUrl.toExternalForm());
+            post.setHeader("Content-Type", contentType);
+
+            StringEntity entity = new StringEntity(payload);
+            entity.setContentType(contentType);
+            post.setEntity(new StringEntity(payload));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + post);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        try {
+            HttpResponse response = client.execute(post);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+        return httpCode;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int putMethod(String protocol, String ip, int port, String path, String payload,
+            String contentType) throws APPCException {
+
+        logger.info("Sending PUT request to " + path);
+
+        HttpPut put;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            put = new HttpPut(serviceUrl.toExternalForm());
+            put.setHeader("Content-Type", contentType);
+
+            StringEntity entity = new StringEntity(payload);
+            entity.setContentType(contentType);
+            put.setEntity(new StringEntity(payload));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + put);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        try {
+            HttpResponse response = client.execute(put);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+        return httpCode;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static String getMethod(String protocol, String ip, int port, String path,
+            String contentType) throws APPCException {
+
+        logger.info("Sending GET request to " + path);
+
+        HttpGet get;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            get = new HttpGet(serviceUrl.toExternalForm());
+            get.setHeader("Content-Type", contentType);
+        } catch (MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + get);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        String result;
+
+        try {
+            HttpResponse response = client.execute(get);
+            httpCode = response.getStatusLine().getStatusCode();
+            result = (httpCode == HttpStatus.SC_OK) ? response.getEntity().toString() : null;
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+
+        return result;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int deleteMethod(String protocol, String ip, int port, String path,
+            String contentType) throws APPCException {
+
+        logger.info("Sending DELETE request to " + path);
+
+        HttpDelete delete;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            delete = new HttpDelete(serviceUrl.toExternalForm());
+            delete.setHeader("Content-Type", contentType);
+        } catch (MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + delete);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+
+        try {
+            HttpResponse response = client.execute(delete);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+
+        return httpCode;
+    }
+}
diff --git a/appc-core/appc-common-bundle/pom.xml b/appc-core/appc-common-bundle/pom.xml
new file mode 100644 (file)
index 0000000..0f72a16
--- /dev/null
@@ -0,0 +1,160 @@
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  --><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+  <parent>\r
+      <groupId>org.onap.appc.parent</groupId>\r
+      <artifactId>binding-parent</artifactId>        \r
+      <version>1.4.0-SNAPSHOT</version>\r
+  </parent>\r
+  \r
+  <groupId>org.onap.appc</groupId>\r
+  <artifactId>appc-common-bundle</artifactId>\r
+  <packaging>bundle</packaging>\r
+  \r
+  <dependencies>\r
+    <!--  logging  -->\r
+    <dependency>\r
+      <groupId>com.att.eelf</groupId>\r
+      <artifactId>eelf-core</artifactId>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.slf4j</groupId>\r
+      <artifactId>slf4j-api</artifactId>\r
+      <scope>provided</scope>\r
+    </dependency>\r
+\r
+    <!-- encryption -->\r
+    \r
+    <dependency>\r
+           <groupId>org.apache.servicemix.bundles</groupId>\r
+           <artifactId>org.apache.servicemix.bundles.jasypt</artifactId>\r
+           <version>1.9.2_1</version>\r
+    </dependency>\r
+\r
+    <!-- Web framework -->\r
+    <dependency>\r
+        <groupId>org.apache.commons</groupId>\r
+        <artifactId>commons-lang3</artifactId>\r
+    </dependency>\r
+\r
+    <dependency>\r
+      <groupId>com.fasterxml.jackson.core</groupId>\r
+      <artifactId>jackson-core</artifactId>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>com.fasterxml.jackson.core</groupId>\r
+      <artifactId>jackson-databind</artifactId>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>com.fasterxml.jackson.core</groupId>\r
+      <artifactId>jackson-annotations</artifactId>\r
+    </dependency>\r
+\r
+    <!--  CCSDK components -->\r
+    <dependency>\r
+      <groupId>org.onap.ccsdk.sli.core</groupId>\r
+      <artifactId>dblib-provider</artifactId>\r
+      <scope>provided</scope>\r
+       <exclusions>\r
+               <exclusion>\r
+                       <groupId>equinoxSDK381</groupId>\r
+                       <artifactId>org.eclipse.osgi</artifactId>\r
+               </exclusion>\r
+       </exclusions>\r
+    </dependency>\r
+    \r
+    <!--  TEST DEPENDENCIES -->\r
+    <dependency>\r
+      <groupId>junit</groupId>\r
+      <artifactId>junit</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.mockito</groupId>\r
+      <artifactId>mockito-core</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.powermock</groupId>\r
+      <artifactId>powermock-reflect</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.powermock</groupId>\r
+      <artifactId>powermock-module-junit4</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.powermock</groupId>\r
+      <artifactId>powermock-api-mockito</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+  </dependencies>\r
+  \r
+  <build>\r
+    <plugins>\r
+      <plugin>\r
+            <groupId>com.att.eelf</groupId>\r
+            <artifactId>eelf-maven-plugin</artifactId>\r
+            <version>1.0.0</version>\r
+            <executions>\r
+              <execution>\r
+                <id>validation</id>\r
+                <phase>install</phase>\r
+                <goals>\r
+                  <goal>ValidateApplicationMsgs</goal>\r
+                </goals>\r
+                <configuration>\r
+                  <resources>\r
+                    <resource>\r
+                      <messageClass>org.onap.appc.i18n.Msg</messageClass>\r
+                    </resource>\r
+                  </resources>\r
+                </configuration>\r
+              </execution>\r
+              <execution>\r
+                <id>generate</id>\r
+                <phase>install</phase>\r
+                <goals>\r
+                  <goal>WikiMsgGenerator</goal>\r
+                </goals>\r
+                <configuration>\r
+                  <outputDirectory>target/messages</outputDirectory>\r
+                  <outputFile>messages.html</outputFile>\r
+                  <resources>\r
+                    <resource>\r
+                      <messageClass>org.onap.appc.i18n.Msg</messageClass>\r
+                      <header><![CDATA[<p> <ac:macro ac:name="toc" /> </p>]]></header>\r
+                    </resource>\r
+                  </resources>\r
+                </configuration>\r
+              </execution>\r
+            </executions>\r
+            <dependencies>\r
+              <dependency>\r
+                <groupId>org.onap.appc</groupId>\r
+                <artifactId>appc-common-bundle</artifactId>\r
+                <version>${project.version}</version>\r
+              </dependency>\r
+            </dependencies>\r
+          </plugin>\r
+    </plugins>  \r
+  </build>\r
+</project>
\ No newline at end of file
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/CmdLine.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/CmdLine.java
new file mode 100644 (file)
index 0000000..0203dff
--- /dev/null
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc;
+
+import org.onap.appc.encryption.EncryptionTool;
+
+public class CmdLine {
+
+        public static void main(String[] args) {
+
+            if (args.length < 1) {
+                printUsage();
+                return;
+            }
+
+            String command = args[0];//first parameter
+
+            if (0 == command.compareTo("encrypt") && args.length == 2)//two parameters are required
+            {
+                String clearText = args[1];
+                String encrypted = EncryptionTool.getInstance().encrypt(clearText);
+                System.out.println(encrypted);
+                return;
+            } else {
+                printUsage();
+            }
+        }
+        
+        private static void printUsage(){
+            System.out.println("Usage: java -jar <this jar> ...");
+            System.out.println("\tencrypt <your text> \t\t(Encrypts your text)");
+        }
+}
\ No newline at end of file
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/Constants.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/Constants.java
new file mode 100644 (file)
index 0000000..c1a306a
--- /dev/null
@@ -0,0 +1,209 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc;
+
+/**
+ * This class contains the definitions of all constant values used in the APPC provider, adapters, and other components.
+ * These constants define properties, settings, and context variables. The context variables can be referenced from
+ * within the directed graph(s) to access information placed their by the provider and adapters.
+ * <p>
+ * Context properties are set in the graph context by the various adapters and the provider, or by the graph itself.
+ * These properties may also be accessed by the graph, adapters, or the provider. It is these properties that allow
+ * communication of state through the directed graph. All context properties have a symbolic name that starts with
+ * "CONTEXT_".
+ * </p>
+ *
+ */
+
+public final class Constants {
+
+    /**
+     * The name for the error code attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_ERROR_CODE = "error_code";
+
+    /**
+     * The name for the error message attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_ERROR_MESSAGE = "error-message";
+
+    /**
+     * The name for the success message attribute to be set in the context
+     */
+    @SuppressWarnings("nls")
+    public static final String ATTRIBUTE_SUCCESS_MESSAGE = "success-message";
+
+    public static final String DG_ATTRIBUTE_STATUS = "SvcLogic.status";
+    public static final String DG_OUTPUT_STATUS_CODE = "output.status.code";
+    public static final String DG_OUTPUT_STATUS_MESSAGE = "output.status.message";
+
+    /**
+     * The property that defines the name of the DG service logic to be loaded
+     */
+    public static final String PROPERTY_MODULE_NAME = "appc.service.logic.module.name";
+
+    /**
+     * The property that defines the topology restart DG version to be used
+     */
+    public static final String PROPERTY_TOPOLOGY_VERSION = "appc.topology.dg.version";
+
+    /**
+     * The method name of the DG that is used to perform topology restart operations
+     */
+    public static final String PROPERTY_TOPOLOGY_METHOD = "appc.topology.dg.method";
+
+    /**
+     * The property that supplies the application name
+     */
+    public static final String PROPERTY_APPLICATION_NAME = "appc.application.name";
+
+    /**
+     * The execution mode for the directed graph
+     */
+    public static final String SYNC_MODE = "sync";
+
+    /**
+     * The name of the property that contains the service request enumerated value in the graph's context
+     */
+    public static final String CONTEXT_SERVICE = "org.onap.appc.service";
+
+    /**
+     * The name of the property that contains the VM id value in the graph's context
+     */
+    public static final String CONTEXT_VMID = "org.onap.appc.vmid";
+
+    /**
+     * The name of the property that contains the VM id value in the graph's context
+     */
+    public static final String CONTEXT_IDENTITY_URL = "org.onap.appc.identity.url";
+
+    /**
+     * The name of the property that contains the service request id value in the graph's context
+     */
+    public static final String CONTEXT_REQID = "org.onap.appc.reqid";
+
+    /**
+     * The name of the property that indicates which method of the IaaS adapter to call
+     */
+    public static final String CONTEXT_ACTION = "org.onap.appc.action";
+
+    /**
+     * The enumerated value for restart of a VM. This is a constant for one possible value of CONTEXT_SERVICE.
+     */
+    public static final String SERVICE_RESTART = "RESTART";
+
+    /**
+     * The enumerated value for rebuild of a VM. This is a constant for one possible value of CONTEXT_SERVICE.
+     */
+    public static final String SERVICE_REBUILD = "REBUILD";
+
+    /**
+     * The name of the adapter. We get the name from a property file so that it can be changed easily if needed.
+     */
+    public static final String PROPERTY_ADAPTER_NAME = "org.onap.appc.provider.adaptor.name";
+
+    /**
+     * The minimum number of contexts to cache in each provider/tenant pool
+     */
+    public static final String PROPERTY_MIN_POOL_SIZE = "org.onap.appc.provider.min.pool";
+
+    /**
+     * The maximum number of contexts to cache in each provider/tenant pool
+     */
+    public static final String PROPERTY_MAX_POOL_SIZE = "org.onap.appc.provider.max.pool";
+
+    /**
+     * The amount of time, in seconds, that the application waits for a change of state of a server to a known valid
+     * state before giving up and failing the request.
+     */
+    public static final String PROPERTY_SERVER_STATE_CHANGE_TIMEOUT = "org.onap.appc.server.state.change.timeout";
+
+    /**
+     * The amount of time, in seconds, between subsequent polls to the openstack provider to update the state of a
+     * resource
+     */
+    public static final String PROPERTY_OPENSTACK_POLL_INTERVAL = "org.onap.appc.openstack.poll.interval";
+
+    /**
+     * The amount of time, in seconds, to wait between retry attempts when a connection to a provider fails.
+     */
+    public static final String PROPERTY_RETRY_DELAY = "org.onap.appc.provider.retry.delay";
+
+    /**
+     * The maximum number of times a connection retry will be attempted before the application fails the request
+     */
+    public static final String PROPERTY_RETRY_LIMIT = "org.onap.appc.provider.retry.limit";
+    /**
+     * The amount of time, in seconds, that the application waits for a change of state of a stacj to a known valid
+     * state before giving up and failing the request.
+     */
+    public static final String PROPERTY_STACK_STATE_CHANGE_TIMEOUT ="org.onap.appc.stack.state.change.timeout" ;
+
+    @SuppressWarnings("nls")
+    public static final String STATUS_GETTER = "status-getter";
+
+    @SuppressWarnings("nls")
+    public static final String VM_FUSION_STATUS_GETTER = "fusion-vm-status-getter";
+
+    /**
+     * The name for the status vm attribute to be set in the context when executing a vmstatuscheck.
+     */
+    @SuppressWarnings("nls")
+    public static final String STATUS_OF_VM = "status-vm";
+
+    /**
+     * Yang revision value to be used while generating YANG module
+     */
+    public static final String YANG_REVISION = "2017-03-03";
+    /**
+     * Yang revision format to be used while formatting YANG revision date
+     */
+    public static final String YANG_REVISION_FORMAT = "YYYY-MM-DD";
+
+    /**
+     * Base container for  yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_BASE_CONTAINER = "vnf-config-repo";
+
+    /**
+     *VNF config list for yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_VNF_CONFIG_LIST = "vnf-config-list";
+
+    /**
+     *Base container of VNF configuration data for yang that is generated to store in MD-SAL datastore
+     */
+    public static final String YANG_VNF_CONFIG = "vnf-config";
+
+    /**
+     * default constructor prevents instantiation
+     */
+    Constants() {
+        throw new IllegalAccessError("Constants");
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategies.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategies.java
new file mode 100644 (file)
index 0000000..12f3686
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Enum of CacheStrategies
+ */
+public enum CacheStrategies {
+    LRU
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategy.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/CacheStrategy.java
new file mode 100644 (file)
index 0000000..8976a20
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Interface of CacheStrategy
+ * @param <K> key
+ * @param <V> value
+ */
+public interface CacheStrategy <K,V> {
+    /**
+     * Get object
+     * @param key of the object
+     * @return value of the object
+     */
+    V getObject(K key);
+
+    /**
+     * Put object
+     * @param key of the object
+     * @param value of the object
+     */
+    void putObject(K key,V value);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/MetadataCache.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/MetadataCache.java
new file mode 100644 (file)
index 0000000..caf319a
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+/**
+ * Interface of MetadataCache
+ * @param <K> key
+ * @param <V> value
+ */
+public interface MetadataCache <K,V> {
+    /**
+     * Get object
+     * @param key of the object
+     * @return value of the object
+     */
+    V getObject(K key);
+
+    /**
+     * Put object
+     * @param key of the object
+     * @param value of the object
+     */
+    void putObject(K key,V value);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/LRUCache.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/LRUCache.java
new file mode 100644 (file)
index 0000000..c88439c
--- /dev/null
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.onap.appc.cache.CacheStrategy;
+
+/**
+ * LRU cache implements CacheStategy<K, V>
+ * @param <K> Key
+ * @param <V> Value
+ */
+public class LRUCache<K,V> implements CacheStrategy<K,V> {
+
+    private Map<K,V> map;
+
+    LRUCache(final Integer capacity){
+        map = new LinkedHashMap<K,V>(capacity, 0.75F, true) {
+            @Override
+            protected boolean removeEldestEntry(Map.Entry<K, V> eldest){
+                return size() > capacity;
+            }
+        };
+    }
+
+    @Override
+    public V getObject(K key) {
+        return map.get(key);
+    }
+
+    @Override
+    public void putObject(K key, V value) {
+        map.put(key,value);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheFactory.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheFactory.java
new file mode 100644 (file)
index 0000000..b6398e8
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import org.onap.appc.cache.CacheStrategies;
+import org.onap.appc.cache.MetadataCache;
+
+/**
+ * Metadata Cache Factory
+ */
+public class MetadataCacheFactory {
+
+    private static class ReferenceHolder {
+        private ReferenceHolder() {
+            throw new IllegalAccessError("ReferenceHolder");
+        }
+
+        private static final MetadataCacheFactory FACTORY = new MetadataCacheFactory();
+    }
+
+    private MetadataCacheFactory() {
+        // do nothing
+    }
+
+    public static MetadataCacheFactory getInstance(){
+        return ReferenceHolder.FACTORY;
+    }
+
+    public MetadataCache getMetadataCache(){
+        return new MetadataCacheImpl();
+    }
+
+    /**
+     * Get MetadataCache
+     * @param cacheStrategy the CacheStrategies to be used to build MetadataCacheImpl
+     * @return a new instance of MetadataCacheImpl
+     */
+    public MetadataCache getMetadataCache(CacheStrategies cacheStrategy) {
+        return new MetadataCacheImpl(cacheStrategy);
+    }
+
+
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheImpl.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/cache/impl/MetadataCacheImpl.java
new file mode 100644 (file)
index 0000000..92b70c9
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import org.onap.appc.cache.CacheStrategies;
+import org.onap.appc.cache.CacheStrategy;
+import org.onap.appc.cache.MetadataCache;
+
+/**
+ * Implementation of MetadataCache
+ * @param <K> Key
+ * @param <V> Value
+ */
+public class MetadataCacheImpl<K,V> implements MetadataCache<K,V> {
+
+    private CacheStrategy strategy;
+
+    MetadataCacheImpl(){
+        this(CacheStrategies.LRU);
+    }
+
+    MetadataCacheImpl(CacheStrategies strategy){
+        this.strategy = initializeStrategy(strategy);
+    }
+
+    private CacheStrategy initializeStrategy(CacheStrategies strategy) {
+        if (strategy != null) {
+            switch (strategy) {
+                case LRU:
+                    return new LRUCache<>(50);
+                default:
+                    // do nothing
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public V getObject(K key) {
+        return (V)strategy.getObject(key);
+    }
+
+    @Override
+    public void putObject(K key, V value) {
+        strategy.putObject(key, value);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/concurrent/Signal.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/concurrent/Signal.java
new file mode 100644 (file)
index 0000000..2daa0cf
--- /dev/null
@@ -0,0 +1,230 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.concurrent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.onap.appc.util.StringHelper;
+
+/**
+ * This class is used to synchronize signaling of status between threads.
+ * <p>
+ * In complex multi-threaded applications it is often necessary to synchronize operations between threads. This is
+ * especially true in complex algorithms where processing dependencies exist between different threads and the
+ * synchronization of the operations of those threads is required. This class is a framework to enable multi-thread
+ * signaling and wait/post logic that makes the thread synchronization easier.
+ * </p>
+ * <p>
+ * Basically, in thread synchronization, one thread is the "waiter" and one or more other threads are the "notifiers".
+ * The notifiers send signals to the waiter to inform that thread that certain conditions are true, processing has been
+ * completed, or to inform the waiter of the state of the other thread(s). In the basic java framework, the waiter and
+ * notifier are simply using the wait/notify mechanism provided, which does not allow for different conditions, state,
+ * or "signals" to exist. The wait/notify mechanism, in combination with the object mutex, provides basic blocking and
+ * releasing of a thread's dispatching state.
+ * </p>
+ * <p>
+ * This class builds upon the java wait/notify mechanism and allows for "signals" to be defined. These signals are
+ * simply string constants that mean something to the waiter and notifier threads. Any number of signals may be defined,
+ * and it is possible to wait for more than one signal to be received, wait for any one of a set to be received, or to
+ * test if a signal has been received without blocking.
+ * </p>
+ * <p>
+ * Some operations are blocking operations. These stop the execution of the calling thread until the specified condition
+ * is true. These blocking methods are all named "wait...", such as {@link #waitFor(String...)} and
+ * {@link #waitForAny(String...)}. The thread making the call to these blocking methods MUST be the waiter thread (the
+ * thread registered with the signal object).
+ * </p>
+ * <p>
+ * Some operations are non-blocking. These operations allow for the testing or setting of signal conditions and do not
+ * block the caller. When calling these methods ({@link #isSignaled(String)}, {@link #signal(String)}, and
+ * {@link #setTimeout(long)} the waiter thread mutex will be held and may block the waiter thread for the duration of
+ * the method call.
+ * </p>
+ */
+public class Signal {
+
+    /**
+     * The thread must be the thread of the waiter that is waiting for the signals to be received. It is the recipient
+     * of the signaled condition. This allows any number of other threads to send signals to the recipient and have the
+     * recipient synchronize its operation with the receipt of the appropriate signal(s).
+     */
+    private Thread thread;
+
+    /**
+     * The amount of time to wait for a signal to be receieved. Set to zero to wait forever.
+     */
+    private long timeout = 0L;
+
+    /**
+     * The collection of all received signals. Note, this need not be a synchronized collection because it will always
+     * be accessed while holding the mutex of the thread, therefore it is implicitly synchronized.
+     */
+    private List<String> receivedSignals;
+
+    /**
+     * A signal object must access a thread that is waiting for the receipt of the signal(s).
+     */
+    public Signal(Thread thread) {
+        this.thread = thread;
+        receivedSignals = new ArrayList<String>();
+    }
+
+    /**
+     * Checks the waiter to see if it has been signaled
+     * 
+     * @param signal
+     *            The signal to check for
+     * @return True if the signal has been received, false otherwise
+     */
+    public boolean isSignaled(String signal) {
+        synchronized (thread) {
+            return _signaled(signal);
+        }
+    }
+
+    /**
+     * Sends the indicated signal to the waiter.
+     * 
+     * @param signal
+     *            The signal that is to be sent to the waiting thread and to notify it to process the signal.
+     */
+    public void signal(String signal) {
+        synchronized (thread) {
+            if (!_signaled(signal)) {
+                receivedSignals.add(signal);
+            }
+            thread.notify();
+        }
+    }
+
+    /**
+     * Blocks the waiting thread until all of the indicated signals have been received, or the wait times out.
+     * 
+     * @param signals
+     *            The signals to be received. The waiter is blocked forever or until all of the signals are received.
+     * @throws TimeoutException
+     *             If the wait has timed out waiting for a response
+     */
+    public void waitFor(String... signals) throws TimeoutException {
+        long limit = System.currentTimeMillis() + timeout;
+        synchronized (thread) {
+            while (true) {
+                boolean complete = true;
+                for (String signal : signals) {
+                    if (!_signaled(signal)) {
+                        complete = false;
+                    }
+                }
+
+                if (complete) {
+                    receivedSignals.removeAll(Arrays.asList(signals));
+                    return;
+                }
+
+                if (timeout > 0) {
+                    if (System.currentTimeMillis() > limit) {
+                        throw new TimeoutException(String.format("Signals %s not received in the allotted timeout.",
+                            StringHelper.asList(signals)));
+                    }
+                }
+
+                try {
+                    thread.wait(timeout);
+                } catch (InterruptedException e) {
+                    /*
+                     * Interrupted exceptions are ignored
+                     */
+                }
+            }
+        }
+    }
+
+    /**
+     * This method blocks the waiter until at least one of the indicated signals have been received.
+     * 
+     * @param signals
+     *            A list of signals, any one of which will satisfy the wait condition
+     * @return The signal that satisfied the wait
+     * @throws TimeoutException
+     *             If none of the signals have been received within the allotted time
+     */
+    public String waitForAny(String... signals) throws TimeoutException {
+        long limit = System.currentTimeMillis() + timeout;
+        synchronized (thread) {
+            while (true) {
+                for (String signal : signals) {
+                    if (!_signaled(signal)) {
+                        receivedSignals.remove(signal);
+                        return signal;
+                    }
+                }
+
+                if (timeout > 0) {
+                    if (System.currentTimeMillis() > limit) {
+                        throw new TimeoutException(
+                            String.format("One of signals \"%s\" not received in the allotted timeout.",
+                                StringHelper.asList(signals)));
+                    }
+                }
+
+                try {
+                    thread.wait(timeout);
+                } catch (InterruptedException e) {
+                    /*
+                     * Interrupted exceptions are ignored
+                     */
+                }
+            }
+        }
+    }
+
+    /**
+     * This private method is used to handle the check for signaled status. Note that this method assumes the caller
+     * holds the thread mutex.
+     * 
+     * @param signals
+     *            The list of signals to check for
+     * @return True if any one of the signals has been received.
+     */
+    private boolean _signaled(String... signals) {
+        for (String signal : signals) {
+            if (receivedSignals.contains(signal)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets the timeout value for waiting for signals to be received
+     * 
+     * @param timeout
+     */
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/Configuration.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/Configuration.java
new file mode 100644 (file)
index 0000000..0cc3f26
--- /dev/null
@@ -0,0 +1,242 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+
+
+
+/**
+ * This interface defines the common configuration support that is available to the application.
+ * <p>
+ * Where properties are common to all CDP components (server, coordinator, and EPM), the property symbolic values are
+ * defined as part of this interface. Where they are unique to each component, they must be defined within that
+ * component.
+ * </p>
+ */
+public interface Configuration {
+
+    String PROPERTY_BOOTSTRAP_FILE_NAME = "org_onap_appc_bootstrap_file"; //
+    String DEFAULT_BOOTSTRAP_FILE_NAME = "appc.properties"; 
+    String PROPERTY_BOOTSTRAP_FILE_PATH = "org_onap_appc_bootstrap_path"; //
+    String DEFAULT_BOOTSTRAP_FILE_PATH = "/opt/onap/appc/data/properties,${user.home},etc,../etc";
+    String PROPERTY_RESOURCE_BUNDLES = "org.onap.appc.resources"; 
+    String DEFAULT_RESOURCE_BUNDLES = "org/onap/appc/i18n/MessageResources";
+
+   /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
+     * {@link Boolean#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property key
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    boolean getBooleanProperty(String key);
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The standard rules for
+     * {@link Boolean#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property key
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    boolean getBooleanProperty(String key, boolean defaultValue);
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value (double). The standard
+     * rules for {@link Double#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property to retrieve
+     * @return The value of the property, or 0.0 if not found or invalid
+     */
+    double getDoubleProperty(String key);
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value (double). The standard
+     * rules for {@link Double#valueOf(String)} are used.
+     * 
+     * @param key
+     *            The property to retrieve
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property, or 0.0 if not found or invalid
+     */
+    double getDoubleProperty(String key, double defaultValue);
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     * 
+     * @param key
+     *            The property name to retrieve.
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     */
+    int getIntegerProperty(String key);
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     * 
+     * @param key
+     *            The property name to retrieve.
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     */
+    int getIntegerProperty(String key, int defaultValue);
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or zero if it does not.
+     * 
+     * @param key
+     *            The key of the property desired.
+     * @return The value of the property expressed as an integer long value, or zero if the property does not exist or
+     *         is not a valid integer long.
+     */
+    long getLongProperty(String key);
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or the default value if it does not exist
+     * or is invalid.
+     * 
+     * @param key
+     *            The key of the property desired.
+     * @param defaultValue
+     *            the value to be returned if the property is not valid or does not exist.
+     * @return The value of the property expressed as an integer long value, or the default value if the property does
+     *         not exist or is not a valid integer long.
+     */
+    long getLongProperty(String key, long defaultValue);
+
+    /**
+     * This method can be called to retrieve a properties object that is immutable. Any attempt to modify the properties
+     * object returned will result in an exception. This allows a caller to view the current configuration as a set of
+     * properties.
+     * 
+     * @return An unmodifiable properties object.
+     */
+    Properties getProperties();
+
+    /**
+     * This method is called to obtain a property as a string value
+     * 
+     * @param key
+     *            The key of the property
+     * @return The string value, or null if it does not exist.
+     */
+    String getProperty(String key);
+
+    /**
+     * This method is called to obtain a property as a string value
+     * 
+     * @param key
+     *            The key of the property
+     * @param defaultValue
+     *            The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     */
+    String getProperty(String key, String defaultValue);
+
+    /**
+     * Returns true if the named property is defined, false otherwise.
+     * 
+     * @param key
+     *            The key of the property we are interested in
+     * @return True if the property exists.
+     */
+    boolean isPropertyDefined(String key);
+
+    /**
+     * Returns an indication of the validity of the boolean property. A boolean property is considered to be valid only
+     * if it has the value "true" or "false" (ignoring case).
+     * 
+     * @param key
+     *            The property to be checked
+     * @return True if the value is a boolean constant, or false if it does not exist or is not a correct string
+     */
+    boolean isValidBoolean(String key);
+
+    /**
+     * Returns an indication if the indicated property represents a valid double-precision floating point number.
+     * 
+     * @param key
+     *            The property to be examined
+     * @return True if the property is a valid representation of a double, or false if it does not exist or contains
+     *         illegal characters.
+     */
+    boolean isValidDouble(String key);
+
+    /**
+     * Returns an indication if the property is a valid integer value or not.
+     * 
+     * @param key
+     *            The key of the property to check
+     * @return True if the value is a valid integer string, or false if it does not exist or contains illegal
+     *         characters.
+     */
+    boolean isValidInteger(String key);
+
+    /**
+     * Determines is the specified property exists and is a valid representation of an integer long value.
+     * 
+     * @param key
+     *            The property to be checked
+     * @return True if the property is a valid representation of an integer long value, and false if it either does not
+     *         exist or is not valid.
+     */
+    boolean isValidLong(String key);
+
+    /**
+     * This method allows the caller to set all properties from a provided properties object into the configuration
+     * property set.
+     * <p>
+     * The primary difference between this method and the factory method
+     * {@link ConfigurationFactory#getConfiguration(Properties)} is that this method does not clear and reload the
+     * configuration. Rather, this method merges the provided properties object contents into the existing properties,
+     * replacing any same-named keys with the values from this object.
+     * </p>
+     * 
+     * @param properties
+     *            The properties object to copy all properties from
+     */
+    void setProperties(Properties properties);
+
+    /**
+     * This method allows a caller to insert a new property definition into the configuration object. This allows the
+     * application to adjust or add to the current configuration. If the property already exists, it is replaced with
+     * the new value.
+     * 
+     * @param key
+     *            The key of the property to be defined
+     * @param value
+     *            The value of the property to be defined
+     */
+    void setProperty(String key, String value);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/ConfigurationFactory.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/ConfigurationFactory.java
new file mode 100644 (file)
index 0000000..9ea5083
--- /dev/null
@@ -0,0 +1,433 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+import org.onap.appc.i18n.Msg;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.i18n.EELFResourceManager;
+
+/**
+ * The configuration factory is used to obtain access to an already created and initialized
+ * singleton configuration object as well as to create and initialize the singleton if not already
+ * set up.
+ * <p>
+ * This class is responsible for the creation of the configuration object used to manage the
+ * configuration of the application. The configuration object implementation must implement the
+ * <code>Configuration</code> interface. This allows for the factory to create different
+ * specializations in the future if needed and not break any application code.
+ * </p>
+ * <p>
+ * The configuration object is basically a wrapper around a properties object. The configuration is
+ * therefore specified as a set of properties that are loaded and processed from different sources
+ * with different precedences. It is important that the configuration object always be able to
+ * supply default values for any configuration properties that must be supplied, and not rely on the
+ * user always supplying these values. This also relieves the application itself from having to
+ * interpret missing or invalid properties and applying defaults. By having all of the defaults in
+ * one place, the application code can be simpler (not having to worry about defaults or invalid
+ * properties), and the defaults can be changed much easier (they are all in one place and not
+ * distributed throughout the codebase).
+ * </p>
+ * <p>
+ * Since the configuration is managed as a property object, we can use a characteristic of the
+ * <code>Properties</code> class to our advantage. Namely, if we put a property into a
+ * <code>Properties</code> object that already exists, the <code>Properties</code> object replaces
+ * it with the new value. This does not affect any other properties that may already be defined in
+ * the properties object. This gives us the ability to initialize the properties with default values
+ * for all of the application settings, then override just those that we need to override, possibly
+ * from multiple sources and in increasing order of precedence.
+ * </p>
+ * <p>
+ * This means that properties are in effect "merged" together from multiple sources in a prescribed
+ * precedence order. In fact, the precedence order that this factory implements is defined as:
+ * </p>
+ * <ol>
+ * <li>Default values from a system resource file.</li>
+ * <li>User-supplied properties file, if any.</li>
+ * <li>Application-supplied properties, if any.</li>
+ * <li>Command-line properties (if any)</li>
+ * </ol>
+ * <p>
+ * The name and location of the properties file that is loaded can also be set, either in the
+ * defaults, overridden by the system command line via -D, or as a system environment variable.
+ * There are two properties that can be specified to define the name and path. These are:
+ * </p>
+ * <dl>
+ * <dt>org.onap.appc.bootstrap.file</dt>
+ * <dd>This property defines the name of the file that will be loaded. If not specified, the default
+ * value is "appc.properties". This can be specified in either (or both) the default properties or
+ * the command line. The command line specification will always override.</dd>
+ * <dt>org.onap.appc.bootstrap.path</dt>
+ * <dd>This is a comma-delimited (,) path of directories to be searched to locate the specified
+ * file. The first occurrence of the file is the one loaded, and no additional searching is
+ * performed. The path can be specified in either, or both, the default values and the command line
+ * specification. If specified on the command line, the value overrides the default values. If
+ * omitted, the default path is <code>$/opt/onap/appc/data/properties,${user.home},.</code></dd>
+ * </dl>
+ *
+ * @since Mar 18, 2014
+ * @version $Id$
+ */
+public final class ConfigurationFactory {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(ConfigurationFactory.class);
+
+    /**
+     * This is a string constant for the comma character. It's intended to be used a common string
+     * delimiter.
+     */
+    private static final String COMMA = ",";
+
+    /**
+     * The default Configuration object that implements the <code>Configuration</code> interface and
+     * represents our system configuration settings.
+     */
+    private static DefaultConfiguration config = null;
+
+    /**
+     * The default properties resource to be loaded
+     */
+    private static final String DEFAULT_PROPERTIES = "org/onap/appc/default.properties";
+
+    /**
+     * This collection allows for special configurations to be created and maintained, organized by
+     * some identification (such as an object reference to the StackBuilder to which they apply),
+     * and then obtained from the configuration factory when needed.
+     */
+    private static HashMap<Object, Configuration> localConfigs = new HashMap<>();
+
+    /**
+     * The reentrant shared lock used to serialize access to the properties.
+     */
+    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+    /**
+     * This is a constant array of special property names that will be copied from the configuration
+     * back to the System properties object if they are defined in the configuration AND they do not
+     * already exist in the System properties object. These are intended as a convenience for
+     * setting the AFT properties for the Discovery client where it may be difficult or impossible
+     * to set VM arguments for the container.
+     */
+    private static final String[] specialProperties =
+            {"AFT_LATITUDE", "AFT_LONGITUDE", "AFT_ENVIRONMENT", "SCLD_PLATFORM"};
+
+    private ConfigurationFactory() {}
+
+    /**
+     * This method is used to obtain the common configuration object (as well as set it up if not
+     * already).
+     *
+     * @return The configuration object implementation
+     */
+    public static Configuration getConfiguration() {
+
+        /*
+         * First, attempt to access the properties as a read lock holder
+         */
+        ReadLock readLock = lock.readLock();
+        readLock.lock();
+        try {
+
+            /*
+             * If the properties don't exist, release the read lock and acquire the write lock. Once
+             * we get the write lock, we need to re-check to see that the configuration needs to be
+             * set up (because another thread may have beat us to it). After we get a configuration
+             * set up, release the write lock and re-obtain the read lock to access the properties.
+             */
+            if (config == null) {
+                readLock.unlock();
+                WriteLock writeLock = lock.writeLock();
+                writeLock.lock();
+                try {
+                    if (config == null) {
+                        config = new DefaultConfiguration();
+                        initialize(null);
+                    }
+                } catch (Exception e){
+                    logger.error("getConfiguration", e);
+                } finally {
+                    writeLock.unlock();
+                }
+                readLock.lock();
+            }
+        } finally {
+            readLock.unlock();
+        }
+        return config;
+    }
+
+    /**
+     * This method will obtain the local configuration for the specified object if it exists, or
+     * will create it from the current global configuration. This allows the configuration to be
+     * tailored for a specific process or operation, and uniquely identified by some value (such as
+     * the object that represents the special use of the configuration).
+     *
+     * @param owner The owner or identification of the owner of the special configuration
+     * @return The special configuration object, or a clone of the global configuration so that it
+     *         can be altered if needed.
+     */
+    public static Configuration getConfiguration(final Object owner) {
+        DefaultConfiguration local;
+        ReadLock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            local = (DefaultConfiguration) localConfigs.get(owner);
+            if (local == null) {
+                readLock.unlock();
+                WriteLock writeLock = lock.writeLock();
+                writeLock.lock();
+                local = (DefaultConfiguration) localConfigs.get(owner);
+                if (local == null) {
+                    local = getClonedDefaultConfiguration(owner, local);
+                }
+                writeLock.unlock();
+            }
+            readLock.lock();
+        } finally {
+            readLock.unlock();
+        }
+        return local;
+    }
+
+    /**
+     * This method allows the caller to alter the configuration, supplying the specified
+     * configuration properties which override the application default values.
+     * <p>
+     * The configuration is re-constructed (if already constructed) or created new (if not already
+     * created) and the default properties are loaded into the configuration.
+     * </p>
+     * <p>
+     * The primary purpose of this method is to allow the application configuration properties to be
+     * reset or refreshed after the application has already been initialized. This method will lock
+     * the configuration for the duration while it is being re-built, and should not be called on a
+     * regular basis.
+     * </p>
+     *
+     * @param props The properties used to configure the application.
+     * @return Access to the configuration implementation
+     */
+    public static Configuration getConfiguration(final Properties props) {
+        WriteLock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            config = new DefaultConfiguration();
+            initialize(props);
+            return config;
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    private static DefaultConfiguration getClonedDefaultConfiguration(Object owner, DefaultConfiguration local) {
+        Optional<DefaultConfiguration> global =
+                Optional.ofNullable((DefaultConfiguration) getConfiguration());
+        try {
+            if (global.isPresent()) {
+                local = (DefaultConfiguration) global.get().clone();
+            }
+        } catch (CloneNotSupportedException e) {
+            logger.error("getClonedDefaultConfiguration", e);
+        }
+        localConfigs.put(owner, local);
+        return local;
+    }
+
+    /**
+     * This method will clear the current configuration and then re-initialize it with the default
+     * values, application-specific configuration file, user-supplied properties (if any), and then
+     * command-line settings.
+     * <p>
+     * This method <strong><em>MUST</em></strong> be called holding the configuration lock!
+     * </p>
+     * <p>
+     * This method is a little special in that logging messages generated during the method must be
+     * cached and delayed until after the logging framework has been initialized. After that, the
+     * delayed logging buffer can be dumped to the log file and cleared.
+     * </p>
+     *
+     * @param props Application-supplied configuration values, if any
+     */
+    private static void initialize(final Properties props) {
+        DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
+        Date now = new Date();
+        logger.info(
+                "------------------------------------------------------------------------------");
+
+        logger.info(Msg.CONFIGURATION_STARTED, format.format(now));
+
+        /*
+         * Clear any existing properties
+         */
+        config.clear();
+        logger.info(Msg.CONFIGURATION_CLEARED);
+
+        /*
+         * Load the defaults (if any are present)
+         */
+        InputStream in = Thread.currentThread().getContextClassLoader()
+                .getResourceAsStream(DEFAULT_PROPERTIES);
+        if (in != null) {
+            logger.info(Msg.LOADING_DEFAULTS, DEFAULT_PROPERTIES);
+            try {
+                config.setProperties(in);
+            } finally {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    logger.error("Cannot close inputStream", e);
+                }
+            }
+            for (String key : config.getProperties().stringPropertyNames()) {
+                logger.info(Msg.PROPERTY_VALUE, key, config.getProperty(key));
+            }
+        } else {
+            logger.info(Msg.NO_DEFAULTS_FOUND, DEFAULT_PROPERTIES);
+        }
+
+        /*
+         * Look for application configuration property file. By default, we will look for the file
+         * "cdp.properties" on the user home path, then on "./etc" (relative to current path), then
+         * on "../etc" (relative to current path). If we do not find any property file, then we
+         * continue. Otherwise, we load the first property file we find and then continue. In order
+         * to allow default values for the filename and paths to be searched, we first attempt to
+         * obtain these from our configuration object (which should be primed with default values
+         * and/or overridden with application-specified values). We then use the values obtained
+         * from that to get any user supplied values on the command line.
+         */
+        String filename = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME,
+                Configuration.DEFAULT_BOOTSTRAP_FILE_NAME);
+        filename = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME, filename);
+        String env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_NAME);
+        if (env != null && env.trim().length() > 0) {
+            filename = env;
+        }
+
+        String path = config.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH,
+                Configuration.DEFAULT_BOOTSTRAP_FILE_PATH);
+        path = System.getProperty(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH, path);
+        env = System.getenv(Configuration.PROPERTY_BOOTSTRAP_FILE_PATH);
+        if (env != null && env.trim().length() > 0) {
+            path = env;
+        }
+
+        logger.info(Msg.SEARCHING_CONFIGURATION_OVERRIDES, path, filename);
+
+        String[] pathElements = path.split(COMMA);
+        boolean found = false;
+        for (String pathElement : pathElements) {
+            File file = new File(pathElement, filename);
+            if (file.exists() && file.canRead() && !file.isDirectory()) {
+
+                logger.info(Msg.LOADING_CONFIGURATION_OVERRIDES, file.getAbsolutePath());
+                Properties fileProperties = new Properties();
+                BufferedInputStream stream = null;
+                try {
+                    stream = new BufferedInputStream(new FileInputStream(file));
+                    fileProperties.load(stream);
+                    for (String key : fileProperties.stringPropertyNames()) {
+                        logger.debug(Msg.PROPERTY_VALUE, key, fileProperties.getProperty(key));
+                        config.setProperty(key, fileProperties.getProperty(key));
+                    }
+                    found = true;
+                    break;
+                } catch (IOException e) {
+                    logger.error(EELFResourceManager.format(e));
+                } finally {
+                    try {
+                        if (stream != null) {
+                            stream.close();
+                        }
+                    } catch (IOException e) {
+                        logger.error("Unable to close stream", e);
+                    }
+                }
+            }
+        }
+
+        if (!found) {
+            logger.warn(Msg.NO_OVERRIDE_PROPERTY_FILE_LOADED, filename, path);
+        }
+
+        /*
+         * Apply any application-specified properties
+         */
+        if (props != null) {
+            logger.info(Msg.LOADING_APPLICATION_OVERRIDES);
+            for (String key : props.stringPropertyNames()) {
+                logger.debug(Msg.PROPERTY_VALUE, key, props.getProperty(key));
+                config.setProperty(key, props.getProperty(key));
+            }
+        } else {
+            logger.info(Msg.NO_APPLICATION_OVERRIDES);
+        }
+
+        /*
+         * Merge in the System.properties to pick-up any command line arguments (-Dkeyword=value)
+         */
+        logger.info(Msg.MERGING_SYSTEM_PROPERTIES);
+        config.setProperties(System.getProperties());
+
+        /*
+         * As a convenience, copy the "specialProperties" that are not defined in System.properties
+         * from the configuration back to the system properties object.
+         */
+        for (String key : config.getProperties().stringPropertyNames()) {
+            for (String specialProperty : specialProperties) {
+                if (key.equals(specialProperty) && !System.getProperties().containsKey(key)) {
+                    System.setProperty(key, config.getProperty(key));
+                    logger.info(Msg.SETTING_SPECIAL_PROPERTY, key, config.getProperty(key));
+                }
+            }
+        }
+
+        /*
+         * Initialize the resource manager by loading the requested bundles, if any are defined.
+         * Resource bundles may be specified as a comma-delimited list of names. These resource
+         * names are base names of resource bundles, do not include the language or country code, or
+         * the ".properties" extension. The actual loading of the resource bundles is done lazily
+         * when requested the first time. If the bundle does not exist, or cannot be loaded, it is
+         * ignored.
+         */
+        String resourcesList = config.getProperty(Configuration.PROPERTY_RESOURCE_BUNDLES,
+                Configuration.DEFAULT_RESOURCE_BUNDLES);
+        String[] resources = resourcesList.split(",");
+        for (String resource : resources) {
+            logger.info(Msg.LOADING_RESOURCE_BUNDLE, resource.trim());
+            EELFResourceManager.loadMessageBundle(resource.trim());
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/DefaultConfiguration.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/DefaultConfiguration.java
new file mode 100644 (file)
index 0000000..635110c
--- /dev/null
@@ -0,0 +1,564 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.configuration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.ProtectionDomain;
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.onap.appc.encryption.EncryptionTool;
+import org.onap.appc.util.UnmodifiableProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class provides the implementation of the <code>Configuration</code> interface. It is created
+ * by the ConfigurationFactory and initialized with the configuration values for the process.
+ *
+ * @since Mar 18, 2014
+ */
+public final class DefaultConfiguration implements Configuration, Cloneable {
+
+    private static final Logger logger = LoggerFactory.getLogger(DefaultConfiguration.class);
+
+    /**
+     * The framework configuration properties.
+     */
+    private Properties properties = new Properties();
+
+    /**
+     * Construct the configuration object.
+     */
+    DefaultConfiguration() {}
+
+    /**
+     * Clears all properties
+     */
+    public void clear() {
+        properties.clear();
+    }
+
+    /**
+     * @see java.lang.Object#clone()
+     */
+    @Override
+    protected Object clone() throws CloneNotSupportedException {
+        DefaultConfiguration clone = (DefaultConfiguration) super.clone();
+
+        clone.properties = new Properties(this.properties);
+        clone.properties.putAll(this.properties);
+
+        return clone;
+    }
+
+    /**
+     * Decrypts an encrypted value, if it is encrypted, and returns the clear text. Performs no
+     * operation on the string if it is not encrypted.
+     *
+     * @param value The value to (optionally) be decrypted
+     * @return The clear text
+     */
+    @SuppressWarnings("nls")
+    private static String decrypt(String value) {
+        if (value != null && value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
+            try {
+                return EncryptionTool.getInstance().decrypt(value);
+            } catch (Exception e) {
+                StringBuilder out = new StringBuilder();
+                for (Provider p : Security.getProviders()) {
+                    for (Service s : p.getServices()) {
+                        String algo = s.getAlgorithm();
+                        out.append(String.format(
+                                "\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]",
+                                algo, p.getName(), s.getClassName()));
+                    }
+                }
+                logger.debug(out.toString());
+                logger.warn(String.format("Could not decrypt the configuration value [%s]", value),
+                        e);
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Decrypts all elements in the properties object
+     */
+    private void decryptAllProperties() {
+        if (properties != null) {
+            for (Entry<Object, Object> e : properties.entrySet()) {
+                if (e.getValue() != null) {
+                    e.setValue(decrypt(e.getValue().toString()));
+                }
+            }
+        }
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (this.getClass() != obj.getClass()) {
+            return false;
+        }
+
+        DefaultConfiguration other = (DefaultConfiguration) obj;
+
+        return (this.properties.size() == other.properties.size())
+                && (this.properties.entrySet().containsAll(other.properties.entrySet()))
+                && (other.properties.entrySet().containsAll(this.properties.entrySet()));
+
+    }
+
+    /**
+     * This method will use the properties object to expand any variables that may be present in the
+     * template provided. Variables are represented by the string "${name}", where "name" is the
+     * name of a property defined in either the current configuration object, or system properties
+     * if undefined. If the value cannot be found, the variable is removed and an empty string is
+     * used to replace the variable.
+     *
+     * @param template The template to be expanded
+     * @return The expanded template where each variable is replaced with its value
+     */
+    @SuppressWarnings("nls")
+    private String expandVariables(String template) {
+        if (template == null) {
+            return null;
+        }
+
+        // Decrypt the template if needed
+        // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also,
+        // Sonar complains
+        // bitterly
+
+        StringBuilder builder = new StringBuilder(decrypt(template));
+        Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}");
+        Matcher matcher = pattern.matcher(builder);
+        while (matcher.find()) {
+            String variable = matcher.group(1);
+            String value = properties.getProperty(variable);
+            if (value == null) {
+                value = System.getProperty(variable);
+            }
+            if (value == null) {
+                value = "";
+            }
+            builder.replace(matcher.start(), matcher.end(), value);
+
+            matcher.reset();
+        }
+        return builder.toString().trim();
+    }
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The
+     * standard rules for Boolean.parseBoolean() are used.
+     *
+     * @param key The property key
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public boolean getBooleanProperty(String key) {
+        return Boolean.valueOf(getProperty(key, "false"));
+    }
+
+    /**
+     * This method is called to obtain a property expressed as a boolean value (true or false). The
+     * standard rules for Boolean.valueOf(String) are used.
+     *
+     * @param key The property key
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The value of the property expressed as a boolean, or false if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getBooleanProperty(java.lang.String, boolean)
+     */
+    @Override
+    public boolean getBooleanProperty(String key, boolean defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getBooleanProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the indicated property value expressed as a floating point double-precision value
+     * (double).
+     *
+     * @param key The property to retrieve
+     * @return The value of the property, or 0.0 if not found
+     * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public double getDoubleProperty(String key) {
+        try {
+            return Double.valueOf(getProperty(key, "0.0"));
+        } catch (NumberFormatException e) {
+            return 0.0;
+        }
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getDoubleProperty(java.lang.String, double)
+     */
+    @Override
+    public double getDoubleProperty(String key, double defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getDoubleProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * {@link Integer#parseInt(String, int)} using a radix of 10 are used.
+     *
+     * @param key The property name to retrieve.
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public int getIntegerProperty(String key) {
+        try {
+            return Integer.parseInt(getProperty(key, "0"), 10);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the property indicated expressed as an integer. The standard rules for
+     * Integer.parseInt(String, int) using a radix of 10 are used.
+     *
+     * @param key The property name to retrieve.
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The value of the property, or 0 if it does not exist or is invalid.
+     * @see org.onap.appc.configuration.Configuration#getIntegerProperty(java.lang.String, int)
+     */
+    @Override
+    public int getIntegerProperty(String key, int defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getIntegerProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or zero if it does not.
+     *
+     * @param key The key of the property desired.
+     * @return The value of the property expressed as an integer long value, or zero if the property
+     *         does not exist or is not a valid integer long.
+     * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public long getLongProperty(String key) {
+        try {
+            return Long.parseLong(getProperty(key, "0"), 10);
+        } catch (NumberFormatException e) {
+            return 0;
+        }
+    }
+
+    /**
+     * Returns the specified property as a long integer value, if it exists, or the default value if
+     * it does not exist or is invalid.
+     *
+     * @param key The key of the property desired.
+     * @param defaultValue the value to be returned if the property is not valid or does not exist.
+     * @return The value of the property expressed as an integer long value, or the default value if
+     *         the property does not exist or is not a valid integer long.
+     * @see org.onap.appc.configuration.Configuration#getLongProperty(java.lang.String, long)
+     */
+    @Override
+    public long getLongProperty(String key, long defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getLongProperty(key);
+        }
+        return defaultValue;
+    }
+
+    /**
+     * This method can be called to retrieve a properties object that is immutable. Any attempt to
+     * modify the properties object returned will result in an exception. This allows a caller to
+     * view the current configuration as a set of properties.
+     *
+     * @return An unmodifiable properties object.
+     * @see org.onap.appc.configuration.Configuration#getProperties()
+     */
+    @Override
+    public Properties getProperties() {
+        return new UnmodifiableProperties(properties);
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @return The string value, or null if it does not exist.
+     */
+    @Override
+    public String getProperty(String key) {
+        String value = properties.getProperty(key);
+        if (value == null) {
+            return null;
+        }
+        return expandVariables(value.trim());
+    }
+
+    /**
+     * This method is called to obtain a property as a string value
+     *
+     * @param key The key of the property
+     * @param defaultValue The default value to be returned if the property does not exist
+     * @return The string value, or null if it does not exist.
+     * @see org.onap.appc.configuration.Configuration#getProperty(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        if (isPropertyDefined(key)) {
+            return getProperty(key);
+        }
+
+        if (defaultValue == null) {
+            return null;
+        }
+
+        return expandVariables(defaultValue.trim());
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return properties == null ? 0 : properties.hashCode();
+    }
+
+    /**
+     * Returns true if the named property is defined, false otherwise.
+     *
+     * @param key The key of the property we are interested in
+     * @return True if the property exists.
+     */
+    @Override
+    public boolean isPropertyDefined(String key) {
+        return properties.containsKey(key);
+    }
+
+    /**
+     * Returns an indication of the validity of the boolean property. A boolean property is
+     * considered to be valid only if it has the value "true" or "false" (ignoring case).
+     *
+     * @param key The property to be checked
+     * @return True if the value is a boolean constant, or false if it does not exist or is not a
+     *         correct string
+     * @see org.onap.appc.configuration.Configuration#isValidBoolean(java.lang.String)
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public boolean isValidBoolean(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            value = value.toLowerCase();
+            return value.matches("true|false");
+        }
+        return false;
+    }
+
+    /**
+     * Returns an indication if the indicated property represents a valid double-precision floating
+     * point number.
+     *
+     * @param key The property to be examined
+     * @return True if the property is a valid representation of a double, or false if it does not
+     *         exist or contains illegal characters.
+     * @see org.onap.appc.configuration.Configuration#isValidDouble(java.lang.String)
+     */
+    @Override
+    public boolean isValidDouble(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Double.valueOf(value);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns an indication if the property is a valid integer value or not.
+     *
+     * @param key The key of the property to check
+     * @return True if the value is a valid integer string, or false if it does not exist or
+     *         contains illegal characters.
+     * @see org.onap.appc.configuration.Configuration#isValidInteger(java.lang.String)
+     */
+    @Override
+    public boolean isValidInteger(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Integer.parseInt(value.trim(), 10);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines is the specified property exists and is a valid representation of an integer long
+     * value.
+     *
+     * @param key The property to be checked
+     * @return True if the property is a valid representation of an integer long value, and false if
+     *         it either does not exist or is not valid.
+     * @see org.onap.appc.configuration.Configuration#isValidLong(java.lang.String)
+     */
+    @Override
+    public boolean isValidLong(String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            try {
+                Long.parseLong(value.trim(), 10);
+                return true;
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method allows an implementation to load configuration properties that may override
+     * default values.
+     *
+     * @param is An input stream that contains the properties to be loaded
+     */
+    public void setProperties(InputStream is) {
+        try {
+            properties.load(is);
+        } catch (IOException e) {
+            logger.warn("setProperties with inputStream got exception", e);
+        }
+    }
+
+    /**
+     * This method allows an implementation to load configuration properties that may override
+     * default values.
+     *
+     * @param props An optional Properties object to be merged into the configuration, replacing any
+     *        same-named properties.
+     * @see org.onap.appc.configuration.Configuration#setProperties(java.util.Properties)
+     */
+    @Override
+    public void setProperties(Properties props) {
+        properties.putAll(props);
+        decryptAllProperties();
+    }
+
+    /**
+     * This method allows a caller to insert a new property definition into the configuration
+     * object. This allows the application to adjust or add to the current configuration. If the
+     * property already exists, it is replaced with the new value.
+     *
+     * @param key The key of the property to be defined
+     * @param value The value of the property to be defined
+     * @see org.onap.appc.configuration.Configuration#setProperty(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public void setProperty(String key, String value) {
+        properties.setProperty(key, decrypt(value));
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @SuppressWarnings("nls")
+    @Override
+    public String toString() {
+        return String.format("Configuration: %d properties, keys:[%s]", properties.size(),
+                properties.keySet().toString());
+    }
+
+    /**
+     * This is a helper method to read the manifest of the jar file that this class was loaded from.
+     * Note that this will only work if the code is packaged in a jar file. If it is an open
+     * deployment, such as under eclipse, this will not work and there is code added to detect that
+     * case.
+     *
+     * @return The manifest object from the jar file, or null if the code is not packaged in a jar
+     *         file.
+     */
+    @SuppressWarnings({"unused", "nls"})
+    private Manifest getManifest() {
+        ProtectionDomain domain = getClass().getProtectionDomain();
+        CodeSource source = domain.getCodeSource();
+        URL location = source.getLocation();
+        String path = location.getPath();
+        int index = path.indexOf('!');
+        if (index != -1) {
+            path = path.substring(0, index);
+        }
+        if (path.endsWith(".jar")) {
+            try (JarFile jar = new JarFile(location.getFile())) {
+                return jar.getManifest();
+            } catch (IOException e) {
+                logger.error("getManifest", e);
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/package.html b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/configuration/package.html
new file mode 100644 (file)
index 0000000..c6889da
--- /dev/null
@@ -0,0 +1,174 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP : APPC
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Copyright (C) 2017 Amdocs
+  =============================================================================
+  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.
+  
+  ECOMP is a trademark and service mark of AT&T Intellectual Property.
+  ============LICENSE_END=========================================================
+  -->
+
+<html>
+<head>
+<title>Configuration</title>
+</head>
+
+<body>
+  <p style="margin-left: 30.0px;">
+    CDP Configuration support is provided by a common framework to load
+    and manage configuration properties from multiple sources. The basic
+    concept is to load a set of default properties from a known resource
+    file located on the class path, and then override these defaults
+    with optional settings that can be provided by a user through either
+    additional property files or via the command line (as VM arguments).
+    The loading of defaults from a resource property file (named <strong>com/att/cdp/default.properties</strong>)
+    ensures that values are defined for properties the application needs
+    in order to operate.
+  </p>
+  <p style="margin-left: 30.0px;">
+    One of these default values that can be set is the name of the
+    property file that allows the user to supply settings, as well as
+    the path where the file can be found. In general, the default name
+    of the property file will be &quot;<strong>cdp.properties</strong>&quot;,
+    and the path that will be searched is &quot;<strong>${user.home};etc;../etc</strong>&quot;.
+    However, these values can be changed through the use of the
+    default.properties resource file. The property that specifies the
+    property file name is named <strong>com.att.cdp.bootstrap.file</strong>,
+    while the property named <strong>com.att.cdp.bootstrap.path</strong>
+    specifies the search path.
+  </p>
+  <p style="margin-left: 30.0px;">
+    After the default.properties are loaded, but prior to searching for
+    the application configuration file, the configuration factory checks
+    for properties <strong>com.att.cdp.bootstrap.path</strong> and <strong>com.att.cdp.bootstrap.file
+    </strong>in the System properties object (meaning they were set by the
+    command line). If these values are defined in the system properties
+    object, they are used. If not, these values are obtained from the
+    default properties just loaded. This allows the specification of
+    either the file name or path, or both, to be overridden during start
+    up by using command-line arguments.
+  </p>
+  <p style="margin-left: 30.0px;">The search path is scanned for the
+    first occurrence of the specified property file. The first
+    occurrence is loaded and scanning is stopped at that point. The
+    configuration factory does not load all occurrences it finds, only
+    the first occurrence it finds.</p>
+  <p style="margin-left: 30.0px;">The configuration properties are
+    loaded and processed according to a defined precedence order, such
+    that properties defined with a higher precedence override the same
+    property at a lower precedence. The precedence order is defined as
+    follows:</p>
+  <h2>Precedence Order</h2>
+  <ol>
+    <li>Default properties are initially loaded into the
+      configuration. These default properties are the lowest level
+      precedence, and will be overridden by any properties specified at
+      higher levels. These are loaded from resources that are packaged
+      as part of the various application components. Each component
+      (Server, Coordinator, EPM, or CLI) may have different default
+      properties. The default properties are loaded from a resource
+      named <strong>com/att/cdp/default.properties</strong>. The default
+      properties can specify the name of the application property file
+      to be used to configure the application, as well as the path to
+      search. Additionally, these properties can be supplied via the
+      command line to override the default settings if needed.<br /> <br />
+    </li>
+    <li>The configuration factory allows for the application to
+      supply an initial properties object to initialize the
+      configuration. This properties object could be loaded or created
+      in any way necessary for the application. This is totally up to
+      the application to define, if it is needed. If no
+      application-specific property object is supplied, this step is
+      skipped. If a property object is supplied, it is used to replace
+      or set any properties that may have been defined by the defaults.<br />
+      <br />
+    </li>
+    <li>The configuration factory will then search for a bootstrap
+      file on a bootstrap path. The actual bootstrap file name and path
+      can be specified as properties on the command line, or will
+      default to a file name of <strong>cdp.properties</strong> and a
+      path of <strong>${user.home};etc;../etc</strong>. If desired, the
+      user can specify the exact name of the property file to be loaded
+      as well as the path using <strong>-Dcom.att.cdp.bootstrap.file=&lt;filename&gt;</strong>
+      and <strong>-Dcom.att.cdp.bootstrap.path=&lt;path&gt;</strong>.
+      These properties are set to default values by the default
+      properties loaded in step #1 above. The first occurrence of a
+      property file is the file loaded and used. Any other occurrences
+      are not processed.<br /> <br />
+    </li>
+    <li>The System properties are then merged into the
+      configuration. This allows the highest level of precedence,
+      command-line VM arguments (-D<strong>name=value</strong>) to be
+      merged into the configuration property object. These settings
+      override all lower level settings of the same name, as well as
+      merge all system properties into the configuration object.
+    </li>
+  </ol>
+  <h2>Variables</h2>
+  <p style="margin-left: 30.0px;">
+    The configuration support allows for variables to be inserted into
+    any property that is defined. Variables are named using the format <strong>${name}</strong>,
+    where the &quot;name&quot; is the name of a property that is defined
+    in the configuration, or a system property (such as <strong>user.home</strong>).
+    Variables can nest, such that a variable can be replaced with
+    another variable, which is then reevaluated to obtain the value.
+    This allows for indirection as well as variable substitution, if
+    needed.
+  </p>
+  <h2>Using the Configuration Support</h2>
+  <p style="margin-left: 30.0px;">
+    The configuration support was designed to be easy to use. The
+    configuration implementation is abstracted away from the application
+    so that it could be changed easily in the future if needed, or if we
+    needed to load different implementations for different reasons. This
+    means that the application always accesses the configuration through
+    an interface, named <strong>Configuration</strong>. The
+    implementation of that configuration interface is obtained by a
+    static method on the <strong>ConfigurationFactory</strong> class.
+    The configuration factory will both create the configuration if not
+    already created on the first access, as well as return the current
+    configuration if already created. Additionally, the
+    ConfigurationFactory provides mechanisms to recreate the
+    configuration after the application is initialized should the need
+    arise to update its configuration.
+  </p>
+  <p style="margin-left: 30.0px;">An example of the code needed to
+    obtain access to the configuration is:</p>
+  <pre style="margin-left: 30.0px;">Configuration config = ConfigurationFactory.getConfiguration();</pre>
+  <p style="margin-left: 30.0px;">Please refer to the javadoc or the
+    source code in cdp-common for other ways that the configuration and
+    configuration factory can be used.</p>
+  <h2>Reloading Properties</h2>
+  <p style="margin-left: 30.0px;">The configuration support allows
+    for properties to be re-loaded and re-evaluated after the
+    application is running. This is designed to allow a configuration to
+    be refreshed should the need arise. This could allow on-demand
+    refresh (via a command, for example), or automatically based on
+    sensing a change in the configuration file.</p>
+  <p style="margin-left: 30.0px;">
+    When the <strong>ConfigurationFactory</strong> method <strong>getConfiguration(Propert</strong><strong>ies)</strong>
+    is called, the current configuration is cleared and rebuilt using
+    the process defined above. The supplied property object is used in
+    step #2 of the process. While the properties are being re-built, no
+    access to the properties are allowed. Any attempt to access
+    properties while the re-build operation is in effect will block the
+    caller until completed. This is accomplished using read and write
+    shared locks.
+  </p>
+</body>
+</html>
+>>>>>>> app-controller/master:appc-common/src/main/java/org/onap/appc/configuration/package.html
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionException.java
new file mode 100644 (file)
index 0000000..804fe6a
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+public class EncryptionException extends Exception {
+
+    public EncryptionException(String message) {
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionTool.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/EncryptionTool.java
new file mode 100644 (file)
index 0000000..37205fc
--- /dev/null
@@ -0,0 +1,210 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.Security;
+
+import javax.crypto.Cipher;
+
+import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64;
+import org.jasypt.util.text.BasicTextEncryptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is used to encapsulate the encryption and decryption support in one place and to provide a utility to
+ * encrypt and decrypt data.
+ */
+public class EncryptionTool {
+
+    /**
+     * This lock object is used ONLY if the singleton has not been set up.
+     */
+    private static final Object lock = new Object();
+
+    /**
+     * The salt is used to initialize the PBE (password Based Encrpytion) algorithm.
+     */
+    private static final byte[] DEFAULT_SALT = {
+        (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99
+    };
+
+    /**
+     * The prefix we insert onto any data we encrypt so that we can tell if it is encrpyted later and therefore decrypt
+     * it
+     */
+    @SuppressWarnings("nls")
+    public static final String ENCRYPTED_VALUE_PREFIX = "enc:";
+
+    /**
+     * The instance of the encryption utility object
+     */
+    private static EncryptionTool instance = null;
+
+    /**
+     * The iteration count used to initialize the PBE algorithm and to generate the key spec
+     */
+    private static final int ITERATION_COUNT = 20;
+
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(EncryptionTool.class);
+
+    /**
+     * The secret passphrase (PBE) that we use to perform encryption and decryption. The algorithm we are using is a
+     * symmetrical cipher.
+     */
+    private static char[] secret = {
+        'C', '_', 'z', 'l', '!', 'K', '!', '4', '?', 'O', 'z', 'E', 'K', 'E', '>', 'U', 'R', '/', '%', 'Y', '\\', 'f',
+        'b', '"', 'e', 'n', '{', '"', 'l', 'U', 'F', '+', 'E', '\'', 'R', 'T', 'p', '1', 'V', '4', 'l', 'a', '9', 'w',
+        'v', '5', 'Z', '#', 'i', 'V', '"', 'd', 'l', '!', 'L', 'M', 'g', 'L', 'Q', '{', 'v', 'v', 'K', 'V'
+    };
+
+    /**
+     * The algorithm to encrypt and decrpyt data is "Password (or passphrase) Based Encryption with Message Digest #5
+     * and the Data Encryption Standard", i.e., PBEWithMD5AndDES.
+     */
+    @SuppressWarnings("nls")
+    private static final String SECURITY_ALGORITHM = "PBEWITHMD5AND256BITAES";// "PBEWithMD5AndDES";
+
+    /**
+     * The decryption cipher object
+     */
+    private Cipher decryptCipher = null;
+
+    /**
+     * The encryption cipher object
+     */
+    private Cipher encryptCipher = null;
+
+    private BasicTextEncryptor encryptor;
+
+    /**
+     * Get an instance of the EncryptionTool
+     *
+     * @return The encryption tool to be used
+     */
+    public static final synchronized EncryptionTool getInstance() {
+        if (instance == null) {
+            instance = new EncryptionTool();
+        }
+        return instance;
+    }
+
+    /**
+     * Create the EncryptionTool instance
+     */
+    @SuppressWarnings("nls")
+    private EncryptionTool() {
+        String out = "Found the following security algorithms:";
+        for (Provider p : Security.getProviders()) {
+            for (Service s : p.getServices()) {
+                String algo = s.getAlgorithm();
+                out +=
+                    String.format("%n  -Algorithm [ %s ] in provider [ %s ] and service [ %s ]", algo, p.getName(),
+                        s.getClassName());
+            }
+        }
+        LOG.debug(out);
+    }
+
+    /**
+     * Decrypt the provided encrypted text
+     *
+     * @param cipherText
+     *            THe cipher text to be decrypted. If the ciphertext is not encrypted, then it is returned as is.
+     * @return the clear test of the (possibly) encrypted value. The original value if the string is not encrypted.
+     */
+    @SuppressWarnings("nls")
+    public synchronized String decrypt(String cipherText) {
+        if (isEncrypted(cipherText)) {
+            String encValue = cipherText.substring(ENCRYPTED_VALUE_PREFIX.length());
+            byte[] plainByte = Base64.decodeBase64(encValue.getBytes());
+            byte[] decryptByte = xorWithSecret(plainByte);
+            return new String(decryptByte);
+        } else {
+            return cipherText;
+        }
+
+    }
+
+    /**
+     * Encrypt the provided clear text
+     *
+     * @param clearText
+     *            The clear text to be encrypted
+     * @return the encrypted text. If the clear text is empty (null or zero length), then an empty string is returned.
+     *         If the clear text is already encrypted, it is not encrypted again and is returned as is. Otherwise, the
+     *         clear text is encrypted and returned.
+     */
+    @SuppressWarnings("nls")
+    public synchronized String encrypt(String clearText) {
+        if (clearText != null) {
+            byte[] encByte = xorWithSecret(clearText.getBytes());
+            String encryptedValue = new String(Base64.encodeBase64(encByte));
+            return ENCRYPTED_VALUE_PREFIX + encryptedValue;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Is a value encrypted? A value is considered to be encrypted if it begins with the
+     * {@linkplain #ENCRYPTED_VALUE_PREFIX encrypted value prefix}.
+     *
+     * @param value
+     *            the value to check.
+     * @return true/false;
+     */
+    private static boolean isEncrypted(final String value) {
+        return value != null && value.startsWith(ENCRYPTED_VALUE_PREFIX);
+    }
+
+    /**
+     * XORs the input byte array with the secret key, padding 0x0 to the end of the secret key if the input is longer
+     * and returns a byte array the same size as input
+     *
+     * @param inp
+     *            The byte array to be XORed with secret
+     * @return A byte array the same size as inp or null if input is null.
+     */
+    private byte[] xorWithSecret(byte[] inp) {
+        if (inp == null) {
+            return null;
+        }
+
+        byte[] secretBytes = new String(secret).getBytes();
+        int size = inp.length;
+
+        byte[] out = new byte[size];
+        for (int i = 0; i < size; i++) {
+            out[i] = (byte) ((inp[i]) ^ (secretBytes[i % secretBytes.length]));
+        }
+        return out;
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/HexHelper.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/encryption/HexHelper.java
new file mode 100644 (file)
index 0000000..9e975f8
--- /dev/null
@@ -0,0 +1,162 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * HexHelper utility used for encryption/decryption
+ */
+public final class HexHelper {
+
+    @SuppressWarnings({
+        "javadoc", "nls"
+    })
+    public static final String CM_PATH = "@(#) [viewpath]/[item]";
+
+    @SuppressWarnings({
+        "nls", "javadoc"
+    })
+    public static final String CM_PROJECT = "@(#) [environment] [baseline]";
+
+    @SuppressWarnings({
+        "javadoc", "nls"
+    })
+    public static final String CM_VERSION = "@(#) [version] [crtime]";
+
+    private static final char[] HEX_TABLE = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
+        'E', 'F'};
+
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(HexHelper.class);
+
+    private static Map<Character, Integer> textToHex;
+
+    static {
+        textToHex = new HashMap<>();
+        textToHex.put('0', 0);
+        textToHex.put('1', 1);
+        textToHex.put('2', 2);
+        textToHex.put('3', 3);
+        textToHex.put('4', 4);
+        textToHex.put('5', 5);
+        textToHex.put('6', 6);
+        textToHex.put('7', 7);
+        textToHex.put('8', 8);
+        textToHex.put('9', 9);
+        textToHex.put('A', 10);
+        textToHex.put('B', 11);
+        textToHex.put('C', 12);
+        textToHex.put('D', 13);
+        textToHex.put('E', 14);
+        textToHex.put('F', 15);
+    }
+
+    /**
+     * Default private constructor prevents instantiation
+     */
+    private HexHelper() {
+        // no-op
+    }
+
+    /**
+     * Converts an array of bytes to the equivalent string representation using hexadecimal notation
+     *
+     * @param bytes The bytes to be converted to a hexadecimal string
+     * @return The string representation
+     */
+    public static String convertBytesToHex(byte[] bytes) throws EncryptionException{
+
+        if (bytes == null)
+            throw new EncryptionException("Given byte array is null");
+
+        StringBuilder builder = new StringBuilder(bytes.length * 2);
+        for (byte aByte : bytes) {
+            char tempChar;
+            // Get the first 4 bits (high) Do bitwise logical AND to get rid of
+            // low nibble. Shift results to right by 4 and get char
+            // representation
+            tempChar = HEX_TABLE[(aByte & 0xf0) >>> 4];
+            builder.append(tempChar);
+
+            // Get the last 4 bits (low) Do bitwise logical AND to get rid of
+            // high nibble. Get char representation
+            tempChar = HEX_TABLE[aByte & 0x0f];
+            builder.append(tempChar);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Converts a hexadecimal string representation of a binary value to an array of bytes
+     *
+     * @param hexValue The hex representation string to be converted
+     * @return The array of bytes that contains the binary value
+     */
+    @SuppressWarnings("nls")
+    public static byte[] convertHexToBytes(String hexValue) throws EncryptionException {
+
+        if (hexValue ==null)
+            throw new EncryptionException("Given hex value is null");
+
+        byte[] bytes;
+        byte high;
+        byte low;
+        char hexChar;
+
+        StringBuilder builder = new StringBuilder(hexValue.toUpperCase());
+        if (builder.length() % 2 != 0) {
+            LOG.warn("Invalid HEX value length. The length of the value has to be a multiple of 2."
+                + " Prepending '0' value.");
+            builder.insert(0, '0');
+        }
+        int hexLength = builder.length();
+        int byteLength = hexLength / 2;
+
+        bytes = new byte[byteLength];
+        try {
+            for (int index = 0; index < hexLength; index += 2) {
+                hexChar = builder.charAt(index);
+                high = textToHex.get(hexChar).byteValue();
+                high = (byte) (high << 4);
+                hexChar = builder.charAt(index + 1);
+                low = textToHex.get(hexChar).byteValue();
+                high = (byte) (high | low);
+                bytes[index / 2] = high;
+            }
+        }
+        catch (NullPointerException e){
+            LOG.error("Given string contains not hexadecimal values", e);
+            throw new EncryptionException("Given string contains not hexadecimal values");
+        }
+
+        return bytes;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/APPCException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/APPCException.java
new file mode 100644 (file)
index 0000000..90dfa67
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+/**
+ * This is a base class for all APPC defined exceptions.
+ */
+
+public class APPCException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Constructs a new exception with null as its detail message. The cause is not initialized, and may subsequently be
+     * initialized by a call to initCause.
+     */
+    public APPCException() {
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+     * be initialized by a call to initCause.
+     * 
+     * @param message
+     *            the detail message. The detail message is saved for later retrieval by the getMessage() method.
+     */
+    public APPCException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail message of (cause==null ? null :
+     * cause.toString()) (which typically contains the class and detail message of cause). This constructor is useful
+     * for exceptions that are little more than wrappers for other throwables (for example,
+     * java.security.PrivilegedActionException).
+     * 
+     * @param cause
+     *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+     *            and indicates that the cause is nonexistent or unknown.)
+     */
+    public APPCException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * 
+     Constructs a new exception with the specified detail message and cause.
+     * <p>
+     * Note that the detail message associated with cause is not automatically incorporated in this exception's detail
+     * message.
+     * </p>
+     * 
+     * @param message
+     *            the detail message (which is saved for later retrieval by the getMessage() method).
+     * @param cause
+     *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+     *            and indicates that the cause is nonexistent or unknown.)
+     */
+    public APPCException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * 
+     Constructs a new exception with the specified detail message, cause, suppression enabled or disabled, and
+     * writable stack trace enabled or disabled.
+     * 
+     * @param message
+     *            the detail message.
+     * @param cause
+     *            the cause. (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression
+     *            whether or not suppression is enabled or disabled
+     * @param writableStackTrace
+     *            whether or not the stack trace should be writable
+     */
+    public APPCException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidInputException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidInputException.java
new file mode 100644 (file)
index 0000000..32a6cde
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+public class InvalidInputException extends Exception {
+    public InvalidInputException(String message){
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidStateException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/InvalidStateException.java
new file mode 100644 (file)
index 0000000..61a8770
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+public class InvalidStateException extends Exception {
+    public InvalidStateException(String message) {
+        super(message);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/UnknownProviderException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/exceptions/UnknownProviderException.java
new file mode 100644 (file)
index 0000000..d23c802
--- /dev/null
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+/**
+ * This exception indicates that the named provider could not be found or was unidentifiable.
+ */
+public class UnknownProviderException extends APPCException {
+
+    /**
+    *
+    */
+   private static final long serialVersionUID = 1L;
+
+   /**
+    * Constructs a new exception with null as its detail message. The cause is not initialized, and may subsequently be
+    * initialized by a call to initCause.
+    */
+   public UnknownProviderException() {
+   }
+
+   /**
+    * Constructs a new exception with the specified detail message. The cause is not initialized, and may subsequently
+    * be initialized by a call to initCause.
+    * 
+    * @param message
+    *            the detail message. The detail message is saved for later retrieval by the getMessage() method.
+    */
+   public UnknownProviderException(String message) {
+       super(message);
+   }
+
+   /**
+    * Constructs a new exception with the specified cause and a detail message of (cause==null ? null :
+    * cause.toString()) (which typically contains the class and detail message of cause). This constructor is useful
+    * for exceptions that are little more than wrappers for other throwables (for example,
+    * java.security.PrivilegedActionException).
+    * 
+    * @param cause
+    *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+    *            and indicates that the cause is nonexistent or unknown.)
+    */
+   public UnknownProviderException(Throwable cause) {
+       super(cause);
+   }
+
+   /**
+    * 
+    Constructs a new exception with the specified detail message and cause.
+    * <p>
+    * Note that the detail message associated with cause is not automatically incorporated in this exception's detail
+    * message.
+    * </p>
+    * 
+    * @param message
+    *            the detail message (which is saved for later retrieval by the getMessage() method).
+    * @param cause
+    *            the cause (which is saved for later retrieval by the getCause() method). (A null value is permitted,
+    *            and indicates that the cause is nonexistent or unknown.)
+    */
+   public UnknownProviderException(String message, Throwable cause) {
+       super(message, cause);
+   }
+
+   /**
+    * 
+    Constructs a new exception with the specified detail message, cause, suppression enabled or disabled, and
+    * writable stack trace enabled or disabled.
+    * 
+    * @param message
+    *            the detail message.
+    * @param cause
+    *            the cause. (A null value is permitted, and indicates that the cause is nonexistent or unknown.)
+    * @param enableSuppression
+    *            whether or not suppression is enabled or disabled
+    * @param writableStackTrace
+    *            whether or not the stack trace should be writable
+    */
+   public UnknownProviderException(String message,
+                                   Throwable cause,
+                                   boolean enableSuppression,
+                                   boolean writableStackTrace) {
+       super(message, cause, enableSuppression, writableStackTrace);
+   }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/i18n/Msg.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/i18n/Msg.java
new file mode 100644 (file)
index 0000000..d030959
--- /dev/null
@@ -0,0 +1,846 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.i18n;
+
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+import com.att.eelf.i18n.EELFResourceManager;
+
+/**
+ * The messages issued by APPC components.
+ * <p>
+ * This message definition is shared by all APPC components.
+ * </p>
+ *
+ */
+@SuppressWarnings("nls")
+public enum Msg implements EELFResolvableErrorEnum {
+
+    /**
+     * ECOMP Application Controller (APP-C) initialization started at {0}
+     */
+    CONFIGURATION_STARTED,
+
+    /**
+     * Prior configuration has been cleared
+     */
+    CONFIGURATION_CLEARED,
+
+    /**
+     * Loading configuration properties from file "{0}"
+     */
+    LOADING_CONFIGURATION_OVERRIDES,
+
+    /**
+     * Configuration defaults loaded from resource file "{0}"
+     */
+    LOADING_DEFAULTS,
+
+    /**
+     * No default property resource "{0}" was found!
+     */
+    NO_DEFAULTS_FOUND,
+
+    /**
+     * Property "{0}" ="{1}"
+     */
+    PROPERTY_VALUE,
+
+    /**
+     * No configuration file named [{0}] was found on the configuration search path [{1}]. \ If a configuration file
+     * should have been loaded, check the file name and search path specified. CDP will proceed using the \ default
+     * values and command-line overrides (if any).
+     */
+    NO_OVERRIDE_PROPERTY_FILE_LOADED,
+
+    /**
+     * Searching path "{0}" for configuration settings "{1}"
+     */
+    SEARCHING_CONFIGURATION_OVERRIDES,
+
+    /**
+     * Loading application-specific override properties
+     */
+    LOADING_APPLICATION_OVERRIDES,
+
+    /**
+     * No application-specific override properties were provided!
+     */
+    NO_APPLICATION_OVERRIDES,
+
+    /**
+     * Merging system properties into configuration
+     */
+    MERGING_SYSTEM_PROPERTIES,
+
+    /**
+     * Setting property "{0}={1}" in system properties
+     */
+    SETTING_SPECIAL_PROPERTY,
+
+    /**
+     * Loading resource bundle "{0}"
+     */
+    LOADING_RESOURCE_BUNDLE,
+
+    /**
+     * Logging has already been initialized, check the container logging definitions to ensure they represent your
+     * desired logging configuration.
+     */
+    LOGGING_ALREADY_INITIALIZED,
+
+    /**
+     * Searching path "{0}" for log configuration file "{1}"
+     */
+    SEARCHING_LOG_CONFIGURATION,
+
+    /**
+     * Loading default logging configuration from system resource file "{0}"
+     */
+    LOADING_DEFAULT_LOG_CONFIGURATION,
+
+    /**
+     * No log configuration could be found or defaulted!
+     */
+    NO_LOG_CONFIGURATION,
+
+    /**
+     * An unsupported logging framework is bound to SLF4J. Only Logback or Log4J are supported.
+     */
+    UNSUPPORTED_LOGGING_FRAMEWORK,
+
+    /**
+     * Loading logging configuration from file "{0}"
+     */
+    LOADING_LOG_CONFIGURATION,
+
+    /**
+     * Provider {0} cannot be found or cannot be resolved to a valid provider.
+     */
+    UNKNOWN_PROVIDER,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" and region "{3}" did not change state within the alloted time.
+     * Current state is "{4}" and the desired state(s) are "{5}"
+     */
+    SERVER_STATE_CHANGE_TIMEOUT,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" has a state of deleted and cannot be {3}.
+     */
+    SERVER_DELETED,
+
+    /**
+     * Server name "{0}" with id "{1}" in tenant "{2}" has an unknown state of "{3}".
+     */
+    UNKNOWN_SERVER_STATE,
+
+    /**
+     * {0} component {1} is being initialized...
+     */
+    COMPONENT_INITIALIZING,
+
+    /**
+     * {0} component {1} has completed initialization
+     */
+    COMPONENT_INITIALIZED,
+
+    /**
+     * {0} component {1} is terminating...
+     */
+    COMPONENT_TERMINATING,
+
+    /**
+     * {0} component {1} has terminated
+     */
+    COMPONENT_TERMINATED,
+
+    /**
+     * Operation {0} is not supported or implemented at this time.
+     */
+    IAAS_ADAPTER_UNSUPPORTED_OPERATION,
+
+    /**
+     * Operation {0} called. Input document:\n{1}
+     */
+    IAAS_ADAPTER_RPC_CALLED,
+
+    /**
+     * Unable to locate the {0} service in the OSGi container
+     */
+    NO_SERVICE_FOUND,
+
+    /**
+     * Dump of context parameters for module {0}, RPC {1}, and version {2}
+     */
+    CONTEXT_PARAMETERS_DISPLAY,
+
+    /**
+     * Response properties from execution of module '{0}', RPC '{1}', and version '{2}' are:
+     */
+    RESPONSE_PARAMETERS_DISPLAY,
+
+    /**
+     * Service {0}:{1} was provided a null (empty) or invalid argument, '{2}' = '{3}'
+     */
+    NULL_OR_INVALID_ARGUMENT,
+
+    /**
+     * Service {0}:{1} is processing service '{2}' with request id '{3}'
+     */
+    PROCESSING_REQUEST,
+
+    /**
+     * Service {0}:{1} received request for service '{2}' but that service is invalid or unknown.
+     */
+    INVALID_SERVICE_REQUEST,
+
+    /**
+     * {0} registering service {1} using class {2}
+     */
+    REGISTERING_SERVICE,
+
+    /**
+     * {0} unregistering service {1}
+     */
+    UNREGISTERING_SERVICE,
+
+    /**
+     * {0} IAAS Adapter initializing provider {1} as {2}
+     */
+    LOADING_PROVIDER_DEFINITIONS,
+
+    /**
+     * {0} IAAS Adapter restart of server requested
+     */
+    RESTARTING_SERVER,
+
+    /**
+     * {0} IAAS Adapter rebuild of server requested
+     */
+    REBUILDING_SERVER,
+
+    /**
+     * {0} IAAS Adapter migrate of server requested
+     */
+    MIGRATING_SERVER,
+
+    /**
+     * {0} IAAS Adapter evacuate of server requested
+     */
+    EVACUATING_SERVER,
+
+    /**
+     * {0} IAAS Adapter create snapshot of server requested
+     */
+    SNAPSHOTING_SERVER,
+
+    /**
+     * {0} IAAS Adapter look for server requested
+     */
+    LOOKING_SERVER_UP,
+
+    /**
+     * {0} IAAS Adapter cannot perform requested service, VM url '{1}' is invalid
+     */
+    INVALID_SELF_LINK_URL,
+
+    /**
+     * Located server '{0}' on tenant '{1}' and in state '{2}'
+     */
+    SERVER_FOUND,
+
+    /**
+     * No server found in provider with self-link URL [{0}]
+     */
+    SERVER_NOT_FOUND,
+
+    /**
+     * Exception {0} was caught attempting {1} of server [{2}] on tenant [{3}]
+     */
+    SERVER_OPERATION_EXCEPTION,
+
+    /**
+     * One or more properties for [{0}] are missing, null, or empty. They are:
+     */
+    MISSING_REQUIRED_PROPERTIES,
+
+    /**
+     * The server [{0}] (id={1}) in tenant {2} is in error state, {3} is not allowed
+     */
+    SERVER_ERROR_STATE,
+
+    /**
+     * The image {0} could not be located for {1}
+     */
+    IMAGE_NOT_FOUND,
+
+    /**
+     * Time out waiting for {0} with name {1} (and id {2}) to reach one of {3} states, current state is {4}
+     */
+    STATE_CHANGE_TIMEOUT,
+
+    /**
+     * Exception {0} waiting for {1} with name {2} (and id {3}) to reach one of {4} states, current state is {5}
+     * cause={6}
+     */
+    STATE_CHANGE_EXCEPTION,
+
+    /**
+     * Server {0} is being stopped...
+     */
+    STOP_SERVER,
+
+    /**
+     * Server {0} is being started...
+     */
+    START_SERVER,
+
+    /**
+     * Server {0} is being resumed...
+     */
+    RESUME_SERVER,
+
+    /**
+     * Server {0} is being unpaused...
+     */
+    UNPAUSE_SERVER,
+
+    /**
+     * Server {0} is being rebuilt...
+     */
+    REBUILD_SERVER,
+
+    /**
+     * Connection to provider {0} at identity {1} using tenant name {2} (id {3}) failed, reason={4}, retrying in {5}
+     * seconds, attempt {6} of {7}.
+     */
+    CONNECTION_FAILED_RETRY,
+
+    /**
+     * Connection to provider {0} at service {1} failed after all retry attempts.
+     */
+    CONNECTION_FAILED,
+
+    /**
+     * {0} IAAS Adapter stop server requested
+     */
+    STOPPING_SERVER,
+
+    /**
+     * {0} IAAS Adapter start server requested
+     */
+    STARTING_SERVER,
+
+    /**
+     * Server {0} (id {1}) failed to rebuild, reason {2}
+     */
+    REBUILD_SERVER_FAILED,
+
+    /**
+     * Application {0} graph {1} response did not set the {2} parameter. This parameter is required for synchronization
+     * with the controller. Absence of this parameter is assumed to be a failure. Please correct the DG.
+     */
+    PARAMETER_IS_MISSING,
+
+    /**
+     * Application {0} graph {1} did not set parameter {2} to a valid numeric value ({3}). Please correct the DG.
+     */
+    PARAMETER_NOT_NUMERIC,
+
+    /**
+     * Application {0} graph {1} completed with failure: error code = {2}, message = {3}
+     */
+    DG_FAILED_RESPONSE,
+
+    /**
+     * Application {0} received exception {1} attempting to call graph {2}, exception message = {3}
+     */
+    EXCEPTION_CALLING_DG,
+
+    /**
+     * Application {0} was unable to locate graph {1}
+     */
+    GRAPH_NOT_FOUND,
+
+    /**
+     * Application {0} graph {1} responded with {3} properties
+     */
+    DEBUG_GRAPH_RESPONSE_HEADER,
+
+    /**
+     * {0}:{1} - {2} = {3}
+     */
+    DEBUG_GRAPH_RESPONSE_DETAIL,
+
+    /**
+     * Application {0} request {1} was supplied a property '{2}' with the value '{3}' that does not meet the required
+     * form(s):
+     */
+    INVALID_REQUIRED_PROPERTY,
+
+    /**
+     * Server {0} (id {1}) failed to migrate during {2} phase, reason {3}
+     */
+    MIGRATE_SERVER_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to evacuate, reason {2}
+     */
+    EVACUATE_SERVER_FAILED,
+    
+    /**
+     * Server {0} evacuate from host {1} to host {2} failed during the rebuild on host {2}, reason {3}
+     */
+    EVACUATE_SERVER_REBUILD_FAILED,
+
+    /**
+     * APP-C instance is too busy
+     */
+    APPC_TOO_BUSY,
+
+    /**
+     * Concurrent access to server "{0}"
+     */
+    VF_SERVER_BUSY,
+
+    /**
+     * Server "{0}" does not support command "{1}" in the current state "{2}"
+     */
+    VF_ILLEGAL_COMMAND,
+
+    /**
+     * Server "{0}" cannot handle command "{1}" because of its doubtful state
+     */
+    VF_UNDEFINED_STATE,
+
+    /**
+     * No resource found with ID "{0}" in A&AI system
+     */
+    APPC_NO_RESOURCE_FOUND,
+
+    /**
+     * The request "{0}" for server "{1}" has exceeded its TTL limit of "{3}" seconds
+     */
+    APPC_EXPIRED_REQUEST,
+
+    /**
+     * Workflow for vnfType = "{0}" and command = "{1}" not found.
+     */
+    APPC_WORKFLOW_NOT_FOUND,
+
+    /**
+     * Null vnfId and command provided
+     */
+    APPC_INVALID_INPUT,
+
+    /**
+     * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' was started at '{4}' and ended at '{5}'
+     * with status code '{6}'
+     */
+    APPC_AUDIT_MSG,
+
+    /**
+     * APP-C is unable to communicate with A&AI
+     */
+    AAI_CONNECTION_FAILED,
+
+    /**
+     * APP-C is unable to update COMPONENT_ID {0} to {1} for reason {2}
+     */
+    AAI_UPDATE_FAILED,
+
+    /**
+     * APP-C is unable to retrieve VF/VFC {0} data for Transaction ID{1}as a result of A&AI communication failure or its
+     * internal error.
+     */
+    AAI_GET_DATA_FAILED,
+
+    /**
+     * A&AI at identity {0} using VNF_ID {1} failed, reason={2}, retrying in {3} seconds, attempt {4} of {5}
+     */
+    AAI_CONNECTION_FAILED_RETRY,
+
+    /**
+     * APP-C is unable to delete COMPONENT_ID {0} for reason {1}
+     */
+    AAI_DELETE_FAILED,
+
+    /**
+     * APP-C is unable to query AAI for VNF_ID {0}
+     */
+    AAI_QUERY_FAILED,
+
+    /**
+     * VNF {0} is configured
+     */
+    VNF_CONFIGURED,
+
+    /**
+     * VNF {0} is being configured
+     */
+    VNF_CONFIGURATION_STARTED,
+
+    /**
+     * VNF {0} configuration failed for reason {1}
+     */
+    VNF_CONFIGURATION_FAILED,
+
+    /**
+     * VNF {0} is being tested
+     */
+    VNF_TEST_STARTED,
+
+    /**
+     * VNF {0} was tested
+     */
+    VNF_TESTED,
+
+    /**
+     * VNF {0} test failed for reason {1}
+     */
+    VNF_TEST_FAILED,
+
+    /**
+     * VNF {0} test failed for reason {1}
+     */
+    VNF_NOT_FOUND,
+
+    /**
+     * VNF {0} Healthcheck operation failed for reason {1}
+     */
+    VNF_HEALTHCECK_FAILED,
+
+    /**
+     * VM {0} Healthcheck operation failed for reason {1}
+     */
+    VM_HEALTHCECK_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to stop during {2} phase, reason {3}
+     */
+    STOP_SERVER_FAILED,
+
+    /**
+     * Server {0} (id {1}) failed to terminate during {2} phase, reason {3}
+     */
+    TERMINATE_SERVER_FAILED,
+
+    /**
+     * {0} IAAS Adapter terminate server requested
+     */
+    TERMINATING_SERVER,
+
+    /**
+     * Server {0} is being terminated...
+     */
+    TERMINATE_SERVER,
+
+    /**
+     * Migrate {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    MIGRATE_COMPLETE,
+
+    /**
+     * Restart {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    RESTART_COMPLETE,
+
+    /**
+     * Rebuild {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...
+     */
+    REBUILD_COMPLETE,
+
+    /**
+     * Located stack '{0}' on tenant '{1}' and in state '{2}'
+     */
+    STACK_FOUND,
+
+    /**
+     * {0} IAAS Adapter terminate stack requested
+     */
+
+    TERMINATING_STACK,
+
+    /**
+     * stack {0} is being terminated...
+     */
+    TERMINATE_STACK,
+    /**
+     * No stack found in provider with self-link URL [{0}]
+     */
+
+    STACK_NOT_FOUND,
+
+    /**
+     * Exception {0} was caught attempting {1} of stack [{2}] on tenant [{3}]
+     */
+    STACK_OPERATION_EXCEPTION,
+
+    /**
+     * Stack {0} (id {1}) failed to terminate during {2} phase, reason {3}
+     */
+
+    TERMINATE_STACK_FAILED,
+
+    /**
+     * Exception {0} was caught attempting to close provider context for {1}.
+     */
+
+    CLOSE_CONTEXT_FAILED,
+
+    /**
+     * {0} IAAS Adapter snapshoting stack
+     */
+    SNAPSHOTING_STACK,
+
+    /**
+     * Stack {0} snapshoted, snapshot ID = [{1}].
+     */
+    STACK_SNAPSHOTED,
+
+    /**
+     * {0} IAAS Adapter restoring stack
+     */
+    RESTORING_STACK,
+
+    /**
+     * Stack {0} is restored to snapshot {1}.
+     */
+    STACK_RESTORED,
+
+    /**
+     * {0} IAAS Adapter checking server
+     */
+    CHECKING_SERVER,
+
+    /**
+     * Parameter {0} is missing in svc request of {1}.
+     */
+    MISSING_PARAMETER_IN_REQUEST,
+
+    /**
+     * Cannot establish connection to server {0} port {1} with user {2}.
+     */
+    CANNOT_ESTABLISH_CONNECTION,
+
+    /**
+     * Operation '{0}' for VNF type '{1}' from Source '{2}' with RequestID '{3}' on '{4}' with action '{5}'
+     * ended in {6}ms with result '{7}'
+     */
+    APPC_METRIC_MSG,
+
+    /**
+     * Parsing failied for{0}
+     */
+    INPUT_PAYLOAD_PARSING_FAILED,
+
+    /**
+     * Error occurred for due to {0}
+     */
+    APPC_EXCEPTION,
+
+    /**
+     * SSH Data Exception occurred due to {0}
+     */
+    SSH_DATA_EXCEPTION,
+
+    /**
+     * Json processing exception occurred due to {0}
+     */
+    JSON_PROCESSING_EXCEPTION,
+
+   /**
+     * Operation {0} succeed for {1}
+     */
+    SUCCESS_EVENT_MESSAGE,
+
+    /**
+     * Dependency model not found for VNF type {0} due to {1}
+     */
+    DEPENDENCY_MODEL_NOT_FOUND,
+
+    /**
+     * Invalid Dependency model for VNF Type {0} due to {1}
+     */
+    INVALID_DEPENDENCY_MODEL,
+
+    /**
+     * Failed to retrieve VNFC DG
+     */
+    FAILURE_RETRIEVE_VNFC_DG,
+
+    /**
+     * Network check for Server {0} failed for Port {1}
+     *
+     */
+    SERVER_NETWORK_ERROR,
+
+    /**
+     * Hypervisor check for Server {0} failed. Status is DOWN or UNKNOWN
+     *
+     */
+    HYPERVISOR_DOWN_ERROR,
+    
+    /**
+     * Unable to determine Hypervisor status for Server {0}. failed.
+     *
+     */
+    HYPERVISOR_STATUS_UKNOWN,
+
+    /**
+     * Hypervisor Network check for Server {0} failed. Not reachable by APPC
+     *
+     */
+    HYPERVISOR_NETWORK_ERROR,
+
+    /**
+     * Restart application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_RESTART_FAILED,
+
+    /**
+     * Start application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_START_FAILED,
+
+    /**
+     * Start application operation failed on server : {0}, reason {1}
+     */
+    APPLICATION_STOP_FAILED,
+
+    /**
+     * Application on server {0} is being restarted...
+     */
+    RESTART_APPLICATION,
+
+    /**
+     * Application on server {0} is being started...
+     */
+    START_APPLICATION,
+
+    /**
+     * Application on server {0} is being started...
+     */
+    STOP_APPLICATION,
+
+    /**
+     * APPC LCM operations are disabled
+     */
+    LCM_OPERATIONS_DISABLED,
+
+    /**
+     * Application {0} received exception {1} while attempting to execute oam operation {2}, exception message = {3}|\
+     */
+    OAM_OPERATION_EXCEPTION,
+
+    /**
+     *   Application {0} is {1}
+     */
+    OAM_OPERATION_ENTERING_MAINTENANCE_MODE,
+
+    /**
+     * Application {0} is in {1}
+     */
+    OAM_OPERATION_MAINTENANCE_MODE,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STARTING,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STARTED,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STOPPING,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_STOPPED,
+    /**
+     * A {1} API is not allowed when {0} is in the {2} state
+     */
+    INVALID_STATE_TRANSITION,
+
+    /**
+     * Application {0} was unable to find the Request Handler service
+     */
+    REQUEST_HANDLER_UNAVAILABLE,
+
+    /**
+     * Application {0} is {1}
+     */
+    OAM_OPERATION_RESTARTING,
+
+    /**
+     * Application {0} is {1} for restart
+     */
+    OAM_OPERATION_RESTARTED,
+
+    /**
+     * {0}
+     */
+    OAM_OPERATION_INVALID_INPUT,
+
+    ATTACHINGVOLUME_SERVER,
+
+    DETTACHINGVOLUME_SERVER,
+
+    REBOOT_SERVER,
+    /**
+     * {0} IAAS Adapter reboot  of server requested
+     */
+    /**
+     * Unsupported identity service version, unable to retrieve ServiceCatalog
+     * for identity service {0}
+     */
+    IAAS_UNSUPPORTED_IDENTITY_SERVICE,
+
+    /**
+     * Sftp data transfer failed on connection to host {0} with user {1} for {2} operation, reason : {3}
+     */
+    SFTP_TRANSFER_FAILED,
+
+    /**
+     * Ssh session with host {0} has timed out during command {1} execution
+     */
+    SSH_CONNECTION_TIMEOUT,
+
+    /**
+     * Could not configure existing ssh session, reason: {0}
+     */
+    SSH_SESSION_CONFIG_ERROR
+    ;
+    /*
+     * Static initializer to ensure the resource bundles for this class are loaded...
+     */
+    static {
+        EELFResourceManager.loadMessageBundle("org/onap/appc/i18n/MessageResources");
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingConstants.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingConstants.java
new file mode 100644 (file)
index 0000000..4178f6b
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.logging;
+
+/**
+ * Constant definition of logging
+ */
+public class LoggingConstants {
+    private LoggingConstants() {
+        throw new IllegalAccessError("LoggingConstants");
+    }
+
+    /**
+     * Constants of MDC property keys
+     */
+    public static class MDCKeys {
+        private MDCKeys() {
+            throw new IllegalAccessError("MDCKeys");
+        }
+
+        public static final String ERROR_CODE = "ErrorCode";
+        public static final String ERROR_DESCRIPTION = "ErrorDescription";
+        public static final String STATUS_CODE = "StatusCode";
+        public static final String RESPONSE_CODE = "ResponseCode";
+        public static final String RESPONSE_DESCRIPTION = "ResponseDescription";
+        public static final String TARGET_ENTITY = "TargetEntity";
+        public static final String TARGET_SERVICE_NAME = "TargetServiceName";
+        public static final String PARTNER_NAME = "PartnerName";
+        public static final String SERVER_NAME = "ServerName";
+        public static final String BEGIN_TIMESTAMP = "BeginTimestamp";
+        public static final String END_TIMESTAMP = "EndTimestamp";
+        public static final String ELAPSED_TIME = "ElapsedTime";
+        public static final String CLASS_NAME = "ClassName";
+        public static final String TARGET_VIRTUAL_ENTITY = "TargetVirtualEntity";
+    }
+
+    /**
+     * Constants of status code values
+     */
+    public static class StatusCodes {
+        private StatusCodes() {
+            throw new IllegalAccessError("StatusCodes");
+        }
+        public static final String COMPLETE = "COMPLETE";
+        public static final String ERROR = "ERROR";
+    }
+
+    /**
+     * Constants of APPC target names
+     */
+    public static class TargetNames {
+        private TargetNames() {
+            throw new IllegalAccessError("TargetNames");
+        }
+        public static final String APPC = "APPC";
+        public static final String AAI = "A&AI";
+        public static final String DB = "DataBase";
+        public static final String APPC_PROVIDER = "APPC Provider";
+        public static final String APPC_OAM_PROVIDER = "APPC OAM Provider";
+        public static final String STATE_MACHINE = "StateMachine";
+        public static final String WORKFLOW_MANAGER = "WorkflowManager";
+        public static final String REQUEST_VALIDATOR = "RequestValidator";
+        public static final String LOCK_MANAGER = "LockManager";
+        public static final String REQUEST_HANDLER = "RequestHandler";
+    }
+
+    /**
+     * Constants of targeted service names
+     */
+    public static class TargetServiceNames {
+        private TargetServiceNames() {
+            throw new IllegalAccessError("TargetServiceNames");
+        }
+
+        /**
+         * Constants of AAI service names
+         */
+        public static class AAIServiceNames {
+            private AAIServiceNames() {
+                throw new IllegalAccessError("AAIServiceNames");
+            }
+            public static final String QUERY = "query";
+            public static final String GET_VNF_DATA = "getVnfData";
+        }
+
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingUtils.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/logging/LoggingUtils.java
new file mode 100644 (file)
index 0000000..c37a9a5
--- /dev/null
@@ -0,0 +1,271 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.logging;
+
+import org.onap.appc.i18n.Msg;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.i18n.EELFResolvableErrorEnum;
+import com.att.eelf.i18n.EELFResourceManager;
+import org.slf4j.MDC;
+import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.UUID;
+
+/**
+ * Logging utilities
+ */
+public class LoggingUtils {
+
+    private static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+    private static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+    private static final EELFLogger metricLogger = EELFManager.getInstance().getMetricsLogger();
+
+    private LoggingUtils() {
+        throw new IllegalAccessError("LoggingUtils");
+    }
+
+    public static void logErrorMessage(String errorCode, String errorDescription,
+            String targetEntity, String targetServiceName, String additionalMessage,
+            String className) {
+        logError(errorCode, errorDescription, targetEntity, targetServiceName, additionalMessage,
+                className);
+    }
+
+    public static void logErrorMessage(String targetEntity, String targetServiceName,
+            String additionalMessage, String className) {
+        logError("", "", targetEntity, targetServiceName, additionalMessage, className);
+    }
+
+    public static void logErrorMessage(String targetServiceName, String additionalMessage,
+            String className) {
+        logError("", "", LoggingConstants.TargetNames.APPC, targetServiceName, additionalMessage,
+                className);
+    }
+
+    private static void logError(String errorCode, String errorDescription, String targetEntity,
+            String targetServiceName, String additionalMessage, String className) {
+        populateErrorLogContext(errorCode, errorDescription, targetEntity, targetServiceName,
+                className);
+        errorLogger.error(additionalMessage == null ? "" : additionalMessage);
+        cleanErrorLogContext();
+    }
+
+    public static void logAuditMessage(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.info(EELFResourceManager.format(Msg.APPC_AUDIT_MSG, MDC.get(MDC_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID),
+                MDC.get(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP),
+                MDC.get(LoggingConstants.MDCKeys.END_TIMESTAMP),
+                MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)));
+        cleanAuditErrorContext();
+    }
+
+    public static void auditInfo(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className, EELFResolvableErrorEnum resourceId,
+            String... arguments) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.info(resourceId, arguments);
+        cleanAuditErrorContext();
+    }
+
+    public static void auditWarn(Instant beginTimeStamp, Instant endTimeStamp, String code,
+            String responseDescription, String className, EELFResolvableErrorEnum resourceId,
+            String... arguments) {
+        populateAuditLogContext(beginTimeStamp, endTimeStamp, code, responseDescription, className);
+        auditLogger.warn(resourceId, arguments);
+        cleanAuditErrorContext();
+    }
+
+    public static void logMetricsMessage(Instant beginTimeStamp, Instant endTimeStamp,
+            String targetEntity, String targetServiceName, String statusCode, String responseCode,
+            String responseDescription, String className) {
+        populateMetricLogContext(beginTimeStamp, endTimeStamp, targetEntity, targetServiceName,
+                statusCode, responseCode, responseDescription, className);
+        metricLogger.info(EELFResourceManager.format(Msg.APPC_METRIC_MSG, MDC.get(MDC_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME), MDC.get(MDC_KEY_REQUEST_ID),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY),
+                MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME),
+                MDC.get(LoggingConstants.MDCKeys.ELAPSED_TIME),
+                MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)));
+        cleanMetricContext();
+    }
+
+    private static void populateAuditLogContext(Instant beginTimeStamp, Instant endTimeStamp,
+            String code, String responseDescription, String className) {
+        populateTimeContext(beginTimeStamp, endTimeStamp);
+        populateRequestContext();
+        String statusCode = ("100".equals(code) || "400".equals(code))
+                ? LoggingConstants.StatusCodes.COMPLETE : LoggingConstants.StatusCodes.ERROR;
+        populateResponseContext(statusCode, code, responseDescription );
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanAuditErrorContext() {
+        cleanRequestContext();
+        cleanTimeContext();
+        cleanResponseContext();
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateErrorLogContext(String errorCode, String errorDescription,
+            String targetEntity, String targetServiceName, String className) {
+        populateErrorContext(errorCode, errorDescription);
+        populateTargetContext(targetEntity, targetServiceName != null ? targetServiceName : "");
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanErrorLogContext() {
+        cleanErrorContext();
+        cleanTargetContext();
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateMetricLogContext(Instant beginTimeStamp, Instant endTimeStamp,
+            String targetEntity, String targetServiceName, String statusCode, String responseCode,
+            String responseDescription, String className) {
+        populateRequestContext();
+        populateTimeContext(beginTimeStamp, endTimeStamp);
+        populateTargetContext(targetEntity, targetServiceName);
+        populateResponseContext(statusCode, responseCode, responseDescription);
+        MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, className != null ? className : "");
+    }
+
+    private static void cleanMetricContext() {
+        cleanRequestContext();
+        cleanTimeContext();
+        cleanTargetContext();
+        cleanResponseContext();
+        MDC.remove(LoggingConstants.MDCKeys.CLASS_NAME);
+    }
+
+    private static void populateTargetContext(String targetEntity, String targetServiceName) {
+        MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, targetEntity != null ? targetEntity : "");
+        MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME,
+                targetServiceName != null ? targetServiceName : "");
+    }
+
+    private static void cleanTargetContext() {
+        MDC.remove(LoggingConstants.MDCKeys.TARGET_ENTITY);
+        MDC.remove(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME);
+    }
+
+    private static void populateRequestContext() {
+        try {
+            UUID.fromString(MDC.get(MDC_KEY_REQUEST_ID));
+            //reaching here without exception means existing RequestId is
+            //valid UUID as per ECOMP logging standards, no-op
+        } catch (Exception e) {
+            MDC.put(MDC_KEY_REQUEST_ID, UUID.randomUUID().toString());
+        }
+
+        try {
+            String partnerName = MDC.get(LoggingConstants.MDCKeys.PARTNER_NAME);
+
+            //ECOMP logging standards require some value for PartnerName.  Default to appc if empty
+            if (partnerName.isEmpty())
+                MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, "appc");
+        } catch (Exception e) {
+            MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, "appc");
+        }
+
+        try {
+            String serviceName = MDC.get(MDC_SERVICE_NAME);
+
+            //ECOMP logging standards require some value for ServiceName.  Default to DEFAULT if empty
+            if (serviceName.isEmpty())
+                MDC.put(MDC_SERVICE_NAME, "DEFAULT");
+        } catch (Exception e) {
+            MDC.put(MDC_SERVICE_NAME, "DEFAULT");
+        }
+    }
+
+    private static void cleanRequestContext() {
+        MDC.remove(MDC_KEY_REQUEST_ID);
+        MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME);
+        MDC.remove(MDC_SERVICE_NAME);
+    }
+    private static void populateTimeContext(Instant beginTimeStamp, Instant endTimeStamp) {
+        String beginTime = "";
+        String endTime = "";
+        String elapsedTime = "";
+
+        if (beginTimeStamp != null && endTimeStamp != null) {
+            elapsedTime = String.valueOf(ChronoUnit.MILLIS.between(beginTimeStamp, endTimeStamp));
+            beginTime = generateTimestampStr(beginTimeStamp);
+            endTime = generateTimestampStr(endTimeStamp);
+        }
+
+        MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, beginTime);
+        MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, endTime);
+        MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, elapsedTime);
+    }
+
+    public static String generateTimestampStr(Instant timeStamp) {
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
+        TimeZone tz = TimeZone.getTimeZone("UTC");
+        df.setTimeZone(tz);
+        return df.format(Date.from(timeStamp));
+    }
+
+    private static void cleanTimeContext() {
+        MDC.remove(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP);
+        MDC.remove(LoggingConstants.MDCKeys.END_TIMESTAMP);
+        MDC.remove(LoggingConstants.MDCKeys.ELAPSED_TIME);
+    }
+
+    private static void populateResponseContext(String statusCode, String responseCode,
+            String responseDescription) {
+        MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, statusCode != null ? statusCode : "");
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, responseCode);
+        MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION,
+                responseDescription != null ? responseDescription : "");
+    }
+
+    private static void cleanResponseContext() {
+        MDC.remove(LoggingConstants.MDCKeys.STATUS_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION);
+    }
+
+    private static void populateErrorContext(String errorCode, String errorDescription) {
+        MDC.put(LoggingConstants.MDCKeys.ERROR_CODE, errorCode);
+        MDC.put(LoggingConstants.MDCKeys.ERROR_DESCRIPTION, errorDescription);
+    }
+
+    private static void cleanErrorContext() {
+        MDC.remove(LoggingConstants.MDCKeys.ERROR_CODE);
+        MDC.remove(LoggingConstants.MDCKeys.ERROR_DESCRIPTION);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/MetadataService.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/MetadataService.java
new file mode 100644 (file)
index 0000000..dfaa462
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata;
+
+import org.onap.appc.metadata.objects.DependencyModelIdentifier;
+
+
+public interface MetadataService {
+    String getVnfModel(DependencyModelIdentifier modelIdentifier);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/impl/MetadataServiceImpl.java
new file mode 100644 (file)
index 0000000..70d2e63
--- /dev/null
@@ -0,0 +1,123 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata.impl;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.ccsdk.sli.core.dblib.DbLibService;
+
+import javax.sql.rowset.CachedRowSet;
+
+import org.onap.appc.cache.MetadataCache;
+import org.onap.appc.cache.impl.MetadataCacheFactory;
+import org.onap.appc.metadata.MetadataService;
+import org.onap.appc.metadata.objects.DependencyModelIdentifier;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+
+public class MetadataServiceImpl implements MetadataService {
+
+    private DbLibService dbLibService;
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(MetadataServiceImpl.class);
+
+    private MetadataCache<DependencyModelIdentifier, String> cache;
+
+    public MetadataServiceImpl() {
+        initialize();
+    }
+
+    private void initialize() {
+        cache = MetadataCacheFactory.getInstance().getMetadataCache();
+        // TODO initialze dbLibService
+    }
+
+    public void setDbLibService(DbLibService dbLibService) {
+        this.dbLibService = dbLibService;
+    }
+
+    void setCache(MetadataCache<DependencyModelIdentifier, String> cache) {
+        this.cache = cache;
+    }
+
+    @Override
+    public String getVnfModel(DependencyModelIdentifier modelIdentifier) {
+        logger.debug("Reading Vnf Model data from cache for vnfType : " + modelIdentifier.getVnfType()
+            + " and catalog version : " + modelIdentifier.getCatalogVersion());
+        String vnfModel = cache.getObject(modelIdentifier);
+        if (vnfModel == null || vnfModel.length() == 0) {
+            logger.debug("Vnf Model not available in cache. Reading from database.");
+            vnfModel = readVnfModel(modelIdentifier);
+            if (vnfModel != null && vnfModel.length() > 0) {
+                logger.debug("Adding retrieved Vnf Model to cache.");
+                addVnfModel(modelIdentifier, vnfModel);
+            }
+        }
+        return vnfModel;
+    }
+
+    private void addVnfModel(DependencyModelIdentifier modelIdentifier, String vnfModel) {
+        cache.putObject(modelIdentifier, vnfModel);
+    }
+
+    private String readVnfModel(DependencyModelIdentifier modelIdentifier) {
+
+        logger.debug("Reading Vnf Model data from database for RESOURCE_NAME : " + modelIdentifier.getVnfType()
+            + " and RESOURCE_VERSION : " + modelIdentifier.getCatalogVersion());
+        StringBuilder query = new StringBuilder();
+        String vnfModel = null;
+        query.append("SELECT ARTIFACT_CONTENT FROM sdnctl.ASDC_ARTIFACTS WHERE RESOURCE_NAME = ? ");
+        ArrayList<String> argList = new ArrayList<>();
+        argList.add(modelIdentifier.getVnfType());
+
+        if (modelIdentifier.getCatalogVersion() == null) {
+            query.append(" ORDER BY  SUBSTRING_INDEX(RESOURCE_VERSION, '.', 1)*1  DESC , " +
+                "SUBSTRING_INDEX(SUBSTRING_INDEX(RESOURCE_VERSION, '.', 2),'.', -1) *1 DESC , " +
+                "SUBSTRING_INDEX(RESOURCE_VERSION, '.', -1)*1 DESC ;");
+        } else {
+            query.append("AND RESOURCE_VERSION = ? ;");
+            argList.add(modelIdentifier.getCatalogVersion());
+        }
+        try {
+            final CachedRowSet data = dbLibService.getData(query.toString(), argList, "sdnctl");
+            if (data.first()) {
+                vnfModel = data.getString("ARTIFACT_CONTENT");
+                if (vnfModel == null || vnfModel.isEmpty()) {
+                    logger.error("Invalid dependency model for vnf type : " + modelIdentifier.getVnfType()
+                        + " and catalog version : " + modelIdentifier.getCatalogVersion());
+                    throw new RuntimeException("Invalid or Empty VNF Model");
+                }
+                logger.debug("Retrieved Vnf Model : " + vnfModel);
+            } else {
+                logger.warn("VNF Model not found in datastore for RESOURCE_NAME : " + modelIdentifier.getVnfType()
+                    + " AND RESOURCE_VERSION : " + modelIdentifier.getCatalogVersion());
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException("Database error occurred");
+        }
+        return vnfModel;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/metadata/objects/DependencyModelIdentifier.java
new file mode 100644 (file)
index 0000000..070e200
--- /dev/null
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata.objects;
+
+/**
+ * Object of identifier for dependency model. Currently uses VNF type and catalog version
+ */
+public class DependencyModelIdentifier {
+    static final String TO_STRING_FORMAT =
+            "DependencyModelIdentifier : vnfType = %s , catalogVersion = %s";
+    static final int prime = 31;
+
+    private String vnfType;
+    private String catalogVersion;
+
+    /**
+     * Constructor
+     * 
+     * @param vnfType String of the VNF type
+     * @param catalogVersion String of the catalog version
+     */
+    public DependencyModelIdentifier(String vnfType, String catalogVersion) {
+        this.vnfType = vnfType;
+        this.catalogVersion = catalogVersion;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        result = result * prime + (this.vnfType == null ? 0 : this.vnfType.hashCode());
+        result = result * prime
+                + (this.catalogVersion == null ? 0 : this.catalogVersion.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof DependencyModelIdentifier)) {
+            return false;
+        }
+
+        DependencyModelIdentifier modelIdentifier = (DependencyModelIdentifier) obj;
+        if (this.vnfType == null) {
+            if (modelIdentifier.vnfType != null) {
+                return false;
+            }
+        } else if (!this.vnfType.equals(modelIdentifier.vnfType)) {
+            return false;
+        }
+
+        if (this.catalogVersion == null) {
+            if (modelIdentifier.catalogVersion != null) {
+                return false;
+            }
+        } else if (!this.catalogVersion.equals(modelIdentifier.catalogVersion)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(TO_STRING_FORMAT, vnfType, catalogVersion);
+    }
+
+    public String getVnfType() {
+        return vnfType;
+    }
+
+    public String getCatalogVersion() {
+        return catalogVersion;
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Allocator.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Allocator.java
new file mode 100644 (file)
index 0000000..9992e89
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+
+/**
+ * This interface is used to supply an object that will be called by the pool manager whenever a new widget must be
+ * allocated.
+ * @param <T>
+ *            The generic type that we are caching.
+ */
+
+public interface Allocator<T extends Closeable> {
+
+    /**
+     * Allocate an object of type <T> and return it to the pool
+     *
+     * @param pool
+     *            The pool that the object is to be allocated to
+     * @return An object of type T
+     */
+    T allocate(Pool<T> pool);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CacheManagement.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CacheManagement.java
new file mode 100644 (file)
index 0000000..d0051a8
--- /dev/null
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+public interface CacheManagement {
+
+    /**
+     * @return The object that is actually being wrapped and cached
+     */
+    Object getWrappedObject();
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CachedElement.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/CachedElement.java
new file mode 100644 (file)
index 0000000..e9b2ffe
--- /dev/null
@@ -0,0 +1,214 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class is used as a "wrapper" for any closeable elements that are cached in a pool. It is
+ * implemented as a dynamic proxy, so that it appears to be the same class of object to the client
+ * as the interface being cached. The generic type being cached MUST be an interface.
+ * 
+ * @param <T> The generic type that we create a cached element for. This type is used to wrap
+ *        instances of this type and expose access to the {@link java.io.Closeable} interface by
+ *        using a dynamic proxy.
+ */
+
+public class CachedElement<T extends Closeable>
+        implements Closeable, InvocationHandler, CacheManagement {
+
+    /**
+     * The pool that is managing this cached element
+     */
+    private Pool<T> pool;
+
+    /**
+     * The element that we are caching in the pool
+     */
+    private T element;
+
+    /**
+     * A thread-safe atomic indicator that tells us that the wrapped element has been released to
+     * the pool already, and not to do it again.
+     */
+    private AtomicBoolean released = new AtomicBoolean(false);
+
+    /**
+     * Create a new instance of a cached element dynamic proxy for use in the pool.
+     * <p>
+     * This returns an instance of the proxy to the caller that appears to be the same interface(s)
+     * as the object being cached. The dynamic proxy then intercepts all open and close semantics
+     * and directs that element to the pool.
+     * </p>
+     * <p>
+     * If the object being proxied does not implement the {@link CacheManagement} interface, then
+     * that interface is added to the dynamic proxy being created. This interface is actually
+     * implemented by the invocation handler (this object) for the proxy and allows direct access to
+     * the wrapped object inside the proxy.
+     * </p>
+     *
+     * @param pool The pool that we are caching these elements within
+     * @param element The element actually being cached
+     * @param interfaces The interface list of interfaces the element must implement (usually one)
+     * @return The dynamic proxy
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Closeable> T newInstance(Pool<T> pool, T element,
+            Class<?>[] interfaces) {
+        ClassLoader cl = element.getClass().getClassLoader();
+        CachedElement<T> ce = new CachedElement<>(pool, element);
+        boolean found = false;
+        for (Class<?> intf : interfaces) {
+            if (intf.getName().equals(CacheManagement.class.getName())) {
+                found = true;
+                break;
+            }
+        }
+
+        int length = found ? interfaces.length : interfaces.length + 1;
+        Class<?>[] proxyInterfaces = new Class[length];
+        System.arraycopy(interfaces, 0, proxyInterfaces, 0, interfaces.length);
+
+        if (!found) {
+            proxyInterfaces[interfaces.length] = CacheManagement.class;
+        }
+
+        return (T) Proxy.newProxyInstance(cl, proxyInterfaces, ce);
+    }
+
+    /**
+     * Construct a cached element and assign it to the pool as a free element
+     *
+     * @param pool The pool that the element will be managed within
+     * @param element The element we are caching
+     */
+    @SuppressWarnings("unchecked")
+    public CachedElement(Pool<T> pool, T element) {
+        this.pool = pool;
+        this.element = element;
+
+        try {
+            pool.release((T) this);
+        } catch (PoolDrainedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * This method delegates the close call to the actual wrapped element.
+     * <p>
+     * NOTE: This is not the same method that is called by the dynamic proxy. This method is in
+     * place to satisfy the signature of the {@link java.io.Closeable} interface. If it were to be
+     * called directly, then we will delegate the close to the underlying context. However, when the
+     * cached element is called as a synamic proxy, entry is in the
+     * {@link #invoke(Object, Method, Object[])} method.
+     * </p>
+     * 
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() throws IOException {
+        element.close();
+    }
+
+    /**
+     * This method is the magic part of dynamic proxies. When the caller makes a method call based
+     * on the interface being proxied, this method is given control. This informs us of the method
+     * and arguments of the call. The object reference is that of the dynamic proxy itself, which is
+     * us.
+     * <p>
+     * Here we will check to see if the user is trying to close the "element" (the dynamic proxy
+     * acts like the wrapped element). If he is, then we don't really close it, but instead release
+     * the element that we are wrapping back to the free pool. Once this has happened, we mark the
+     * element as "closed" (from the perspective of this dynamic proxy) so that we wont try to
+     * release it again.
+     * </p>
+     * <p>
+     * If the method is the <code>equals</code> method then we assume that we are comparing the
+     * cached element in one dynamic proxy to the cached element in another. We execute the
+     * comparison between the cached elements, and not the dynamic proxies themselves. This
+     * preserves the allusion to the caller that the dynamic proxy is the object being wrapped.
+     * </p>
+     * <p>
+     * For convenience, we also implement the <code>getWrappedObject</code> method so that the
+     * dynamic proxy can be called to obtain the actual wrapped object if desired. Note, to use this
+     * method, the caller would have to invoke it through reflection.
+     * </p>
+     * <p>
+     * If the method being invoked is not one that we intercept, then we simply delegate that method
+     * onto the wrapped object.
+     * </p>
+     * 
+     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method,
+     *      java.lang.Object[])
+     */
+    @SuppressWarnings({"unchecked", "nls"})
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
+        Object result = null;
+
+        switch (method.getName()) {
+            case "close":
+                if (released.compareAndSet(false, true)) {
+                    if (!pool.isDrained()) {
+                        pool.release((T) proxy);
+                    }
+                }
+                break;
+            case "equals":
+                CacheManagement cm = (CacheManagement) proxy;
+                T other = (T) cm.getWrappedObject();
+                result = element.equals(other);
+                break;
+            case "getWrappedObject":
+                return element;
+            default:
+                result = method.invoke(element, args);
+                break;
+        }
+
+        return result;
+    }
+
+    /**
+     * This method is used to be able to access the wrapped object underneath the dynamic proxy
+     * 
+     * @see org.onap.appc.pool.CacheManagement#getWrappedObject()
+     */
+    @Override
+    public T getWrappedObject() {
+        return element;
+    }
+
+    @SuppressWarnings("nls")
+    @Override
+    public String toString() {
+        return element == null ? "null" : element.toString();
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Destructor.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Destructor.java
new file mode 100644 (file)
index 0000000..6c7e7d4
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+
+/**
+ * @param <T>
+ *            The generic type we are caching
+ */
+
+public interface Destructor<T extends Closeable> {
+
+    /**
+     * Called to destroy the object when it is no longer being used by the pool
+     *
+     * @param obj
+     *            The object to be destroyed
+     * @param pool
+     *            The pool that the object is being removed from
+     */
+    void destroy(T obj, Pool<T> pool);
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Pool.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/Pool.java
new file mode 100644 (file)
index 0000000..1faf0fe
--- /dev/null
@@ -0,0 +1,371 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class is used to manage a pool of things.
+ * <p>
+ * The class is parameterized so that the type of objects maintained in the pool is definable by some provided type.
+ * This type must implement the <code>Comparable</code> interface so that it can be managed in the pool.
+ * </p>
+ * 
+ * @param <T>
+ *            The type of element being pooled
+ */
+
+public class Pool<T extends Closeable> {
+    private Deque<T> free;
+    private List<T> allocated;
+    private int minPool;
+    private int maxPool;
+    private Allocator<T> allocator;
+    private Destructor<T> destructor;
+    private ReadWriteLock lock;
+    private AtomicBoolean drained;
+    private Properties properties;
+
+    /**
+     * Create the pool
+     *
+     * @param minPool
+     *            The minimum size of the pool
+     * @param maxPool
+     *            The maximum size of the pool, set to zero (0) for unbounded
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    public Pool(int minPool, int maxPool) throws PoolSpecificationException {
+
+        if (minPool < 0) {
+            throw new PoolSpecificationException(String.format("The minimum pool size must be a "
+                + "positive value or zero, %d is not valid.", minPool));
+        }
+        if (maxPool != 0 && maxPool < minPool) {
+            throw new PoolSpecificationException(String.format("The maximum pool size must be a "
+                + "positive value greater than the minimum size, or zero. %d is not valid.", maxPool));
+        }
+
+        this.minPool = minPool;
+        this.maxPool = maxPool;
+
+        properties = new Properties();
+        free = new ArrayDeque<T>();
+        allocated = new ArrayList<T>();
+        lock = new ReentrantReadWriteLock();
+        drained = new AtomicBoolean(false);
+    }
+
+    /**
+     * Returns the amount of objects on the free collection
+     *
+     * @return The number of objects on the free collection
+     */
+    public int getFreeSize() {
+        Lock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            return free.size();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the value for a specified property of this pool, if defined.
+     * 
+     * @param key
+     *            The key of the desired property
+     * @return The value of the property, or null if not defined
+     */
+    public String getProperty(String key) {
+        return properties.getProperty(key);
+    }
+
+    /**
+     * Sets the value of the specified property or replaces it if it already exists
+     * 
+     * @param key
+     *            The key of the property to be set
+     * @param value
+     *            The value to set the property to
+     */
+    public void setProperty(String key, String value) {
+        properties.setProperty(key, value);
+    }
+
+    /**
+     * @return The properties object for the pool
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Returns the number of objects that are currently allocated
+     *
+     * @return The allocate collection size
+     */
+    public int getAllocatedSize() {
+        Lock readLock = lock.readLock();
+        readLock.lock();
+        try {
+            return allocated.size();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * @return the value of allocator
+     */
+    public Allocator<T> getAllocator() {
+        return allocator;
+    }
+
+    /**
+     * @param allocator
+     *            the value for allocator
+     */
+    public void setAllocator(Allocator<T> allocator) {
+        this.allocator = allocator;
+    }
+
+    /**
+     * @return the value of destructor
+     */
+    public Destructor<T> getDestructor() {
+        return destructor;
+    }
+
+    /**
+     * @return the value of minPool
+     */
+    public int getMinPool() {
+        return minPool;
+    }
+
+    /**
+     * @return the value of maxPool
+     */
+    public int getMaxPool() {
+        return maxPool;
+    }
+
+    /**
+     * @param destructor
+     *            the value for destructor
+     */
+    public void setDestructor(Destructor<T> destructor) {
+        this.destructor = destructor;
+    }
+
+    /**
+     * Drains the pool, releasing and destroying all pooled objects, even if they are currently allocated.
+     */
+    public void drain() {
+        if (drained.compareAndSet(false, true)) {
+            Lock writeLock = lock.writeLock();
+            writeLock.lock();
+            try {
+                int size = getAllocatedSize();
+                /*
+                 * We can't use the "release" method call here because we are modifying the list we are iterating
+                 */
+                ListIterator<T> it = allocated.listIterator();
+                while (it.hasNext()) {
+                    T obj = it.next();
+                    it.remove();
+                    free.addFirst(obj);
+                }
+                size = getFreeSize();
+                trim(size);
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Returns an indication if the pool has been drained
+     *
+     * @return True indicates that the pool has been drained. Once a pool has been drained, it can no longer be used.
+     */
+    public boolean isDrained() {
+        return drained.get();
+    }
+
+    /**
+     * Reserves an object of type T from the pool for the caller and returns it
+     *
+     * @return The object of type T to be used by the caller
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @SuppressWarnings("unchecked")
+    public T reserve() throws PoolExtensionException, PoolDrainedException {
+        if (isDrained()) {
+            throw new PoolDrainedException("The pool has been drained and cannot be used.");
+        }
+
+        T obj = null;
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            int freeSize = getFreeSize();
+            int allocatedSize = getAllocatedSize();
+
+            if (freeSize == 0) {
+                if (allocatedSize == 0) {
+                    extend(minPool == 0 ? 1 : minPool);
+                } else if (allocatedSize >= maxPool && maxPool > 0) {
+                    throw new PoolExtensionException(String.format("Unable to add "
+                        + "more elements, pool is at maximum size of %d", maxPool));
+                } else {
+                    extend(1);
+                }
+            }
+
+            obj = free.removeFirst();
+            allocated.add(obj);
+        } finally {
+            writeLock.unlock();
+        }
+
+        /*
+         * Now that we have the real object, lets wrap it in a dynamic proxy so that we can intercept the close call and
+         * just return the context to the free pool. obj.getClass().getInterfaces(). We need to find ALL interfaces that
+         * the object (and all superclasses) implement and have the proxy implement them too
+         */
+        Class<?> cls = obj.getClass();
+        Class<?>[] array;
+        List<Class<?>> interfaces = new ArrayList<Class<?>>();
+        while (!cls.equals(Object.class)) {
+            array = cls.getInterfaces();
+            for (Class<?> item : array) {
+                if (!interfaces.contains(item)) {
+                    interfaces.add(item);
+                }
+            }
+            cls = cls.getSuperclass();
+        }
+        array = new Class<?>[interfaces.size()];
+        array = interfaces.toArray(array);
+        return CachedElement.newInstance(this, obj, array);
+    }
+
+    /**
+     * releases the allocated object back to the free pool to be used by another request.
+     *
+     * @param obj
+     *            The object to be returned to the pool
+     * @throws PoolDrainedException
+     *             If the caller is trying to release an element to a drained pool
+     */
+    public void release(T obj) throws PoolDrainedException {
+        if (isDrained()) {
+            throw new PoolDrainedException("The pool has been drained and cannot be used.");
+        }
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            if (allocated.remove(obj)) {
+                free.addFirst(obj);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Extend the free pool by some number of elements
+     *
+     * @param count
+     *            The number of elements to add to the pool
+     * @throws PoolExtensionException
+     *             if the pool cannot be extended because no allocator has been specified.
+     */
+    private void extend(int count) throws PoolExtensionException {
+        if (allocator == null) {
+            throw new PoolExtensionException(String.format("Unable to extend pool "
+                + "because no allocator has been specified"));
+        }
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            for (int index = 0; index < count; index++) {
+                T obj = allocator.allocate(this);
+                if (obj == null) {
+                    throw new PoolExtensionException(
+                        "The allocator failed to allocate a new context to extend the pool.");
+                }
+                free.push(obj);
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Used to trim the free collection by some specified number of elements, or the free element count, whichever is
+     * less. The elements are removed from the end of the free element deque, thus trimming the oldest elements first.
+     *
+     * @param count
+     *            The number of elements to trim
+     */
+    private void trim(int count) {
+        Lock writeLock = lock.writeLock();
+        writeLock.lock();
+        try {
+            int trimCount = count;
+            if (getFreeSize() < count) {
+                trimCount = getFreeSize();
+            }
+            for (int i = 0; i < trimCount; i++) {
+                T obj = free.removeLast();
+                if (destructor != null) {
+                    destructor.destroy(obj, this);
+                }
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolDrainedException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolDrainedException.java
new file mode 100644 (file)
index 0000000..0831366
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * This exception is thrown whenever an attempt is made to access a pool of resources where the pool has been drained.
+ * Once drained, the pool is no longer usable.
+ *
+ */
+public class PoolDrainedException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolDrainedException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolDrainedException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolException.java
new file mode 100644 (file)
index 0000000..9b22eee
--- /dev/null
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * A pool exception is a specialization of checked exceptions that define various pool abnormal states or requests.
+ *
+ */
+public class PoolException extends Exception {
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolException constructor
+     */
+    public PoolException() {
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     */
+    public PoolException(String message) {
+        super(message);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param cause
+     *            The cause of the exception
+     */
+    public PoolException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     * @param cause
+     *            The cause of the exception
+     */
+    public PoolException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * PoolException constructor
+     *
+     * @param message
+     *            The error message
+     * @param cause
+     *            The cause of the exception
+     * @param enableSuppression
+     *            whether or not suppression is enabled or disabled
+     * @param writableStackTrace
+     *            whether or not the stack trace should be writable
+     */
+    public PoolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolExtensionException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolExtensionException.java
new file mode 100644 (file)
index 0000000..9daaca1
--- /dev/null
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * An error occurred trying to extend the pool
+ *
+ */
+public class PoolExtensionException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolExtensionException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolExtensionException(String msg) {
+        super(msg);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolSpecificationException.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/pool/PoolSpecificationException.java
new file mode 100644 (file)
index 0000000..d1f2189
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+/**
+ * This exception is thrown whenever the pool is not specified correctly
+ * 
+ */
+public class PoolSpecificationException extends PoolException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * PoolSpecificationException constructor
+     *
+     * @param msg
+     *            The error message
+     */
+    public PoolSpecificationException(String msg) {
+        super(msg);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/rest/client/RestClientInvoker.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/rest/client/RestClientInvoker.java
new file mode 100644 (file)
index 0000000..41a0a85
--- /dev/null
@@ -0,0 +1,258 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.rest.client;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.onap.appc.exceptions.APPCException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+@SuppressWarnings("deprecation")
+public class RestClientInvoker {
+
+    private static final EELFLogger LOG = EELFManager.getInstance().getLogger(RestClientInvoker.class);
+    private static final String OPERATION_HTTPS = "https";
+    private static final String OPERATION_APPLICATION_JSON = " application/json";
+    private static final String BASIC = "Basic ";
+
+    private URL url = null;
+    private String basicAuth = null;
+
+    public RestClientInvoker(URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Sets the basic authentication header for the given user and password. If either entry is null
+     * then does not set basic auth
+     *
+     * @param user The user with optional domain name (for AAF)
+     * @param password The password for the user
+     */
+    public void setAuthentication(String user, String password) {
+        if (user != null && password != null) {
+            String authStr = user + ":" + password;
+            basicAuth = new String(Base64.encodeBase64(authStr.getBytes()));
+        }
+    }
+
+    public HttpResponse doPost(String path, String body) throws APPCException {
+        HttpPost post;
+
+        try {
+
+            URL postUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            post = new HttpPost(postUrl.toExternalForm());
+            post.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            post.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                post.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+            StringEntity entity = new StringEntity(body);
+            entity.setContentType(OPERATION_APPLICATION_JSON);
+            post.setEntity(new StringEntity(body));
+        } catch (MalformedURLException | UnsupportedEncodingException e) {
+            throw new APPCException(e);
+        }
+        HttpClient client = getHttpClient();
+
+        try {
+            return client.execute(post);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    /**
+     * This is Generic method that can be used to perform REST Put operation
+     *
+     * @param path - path for put
+     * @param body - payload for put action which will be sent as request body.
+     * @return - HttpResponse object which is returned from put REST call.
+     * @throws APPCException when error occurs
+     */
+    public HttpResponse doPut(String path, String body) throws APPCException {
+        HttpPut put;
+        try {
+            URL putUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            put = new HttpPut(putUrl.toExternalForm());
+            put.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            put.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                put.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+            StringEntity entity = new StringEntity(body);
+            entity.setContentType(OPERATION_APPLICATION_JSON);
+            put.setEntity(new StringEntity(body));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        HttpClient client = getHttpClient();
+
+        try {
+            return client.execute(put);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    public HttpResponse doGet(String path) throws APPCException {
+        HttpGet get;
+        try {
+            URL getUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
+            get = new HttpGet(getUrl.toExternalForm());
+            get.setHeader(HttpHeaders.CONTENT_TYPE, OPERATION_APPLICATION_JSON);
+            get.setHeader(HttpHeaders.ACCEPT, OPERATION_APPLICATION_JSON);
+
+            if (basicAuth != null) {
+                get.setHeader(HttpHeaders.AUTHORIZATION, BASIC + basicAuth);
+            }
+
+        } catch (Exception e) {
+            throw new APPCException(e);
+        }
+
+        try (CloseableHttpClient client = getHttpClient()) {
+            return client.execute(get);
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+    }
+
+    private CloseableHttpClient getHttpClient() throws APPCException {
+        switch (url.getProtocol()) {
+            case OPERATION_HTTPS:
+                return createHttpsClient();
+            case "http":
+                return new DefaultHttpClient();
+            default:
+                throw new APPCException("The url did not start with http[s]");
+        }
+    }
+
+
+    private CloseableHttpClient createHttpsClient() {
+        try {
+            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            trustStore.load(null, null);
+            MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
+            sf.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+            HttpParams params = new BasicHttpParams();
+            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+            registry.register(new Scheme(OPERATION_HTTPS, sf, 443));
+            registry.register(new Scheme(OPERATION_HTTPS, sf, 8443));
+            registry.register(new Scheme("http", sf, 8181));
+
+            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+            return new DefaultHttpClient(ccm, params);
+        } catch (Exception e) {
+            LOG.error("Error creating HTTPs Client. Creating default client.", e);
+            return new DefaultHttpClient();
+        }
+    }
+
+    private static class MySSLSocketFactory extends SSLSocketFactory {
+        private SSLContext sslContext = SSLContext.getInstance("TLS");
+
+        private MySSLSocketFactory(KeyStore truststore)
+                throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+            super(truststore);
+
+            TrustManager tm = new X509TrustManager() {
+                @Override
+                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                    LOG.debug("Inside checkClientTrusted");
+                }
+
+                @Override
+                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                    LOG.debug("Inside checkServerTrusted");
+                }
+
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return new X509Certificate[1];
+                }
+            };
+
+            sslContext.init(null, new TrustManager[] {tm}, null);
+        }
+
+        @Override
+        public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
+            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
+        }
+
+        @Override
+        public Socket createSocket() throws IOException {
+            return sslContext.getSocketFactory().createSocket();
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/JsonUtil.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/JsonUtil.java
new file mode 100644 (file)
index 0000000..1478459
--- /dev/null
@@ -0,0 +1,126 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+public class JsonUtil {
+
+    static ObjectMapper MAPPER = null;
+    static {
+        MAPPER = new ObjectMapper();
+        MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
+        MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
+        MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // allow translation even
+                                                                           // if extra attrs exist
+                                                                           // in the json
+        MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+        // Uncomment below when Jackson is upgraded to version 2.7 or above
+        // MAPPER.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
+    }
+
+    /**
+     * @param valueAsString a valid json Map represented as String
+     * @return a flat map that each entry key derived from hierarchy path in the json object and
+     *         flatted to a dotted separated string. e.g.
+     *         "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}"; will be
+     *         represented as {A=A-value, B.C=B.C-value, B.D=B.D-value} when it required that the
+     *         input will not be flatted the json string should be formatted as below example: e.g.
+     *         "{\"A\":\"A-value\",\"B\":\"{\\\"C\\\":\\\"C-value\\\",\\\"D\\\":\\\"D-value\\\"}\"}"
+     *         will be represented as {A=A-value, B={"C":"C-value","D":"D-value"}}
+     * @throws IOException when the object is not valid json Map
+     */
+    public static Map<String, String> convertJsonStringToFlatMap(String valueAsString)
+            throws IOException {
+        Map readValueMap = MAPPER.readValue(valueAsString, Map.class);
+        return org.onap.appc.util.ObjectMapper.map(readValueMap);
+    }
+
+    /**
+     * 0 is the getStackTrace method 1 is the current method 2 is the parent method, 3 is the
+     * grandparent method or the parent class in this case.
+     */
+    private static final int PARENT_CLASS_INDEX = 3;
+
+
+    /**
+     * @see #readInputJson(String, Class, Class)
+     */
+    public static <T> T readInputJson(String location, Class<T> returnClass) throws IOException {
+        return readInputJson(location, returnClass, getCallingClass(PARENT_CLASS_INDEX));
+    }
+
+    /**
+     * @param location The location or name of the file we are trying to read e.g. JsonBody.json
+     * @param returnClass The class *this* Json is suppose to represent.
+     * @param locationClass The starting point for json lookup. the value specified by location is
+     *        relative to this class.
+     * @return The object being returned
+     * @throws IOException Can't find the specified json file at Location.
+     */
+    public static <T> T readInputJson(String location, Class<T> returnClass, Class<?> locationClass)
+            throws IOException {
+        try (InputStream is = locationClass.getResourceAsStream(location)) {
+            validateInput(is, location);
+            return MAPPER.readValue(is, returnClass);
+        }
+    }
+
+    /**
+     * Note that this method is sensitive to the depth of the call stack. For example if a public
+     * method calls a private method, that calls this method likely the desired classIndex value is
+     * 4 rather than 3. However, it's convenient to reduce the input required by callers of this
+     * class.
+     *
+     * @param classIndex How far up the stack trace to find the class we want.
+     * @return The class that called one of the public methods of this class.
+     */
+    private static Class<?> getCallingClass(int classIndex) {
+        String className = Thread.currentThread().getStackTrace()[classIndex].getClassName();
+        try {
+            return Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            // Theoretically impossible.
+            throw new IllegalStateException(
+                    "Could not do class lookup for class in our stack trace?!?");
+        }
+    }
+
+    private static void validateInput(InputStream is, String location)
+            throws FileNotFoundException {
+        if (is == null) {
+            throw new FileNotFoundException(String.format("Could not find file at '%s'", location));
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/MessageFormatter.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/MessageFormatter.java
new file mode 100644 (file)
index 0000000..a46047e
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import org.apache.commons.lang3.StringUtils;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class MessageFormatter {
+    private final static String paramNameRegexGroupName = "paramName";
+
+    /**
+     * start with ${ and after there is one or more characters that are not $ and not } and ended with }
+     */
+    private final static String paramRegex = "\\$\\{(?<paramName>[^}$]+)\\}";
+
+    public static String format(String messageTemplate, Map<String, Object> params) {
+        if (StringUtils.isEmpty(messageTemplate))
+            return "";
+        if (params == null || params.isEmpty())
+            return messageTemplate;
+
+        String formattedMessage = messageTemplate;
+        if (formattedMessage.contains("$")) {
+            for (Map.Entry<String, Object> entry : params.entrySet()) {
+                formattedMessage = formattedMessage.replaceAll("\\$\\{" + entry.getKey() + "\\}",
+                        escapeDollarChar(String.valueOf(entry.getValue())));
+            }
+        }
+
+        return formattedMessage;
+    }
+
+    private static String escapeDollarChar(String msg) {
+        String formatedMsg = msg;
+        if (formatedMsg.contains("$")) {
+            formatedMsg = formatedMsg.replaceAll("\\$", "\\\\\\$");
+
+        }
+        return formatedMsg;
+    }
+
+    public static List<String> getParamsNamesList(String messageTemplate) {
+        List<String> paramsNames = null;
+        if (!StringUtils.isEmpty(messageTemplate)) {
+            paramsNames = new ArrayList<>();
+            Matcher m = Pattern.compile(paramRegex).matcher(messageTemplate);
+            while (m.find()) {
+                String paramName = m.group(paramNameRegexGroupName);
+                paramsNames.add(paramName);
+            }
+        }
+        return paramsNames;
+    }
+
+    public static Set<String> getParamsNamesSet(String messageTemplate) {
+        List<String> paramsNamesList = getParamsNamesList(messageTemplate);
+        Set<String> paramsNamesSet = null;
+        if (paramsNamesList != null && !paramsNamesList.isEmpty()) {
+            paramsNamesSet = new HashSet<String>();
+            for (String paramName : paramsNamesList) {
+                paramsNamesSet.add(paramName);
+            }
+        }
+        return paramsNamesSet;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/ObjectMapper.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/ObjectMapper.java
new file mode 100644 (file)
index 0000000..e4b76dd
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.lang.reflect.Array;
+import java.util.Map;
+
+public class ObjectMapper {
+
+       private ObjectMapper() {
+       }
+
+       private static void dispatch(PathContext context, Object obj) {
+
+               if (obj == null) {
+                       return;
+               }
+
+               final Class<?> cls = obj.getClass();
+
+               if (cls.isPrimitive()
+                               || String.class.isAssignableFrom(cls)
+                               || Number.class.isAssignableFrom(cls)
+                               || Boolean.class.isAssignableFrom(cls)) {
+                       handlePrimitive(context, obj);
+               } else if (cls.isArray()) {
+                       handleArray(context, obj);
+               } else if (Map.class.isAssignableFrom(cls)) {
+                       handleMap(context, (Map<?, ?>) obj);
+               } else if (Iterable.class.isAssignableFrom(cls)) {
+                       handleCollection(context, Iterable.class.cast(obj));
+               } else {
+                       throw new IllegalArgumentException(obj.getClass().getName());
+               }
+       }
+
+       public static Map<String, String> map(Object obj) {
+               PathContext context = new PathContext();
+               dispatch(context, obj);
+               return context.entries();
+       }
+
+       private static void handleMap(PathContext context, Map<?, ?> val) {
+               for (Map.Entry<?, ?> entry : val.entrySet()) {
+                       context.pushToken(entry.getKey().toString());
+                       dispatch(context, entry.getValue());
+                       context.popToken();
+               }
+       }
+
+       private static void handleCollection(PathContext context, Iterable<?> val) {
+               int index = 0;
+               for (Object elem : val) {
+                       handleElement(context, index++, elem);
+               }
+       }
+
+       private static void handleArray(PathContext context, Object val) {
+               for (int i = 0, n = Array.getLength(val); i < n; i++) {
+                       handleElement(context, i, Array.get(val, i));
+               }
+       }
+
+       private static void handleElement(PathContext context, int index, Object val) {
+               if (val == null) {
+                       return;
+               }
+
+               String modifier = new StringBuilder().append('[').append(Integer.valueOf(index)).append(']').toString();
+
+               context.pushModifier(modifier);
+               dispatch(context, val);
+               context.popModifier();
+       }
+
+       private static void handlePrimitive(PathContext context, Object val) {
+               context.entry(context.getPath(), val.toString());
+       }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/PathContext.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/PathContext.java
new file mode 100644 (file)
index 0000000..d57837c
--- /dev/null
@@ -0,0 +1,102 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+class PathContext {
+
+       private StringBuilder path = new StringBuilder(128);
+
+       private LinkedList<Integer> indexes = new LinkedList<>();
+       private Map<String, String> entries = new LinkedHashMap<>();
+       private int offset = 0;
+
+       private final String delimiter;
+
+       PathContext() {
+               this(".");
+       }
+
+       PathContext(String delimiter) {
+               this.delimiter = delimiter;
+       }
+
+       private void push(String elem, boolean delimit) {
+               if (elem == null) {
+                       throw new IllegalArgumentException();
+               }
+
+               int length = elem.length();
+
+               if (delimit && !indexes.isEmpty()) {
+                       path.append(delimiter);
+                       length += delimiter.length();
+               }
+
+               path.append(elem);
+               offset += length;
+               indexes.addLast(Integer.valueOf(length));
+       }
+
+       private void pop() {
+               if (indexes.isEmpty()) {
+                       throw new IllegalStateException();
+               }
+               offset -= indexes.removeLast();
+               path.setLength(offset);
+       }
+
+       void pushToken(String token) {
+               push(token, true);
+       }
+
+       void popToken() {
+               pop();
+       }
+
+       void pushModifier(String modifier) {
+               push(modifier, false);
+       }
+
+       void popModifier() {
+               pop();
+       }
+
+       String getPath() {
+               return path.substring(0, offset);
+       }
+
+       void entry(String name, String value) {
+               entries.put(name, value);
+       }
+
+       Map<String, String> entries() {
+               return Collections.unmodifiableMap(entries);
+       }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StreamHelper.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StreamHelper.java
new file mode 100644 (file)
index 0000000..4468c84
--- /dev/null
@@ -0,0 +1,62 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+public class StreamHelper {
+
+    /**
+     * private default constructor prevents instantiation
+     */
+    private StreamHelper() {
+    }
+
+    /**
+     * @param inputStream
+     * @return Input stream converted to string
+     */
+    public static String getStringFromInputStream(InputStream inputStream) {
+        StringBuffer buffer = new StringBuffer();
+        byte[] array = new byte[4096];
+
+        if (inputStream != null) {
+            try {
+                int len = inputStream.read(array);
+                while (len != -1) {
+                    buffer.append(new String(array, 0, len, Charset.forName("UTF-8")));
+                    len = inputStream.read(array);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return buffer.toString();
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StringHelper.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StringHelper.java
new file mode 100644 (file)
index 0000000..920ce42
--- /dev/null
@@ -0,0 +1,604 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class contains several static helper methods that can be used to perform string manipulation algorithms.
+ */
+
+public final class StringHelper {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(StringHelper.class);
+
+    public static final String DASH = "-";
+    public static final String DOT = ".";
+    public static final String ELLIPSES = "...";
+    public static final String LINE_FEED = "\n";
+    public static final String SLASH = "/";
+    public static final String COMMA = ",";
+
+    /**
+     * Converts the specified string pattern to a regular expression string. If the supplied string is null or empty,
+     * then a regular expression that matches all strings (.*) is returned.
+     * <p>
+     * The expression passed to this method should not already be a regular expression. If it contains problematic
+     * meta-characters for this routine (such as period, asterisk, and plus), they will be escaped and matched literally
+     * in the resulting regular expression returned.
+     * </p>
+     *
+     * @param value
+     *            The pattern that we need to convert to a regular expression
+     * @return The regular expression that is equivalent to the pattern
+     */
+    public static String convertToRegex(String value) {
+        if (value == null || value.trim().length() == 0) {
+            return ".*";
+        }
+
+        StringBuilder builder = new StringBuilder(value.trim());
+
+        /*
+         * If there are any period characters, we need to escape them so that they are exactly matched
+         */
+        Pattern pattern = Pattern.compile("\\.");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.replace(matcher.start(), matcher.end(), "\\.");
+            position = matcher.end() + 1;
+        }
+
+        /*
+         * If there are any asterisks or pluses, which we need to interpret as wildcard characters, we need to convert
+         * them into .* or .
+         */
+        pattern = Pattern.compile("\\*|\\+");
+        matcher = pattern.matcher(builder);
+
+        /*
+         * If the string contains a .* meta-character sequence anywhere in the middle of the string (i.e., there are
+         * other characters following the .* meta-characters), OR the string ends with the .+ sequence, then we need to
+         * append the "end-of-line" boundary condition to the end of the string to get predictable results.
+         */
+        if (resolveAppendingEOL(builder, matcher)) {
+            builder.append("$");
+        }
+        return builder.toString();
+    }
+
+    private static boolean resolveAppendingEOL(StringBuilder builder, Matcher matcher) {
+        int position = 0;
+        boolean appendEOL = false;
+
+        while (matcher.find(position)) {
+            String metachar = builder.substring(matcher.start(), matcher.end());
+            if ("*".equals(metachar)) {
+                builder.replace(matcher.start(), matcher.end(), ".*");
+                position = matcher.end() + 1;
+                if (matcher.end() < builder.length() - 1) {
+                    appendEOL = true;
+                }
+            } else if ("+".equals(metachar)) {
+                builder.replace(matcher.start(), matcher.end(), ".");
+                position = matcher.end();
+                if (matcher.end() == builder.length()) {
+                    appendEOL = true;
+                }
+            }
+        }
+        return appendEOL;
+    }
+
+    /**
+     * Takes a string that may possibly be very long and return a string that is at most maxLength. If the string is
+     * longer than maxLength, the last three characters will be the ellipses (...) to indicate that the string was
+     * shortened.
+     *
+     * @param possiblyLongString
+     * @param maxLength
+     *            must be at least 4 (one character plus ellipses)
+     * @return possibly shortened string
+     */
+    public static String getShortenedString(String possiblyLongString, int maxLength) {
+        if ((possiblyLongString != null) && (maxLength > ELLIPSES.length())
+            && (possiblyLongString.length() > maxLength)) {
+            return possiblyLongString.substring(0, maxLength - ELLIPSES.length()) + ELLIPSES;
+
+        }
+        return possiblyLongString;
+    }
+
+    /**
+     * Determines that a provided string is not null and not empty (length = 0 after trimming)
+     *
+     * @param theString
+     *            The string to be tested
+     * @return true if the string IS NOT null and is NOT empty
+     */
+    public static boolean isNotNullNotEmpty(String theString) {
+        return theString != null && !theString.trim().isEmpty();
+    }
+
+    /**
+     * Determines that a provided string IS null or an empty string (length = 0 after trimming)
+     *
+     * @param theString
+     *            The string to be tested
+     * @return true if the string IS null OR is empty
+     */
+    public static boolean isNullOrEmpty(String theString) {
+        return theString == null || theString.trim().isEmpty();
+    }
+
+    /**
+     * Returns an indication if the first string is equal to the second string, allowing for either or both strings to
+     * be null.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @return True if both strings are null, or both strings are non-null AND they are equal. False otherwise.
+     */
+    public static boolean areEqual(String a, String b) {
+        return areEqual(a, b, false);
+    }
+
+    /**
+     * Returns an indication if the first string is equal to the second string, allowing for either or both strings to
+     * be null, and ignoring case.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @return True if both strings are null, or both strings are non-null AND they are equal (without regard to case).
+     *         False otherwise.
+     */
+    public static boolean equalsIgnoreCase(String a, String b) {
+        return areEqual(a, b, true);
+    }
+
+    /**
+     * Compares two strings (allowing either or both to be null), and allowing for optional case sensitive or
+     * insensitive comparison.
+     *
+     * @param a
+     *            The first string to be compared
+     * @param b
+     *            The second string to be compared
+     * @param caseInsensitive
+     *            True if the comparison is to be case in-sensitive.
+     * @return True if both strings are null, or both strings are non-null and they are equal
+     */
+    private static boolean areEqual(String a, String b, boolean caseInsensitive) {
+        if (a == null && b == null) {
+            return true;
+        }
+        if (a != null && b != null) {
+            if (caseInsensitive) {
+                return a.equalsIgnoreCase(b);
+            } else {
+                return a.equals(b);
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * This method is used to mangle a name.
+     * <p>
+     * This method will first remove all unacceptable characters from the name and translate all characters to lower
+     * case. This is done to eliminate any potentially troublesome characters. If the resulting string is empty, then a
+     * random string of characters for the minimum desired length is returned. If the string is too short to meet the
+     * minimum length requirement, it is padded with random characters.
+     * </p>
+     * <p>
+     * Once the string has been scrubbed and possibly padded, it may be truncated (if longer than the maximum value) and
+     * the result is returned. To make the string as unique as possible, the algorithm removes excess letters from the
+     * center of the string, concatenating the first nad last parts of the name together. The assumption is that users
+     * tend to start the names of multiple things in similar ways, and get more descriptive as the name progresses. If
+     * for example, several objects were named "A test Object", "A test Object1", and "A test Object2", shortening the
+     * name only from the left does not generate a unique name.
+     * </p>
+     *
+     * @param name
+     *            The name to be mangled
+     * @param minLen
+     *            minimum number of characters for the name
+     * @param maxLen
+     *            maximum number of characters for the name
+     * @return The mangled name, or an empty string if the value is null or an empty string.
+     */
+    public static String mangleName(String name, int minLen, int maxLen) {
+        StringBuilder builder = new StringBuilder(name == null ? "" : name);
+        Pattern pattern = Pattern.compile("[^a-z0-9]+", Pattern.CASE_INSENSITIVE);
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.delete(matcher.start(), matcher.end());
+            position = matcher.start();
+        }
+
+        if (builder.length() < minLen) {
+            for (int i = builder.length(); i <= minLen; i++) {
+                builder.append("A");
+            }
+        }
+
+        /*
+         * Remove out of the center of the name to preserve start and end and result in a string of max len
+         */
+        if (builder.length() > maxLen) {
+            int excess = builder.length() - maxLen;
+            int left = maxLen / 2;
+
+            builder.delete(left, excess + left);
+        }
+
+        return builder.toString().toLowerCase();
+    }
+
+    /**
+     * This method is used to normalize a string value.
+     * <p>
+     * This method will ensure that the string value is trimmed of all leading and trailing whitespace if not null. If
+     * it is null or an empty string, then it will return null.
+     * </p>
+     *
+     * @param value
+     *            The value to be normalized
+     * @return The normalized (no leading or trailing whitespace) value, or null if the string was null or an empty
+     *         string (or all whitespace). This method will never return an empty string.
+     */
+    public static String normalizeString(String value) {
+        if (value != null) {
+            String temp = value.trim();
+            if (temp.length() > 0) {
+                return temp;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method is used to strip all carriage returns and line feed characters from a string
+     *
+     * @param value
+     * @return The original value less all carriage returns and line feeds
+     */
+    public static String stripCRLF(String value) {
+
+        if (value == null) {
+            return null;
+        }
+        String[] tokens = value.split("\r\n|\n\r|\r|\n");
+        StringBuilder builder = new StringBuilder();
+        for (String token : tokens) {
+            builder.append(token.trim());
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Converts UNIX-style line endings to DOS-style. Replaces LF with CR+LF as long as the LF does not already exist
+     * paired with a CR.
+     *
+     * @param content
+     *            The content to be converted
+     * @return The converted content.
+     */
+    public static String toDOSLines(String content) {
+        if (content == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(content);
+        Pattern pattern = Pattern.compile("^(\n)[^\r]|[^\r](\n)[^\r]|[^\r](\n)$");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            int index = matcher.start(1);
+            if (index == -1) {
+                index = matcher.start(2);
+            }
+            if (index == -1) {
+                index = matcher.start(3);
+            }
+
+            builder.replace(index, index + 1, "\r\n");
+            position = index + 1;
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * This method will convert a string contents to use the UNIX-style line endings. That is, all occurrences of CR
+     * (Carriage Return) and LF (Line Feed) are reduced to just use LF.
+     *
+     * @param content
+     *            The buffer to be processed
+     * @return The converted contents
+     */
+    public static String toUnixLines(String content) {
+        if (content == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(content);
+        Pattern pattern = Pattern.compile("\r\n|\n\r");
+        Matcher matcher = pattern.matcher(builder);
+        int position = 0;
+        while (matcher.find(position)) {
+            builder.replace(matcher.start(), matcher.end(), "\n");
+            position = matcher.start();
+        }
+
+        return builder.toString();
+    }
+
+     /**
+     * This method is used to translate characters in the input sequence that match the characters in the match list to
+     * the corresponding character in the replacement list. If the replacement list is shorter than the match list, then
+     * the character from the replacement list is taken as the modulo of the match character position and the length of
+     * the replacement list.
+     *
+     * @param sequence
+     *            The input sequence to be processed
+     * @param match
+     *            The list of matching characters to be searched
+     * @param replacement
+     *            The list of replacement characters, positional coincident with the match list. If shorter than the
+     *            match list, then the position "wraps" around on the replacement list.
+     * @return The translated string contents.
+     */
+    public static Object translate(String sequence, String match, String replacement) {
+
+        if (sequence == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(sequence);
+
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+
+            int position = match.indexOf(ch);
+            if (position == -1) {
+                continue;
+            }
+
+            if (position >= replacement.length()) {
+                position %= replacement.length();
+            }
+            builder.setCharAt(index, replacement.charAt(position));
+        }
+
+        return builder.toString();
+    }
+
+    /**
+     * Ensures that the name provided is a valid identifier. This means that no spaces are allowed as well as special
+     * characters. This method translates all spaces and illegal characters to underscores (_).
+     *
+     * @param name
+     *            The name to be checked and converted to an identifier if needed
+     * @return The valid identifier from the name
+     */
+    public static String validIdentifier(String name) {
+        if (name == null || name.length() == 0) {
+            return name;
+        }
+        StringBuilder builder = new StringBuilder(name);
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+
+            if ((index == 0 && !Character.isJavaIdentifierStart(ch)) || (!Character.isJavaIdentifierPart(ch))) {
+                builder.setCharAt(index, '_');
+            }
+        }
+        return builder.toString();
+    }
+
+
+    /**
+     * Private constructor to prevent instantiation of this class - All methods are static!
+     */
+    private StringHelper() {
+
+    }
+
+    /**
+     * This method verifies that the provided string only contains characters from the legal set, and replaces any
+     * character not in the legal set with the specified replacement character.
+     *
+     * @param sequence
+     *            The sequence to be verified
+     * @param legal
+     *            The set of all legal characters
+     * @param replacement
+     *            The replacement character if a character is not in the legal set
+     * @return The verified *and possibly updated) string
+     */
+    public static String verify(String sequence, String legal, char replacement) {
+        if (sequence == null) {
+            return null;
+        }
+
+        StringBuilder builder = new StringBuilder(sequence);
+        for (int index = 0; index < builder.length(); index++) {
+            char ch = builder.charAt(index);
+            if (legal.indexOf(ch) == -1) {
+                builder.setCharAt(index, replacement);
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param list
+     *            The list of elements
+     * @return The list of elements formatted as a comma-delimited list
+     */
+    public static String asList(List<String> list) {
+        StringBuilder builder = new StringBuilder();
+
+        if (list != null) {
+            if (list.size() == 1) {
+                builder.append(list.get(0));
+            } else {
+                for (String element : list) {
+                    builder.append(element);
+                    builder.append(", ");
+                }
+
+                if (builder.length() > 2) {
+                    builder.delete(builder.length() - 2, builder.length());
+                }
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param map
+     *            A map of strings
+     * @return A map expressed as a comma-delimited list of name=value tuples
+     */
+    public static String asList(Map<String, String> map) {
+        StringBuilder builder = new StringBuilder();
+        if (map != null) {
+            Set<String> keys = map.keySet();
+            for (String key : keys) {
+                builder.append(String.format("%s=%s, ", key, map.get(key)));
+            }
+
+            if (builder.length() > 2) {
+                builder.delete(builder.length() - 2, builder.length());
+            }
+        }
+        return builder.toString();
+    }
+
+    /**
+     * @param values
+     *            An array or varargs of Strings to be concatenated into a comma-separated list
+     * @return The comma-seprated list of values
+     */
+    public static String asList(String... values) {
+        StringBuilder builder = new StringBuilder();
+        builder.append('[');
+        if (values != null && values.length > 0) {
+            int count = values.length;
+            for (int index = 0; index < count - 1; index++) {
+                builder.append(values[index]);
+                builder.append(',');
+            }
+            builder.append(values[count - 1]);
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
+    public static Object resolveToType(String input) {
+        String intRegex = "^(\\-)?[0-9]+$";
+        String doubleRegex = "^(\\-)?[0-9\\.]+$";
+        String boolRegex = "(^(?i)((true)|(false))$)";
+
+        // Check for null
+        if (input == null) {
+            return null;
+        }
+
+        // Check int first
+        if (input.matches(intRegex)) {
+            try {
+                return Integer.parseInt(input);
+            } catch (NumberFormatException nfe) {
+                // Should not happen
+                logger.error(nfe.getMessage());
+            }
+        }
+
+        // Check double (int + decimal point)
+        if (input.matches(doubleRegex)) {
+            try {
+                return Double.parseDouble(input);
+            } catch (NumberFormatException | NullPointerException e) {
+                // NPE won't happen bc of regex check
+                logger.error("Parsing input failed", e);
+            }
+        }
+
+        // Check boolean
+        if (input.matches(boolRegex)) {
+            return Boolean.parseBoolean(input);
+        }
+
+        // Try to parse a date
+        Date date = Time.utcParse(input);
+        if (date != null) {
+            return date;
+        }
+
+        // No special type, return string
+        return input;
+    }
+
+    /**
+     * Converts a properties object to a string in the format of <pre>[ key=value, key=value, ... ]</pre>
+     *
+     * @param props
+     *            The properties object to format
+     * @return A string in the format <pre>[ key=value, ... ]</pre> or null if the input was null
+     */
+    public static String propertiesToString(Properties props) {
+        if (props == null) {
+            return null;
+        }
+        StringBuilder out = new StringBuilder();
+        out.append("[");
+        for (Object key : props.keySet()) {
+            out.append(String.format(" %s = %s,", key.toString(), props.getProperty(key.toString())));
+        }
+        if (props.size() > 0) {
+            out.deleteCharAt(out.lastIndexOf(","));
+        }
+        out.append(" ]");
+        return out.toString();
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StructuredPropertyHelper.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/StructuredPropertyHelper.java
new file mode 100644 (file)
index 0000000..5c18f3a
--- /dev/null
@@ -0,0 +1,259 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class is used to assemble properties that are defined using a structured name into groups, and allow them to be
+ * processed as sets of definitions.
+ * <p>
+ * For example, a structured name uses a dotted-notation, like "provider.name". Further, the nodes of the structured
+ * name may be serialized using a suffix ordinal number (e.g., "provider1.name"). These structured properties form a
+ * hierarchical name space where the names are grouped together and can be retrieved as a set.
+ * </p>
+ * 
+ */
+
+public class StructuredPropertyHelper {
+
+    /**
+     * This method scans the properties object for all properties that match the root name and constructs a list of
+     * structured property node graphs that represents the namespaces of the properties.
+     * <p>
+     * For example, assume that there are structured properties of the form "provider1.name", "provider2.name",
+     * "provider3.name", and so forth. There may also be other subordinate properties as well (e.g., "provider1.type").
+     * This method would construct a list of graphs of nodes, where each node represents one value of the structured
+     * name. The roots would be the values "provider1", "provider2", "provider3", and so forth. The values of the
+     * subordinate nodes would be the second, third, and so forth name nodes of the compound name. The value of the
+     * property is associated with nodes that are representative of the leaf of the name space.
+     * </p>
+     * 
+     * @param properties
+     *            The properties to be processed
+     * @param prefix
+     *            The prefix of the root structured property name
+     * @return The node graph of the properties
+     */
+    public static List<Node> getStructuredProperties(Properties properties, String prefix) {
+        List<Node> roots = new ArrayList<>();
+
+        for (String name : properties.stringPropertyNames()) {
+            if (name.startsWith(prefix)) {
+                String value = properties.getProperty(name);
+                processNamespace(roots, name, value);
+            }
+        }
+
+        return roots;
+    }
+
+    /**
+     * This method recursively walks the name space of the structured property and constructs the node graph to
+     * represent the property
+     * 
+     * @param nodes
+     *            The collection of nodes for the current level of the name space
+     * @param propertyName
+     *            The name of the node
+     * @param value
+     *            The value, if any
+     * @return The node for this level in the namespace
+     */
+    @SuppressWarnings("nls")
+    private static Node processNamespace(List<Node> nodes, String propertyName, String value) {
+        String[] tokens = propertyName.split("\\.", 2);
+        String nodeName = normalizeNodeName(tokens[0]);
+
+        Node namespaceNode = null;
+        for (Node node : nodes) {
+            if (node.getName().equals(nodeName)) {
+                namespaceNode = node;
+                break;
+            }
+        }
+        if (namespaceNode == null) {
+            namespaceNode = new Node();
+            namespaceNode.setName(nodeName);
+            nodes.add(namespaceNode);
+        }
+
+        if (tokens.length == 1 || tokens[1] == null || tokens[1].length() == 0) {
+            namespaceNode.setValue(value);
+        } else {
+            processNamespace(namespaceNode.getChildren(), tokens[1], value);
+        }
+
+        return namespaceNode;
+    }
+
+    /**
+     * This method normalizes a node name of the structured property name by removing leading and trailing whitespace,
+     * and by converting any ordinal position to a simple expression without leading zeroes.
+     * 
+     * @param token
+     *            The token to be normalized
+     * @return The normalized name, or null if the token was null;
+     */
+    @SuppressWarnings("nls")
+    private static String normalizeNodeName(String token) {
+        if (token == null) {
+            return null;
+        }
+
+        StringBuffer buffer = new StringBuffer(token.trim());
+        Pattern pattern = Pattern.compile("([^0-9]+)([0-9]*)");
+        Matcher matcher = pattern.matcher(buffer);
+        if (matcher.matches()) {
+            String nameRoot = matcher.group(1);
+            String ordinal = matcher.group(2);
+            if (ordinal != null && ordinal.length() > 0) {
+                int i = Integer.parseInt(ordinal);
+                buffer.setLength(0);
+                buffer.append(nameRoot);
+                buffer.append(Integer.toString(i));
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * This class represents a node in the structured property name space
+     *
+     */
+    public static class Node implements Comparable<Node> {
+
+        /**
+         * The name of the structured property node
+         */
+        private String name;
+
+        /**
+         * If the node is a leaf, then the value of the property
+         */
+        private String value;
+
+        /**
+         * If the node is not a leaf, then the sub-nodes of the property
+         */
+        private List<Node> children;
+
+        /**
+         * @return the value of name
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * @param name
+         *            the value for name
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * @return the value of value
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * @param value
+         *            the value for value
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * @return the value of children
+         */
+        public List<Node> getChildren() {
+            if (children == null) {
+                children = new ArrayList<>();
+            }
+            return children;
+        }
+
+        /**
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return name.hashCode() + (value != null ? value.hashCode() : children.hashCode());
+        }
+
+        /**
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null)
+                return false;
+            if (this.getClass() != obj.getClass())
+                return false;
+
+            Node other = (Node) obj;
+            boolean result = name.equals(other.name);
+
+            if (value == null) {
+                result &= other.value == null;
+            } else {
+                result &= value.equals(other.value);
+            }
+            if (children == null) {
+                result &= other.children == null;
+            } else {
+                result &= children.equals(other.children);
+            }
+            return result;
+        }
+
+        /**
+         * @see java.lang.Object#toString()
+         */
+        @SuppressWarnings("nls")
+        @Override
+        public String toString() {
+            if (value != null) {
+                return String.format("%s = %s", name, value);
+            }
+            return String.format("%s.%s", name, children.toString());
+        }
+
+        @Override
+        public int compareTo(StructuredPropertyHelper.Node o) {
+            return name.compareTo(o.name);
+        }
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/Time.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/Time.java
new file mode 100644 (file)
index 0000000..5e39770
--- /dev/null
@@ -0,0 +1,599 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is a general purpose helper class to augment standard Java time support.
+ *
+ */
+
+public final class Time {
+
+    /**
+     * Logger to log operations
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(Time.class);
+
+    /**
+     * A formatter to be used to format values
+     */
+    private static SimpleDateFormat dateformatter = null;
+
+    /**
+     * The UTC timezone (for UTC or GMT time)
+     */
+    @SuppressWarnings("nls")
+    private static final TimeZone utcTZ = TimeZone.getTimeZone("UTC");
+
+    /**
+     * The cached reference to the datatype factory
+     */
+    private static DatatypeFactory xmlDatatypeFactory = null;
+
+    /**
+     * Private default constructor prevents instantiation
+     */
+    private Time() {
+        //
+    }
+
+    /**
+     * Increments a date by the indicated months, days, hours, minutes, and seconds, and returns the
+     * updated date.
+     *
+     * @param date The date to be manipulated
+     * @param months The number of months to be added to the date
+     * @param days The number of days to be added to the date
+     * @param hours The number of hours to be added to the date
+     * @param minutes The number of minutes to be added to the date
+     * @param seconds The number of seconds to be added to the date
+     * @return The updated date.
+     */
+    public static Date addTime(final Date date, final int months, final int days, final int hours,
+            final int minutes, final int seconds) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.add(Calendar.MONTH, months);
+        cal.add(Calendar.DATE, days);
+        cal.add(Calendar.HOUR_OF_DAY, hours);
+        cal.add(Calendar.MINUTE, minutes);
+        cal.add(Calendar.SECOND, seconds);
+        return cal.getTime();
+    }
+
+    /**
+     * Clears the time components of a calendar to zero, leaving the date components unchanged.
+     *
+     * @param cal the calendar to be updated
+     * @return The updated calendar object
+     */
+    public static Calendar dateOnly(final Calendar cal) {
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal;
+    }
+
+    /**
+     * This method returns the local time that corresponds to the end of the current day
+     *
+     * @return The time that corresponds to the end of the current day, expressed as local time
+     */
+    public static Date endOfDayLocal() {
+        return endOfDayLocal(new Date());
+    }
+
+    /**
+     * This method returns the last moment of the day for the supplied local time. This is defined
+     * as the millisecond before midnight of the current date represented by the local time.
+     *
+     * @param localTime The local time for which the last moment of the day is desired.
+     * @return The millisecond prior to midnight, local time.
+     */
+    public static Date endOfDayLocal(final Date localTime) {
+        // @sonar:off
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTime(localTime);
+        calendar.set(Calendar.HOUR, 11);
+        calendar.set(Calendar.AM_PM, Calendar.PM);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        // @sonar:on
+
+        return calendar.getTime();
+    }
+
+    /**
+     * The end of the current day and in the current time zone expressed as a UTC time.
+     *
+     * @return The UTC time that corresponds to the end of the current day
+     */
+    public static Date endOfDayUTC() {
+        return endOfDayUTC(new Date());
+    }
+
+    /**
+     * Returns the UTC time that corresponds to the end of the day for the local time specified,
+     * using the current (default) time zone.
+     *
+     * @param localTime The local time for which we are requesting the UTC time that corresponds to
+     *        the end of the day
+     * @return The UTC time that corresponds to the end of the local day specified by the local
+     *         time.
+     */
+    public static Date endOfDayUTC(final Date localTime) {
+        return endOfDayUTC(localTime, TimeZone.getDefault());
+    }
+
+    /**
+     * Returns the time expressed in UTC time of the end of the day specified in local time and
+     * within the local time zone.
+     *
+     * @param localTime The local time for which we will compute the end of the local day, and then
+     *        convert to UTC time.
+     * @param localTimeZone The time zone that the local time is within.
+     * @return The UTC date that corresponds to the end of the day local time and in the local time
+     *         zone.
+     */
+    public static Date endOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
+        Date endOfDay = endOfDayLocal(localTime);
+        return utcDate(endOfDay, localTimeZone);
+    }
+
+    /**
+     * returns current Date in 'UTC' Timezone
+     *
+     * @return The current date, expressed in the UTC timezone.
+     */
+    @SuppressWarnings("nls")
+    public static Date getCurrentUTCDate() {
+
+        // This code incorrectly changes the default timezone for the entire JVM in order to compute
+        // the UTC
+        // date for the current time.
+
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+        calendar.setTimeInMillis(utcTime());
+        return calendar.getTime();
+    }
+
+    /**
+     * This method loads and caches the reference to the XML data type factory object.
+     *
+     * @return The XML Data Type Factory object
+     */
+    public static DatatypeFactory getDatatypeFactory() {
+        if (xmlDatatypeFactory == null) {
+            try {
+                xmlDatatypeFactory = DatatypeFactory.newInstance();
+            } catch (DatatypeConfigurationException e) {
+                e.printStackTrace(System.err);
+            }
+        }
+        return xmlDatatypeFactory;
+    }
+
+    /**
+     * Gives the date-time String based on given Locale and Timezone
+     *
+     * @param date The date to be formatted
+     * @param locale The locale that we want to format the value for
+     * @param timezone The time zone that the date is within
+     * @return The formatted value
+     */
+    public static String getDateByLocaleAndTimeZone(final Date date, final Locale locale,
+            final TimeZone timezone) {
+        String strDate = null;
+        DateFormat df =
+                DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
+        df.setTimeZone(timezone);
+        synchronized (df) {
+            strDate = df.format(date);
+        }
+        return strDate;
+    }
+
+    /**
+     * Returns singleton UTC date formatter.
+     *
+     * @return
+     */
+    @SuppressWarnings("nls")
+    private static SimpleDateFormat getDateFormatter() {
+        if (dateformatter == null) {
+            dateformatter = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
+            dateformatter.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
+        }
+        return dateformatter;
+    }
+
+    /**
+     * This method returns the local time that corresponds to a given UTC time in the current time
+     * zone.
+     *
+     * @param utcTime The UTC time for which we desire the equivalent local time in the current time
+     *        zone.
+     * @return The local time that is equivalent to the given UTC time for the current time zone
+     */
+    public static long localTime(final long utcTime) {
+        return localTime(utcTime, TimeZone.getDefault());
+    }
+
+    /**
+     * This method can be used to get the local time that corresponds to a specific UTC time.
+     * <p>
+     * This method has a problem since the offset can only be determined by having a local time. So,
+     * we take the UTC time and add the raw offset to it to come up with an approximation of the
+     * local time. This gives us a local time that we can use to determine what the offset should
+     * be, which is what we actually add to the UTC time to get the local time.
+     * </p>
+     *
+     * @param utcTime The UTC time for which we want to obtain the equivalent local time
+     * @param localTZ The time zone that we want the local time to be within
+     * @return The local time for the specified time zone and the given UTC time
+     */
+    public static long localTime(final long utcTime, final TimeZone localTZ) {
+        int offset = localTZ.getOffset(utcTime + localTZ.getRawOffset());
+        long result = utcTime + offset;
+
+        return result;
+    }
+
+    /**
+     * Sets the date components of a calendar to the specified values, leaving the time components
+     * unchanged.
+     *
+     * @param cal The calendar to be updated
+     * @param year The year to be set
+     * @param month The month to be set
+     * @param day The day to be set
+     * @return The updated calendar object
+     */
+    public static Calendar setDate(final Calendar cal, final int year, final int month,
+            final int day) {
+        cal.set(Calendar.YEAR, year);
+        cal.set(Calendar.MONTH, month);
+        cal.set(Calendar.DAY_OF_MONTH, day);
+        return cal;
+    }
+
+    /**
+     * Returns the start of the day expressed in local time for the current local time.
+     *
+     * @return The start of the day
+     */
+    public static Date startOfDayLocal() {
+        return startOfDayLocal(new Date());
+    }
+
+    /**
+     * This method returns the date that corresponds to the start of the day local time. The date
+     * returned represents midnight of the previous day represented in local time. If the UTC time
+     * is desired, use the methods {@link #startOfDayUTC(Date, TimeZone)},
+     * {@link #startOfDayUTC(Date)}, or {@link #startOfDayUTC()}
+     *
+     * @param localTime The local date that we wish to compute the start of day for.
+     * @return The date that corresponds to the start of the local day
+     */
+    public static Date startOfDayLocal(final Date localTime) {
+        GregorianCalendar calendar = new GregorianCalendar();
+        calendar.setTime(localTime);
+        calendar.set(Calendar.HOUR, 0);
+        calendar.set(Calendar.AM_PM, Calendar.AM);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+
+        return calendar.getTime();
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day based on the
+     * current time and the default time zone (the time zone we are running in).
+     *
+     * @return The start of the local day expressed as a UTC time.
+     */
+    public static Date startOfDayUTC() {
+        return startOfDayUTC(new Date());
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day specified in
+     * the current time zone.
+     *
+     * @param localTime The local time to be used to compute the start of the day
+     * @return The start of the local day expressed as a UTC time.
+     */
+    public static Date startOfDayUTC(final Date localTime) {
+        return startOfDayUTC(localTime, TimeZone.getDefault());
+    }
+
+    /**
+     * This method returns the UTC date that corresponds to the start of the local day specified in
+     * the local timezone.
+     *
+     * @param localTime The local time to be used to compute start of day
+     * @param localTimeZone The time zone that the local time was recorded within
+     * @return The corresponding UTC date
+     */
+    public static Date startOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
+        Date startOfDay = startOfDayLocal(localTime);
+        return utcDate(startOfDay, localTimeZone);
+    }
+
+    /**
+     * This method creates and returns an XML timestamp expressed as the current UTC value for the
+     * system. The caller does not specify the time value or time zone using this method. This
+     * ensures that the timestamp value is always expressed as UTC time.
+     *
+     * @return The XMLGregorianCalendar that can be used to record the timestamp
+     */
+
+    public static XMLGregorianCalendar timestamp() {
+        getDatatypeFactory();
+        XMLGregorianCalendar ts = xmlDatatypeFactory.newXMLGregorianCalendar();
+        GregorianCalendar utc = new GregorianCalendar();
+        utc.setTime(utcDate());
+        ts.setTimezone(0);
+        ts.setYear(utc.get(Calendar.YEAR));
+        // Calendar Months are from 0-11 need to +1
+        ts.setMonth(utc.get(Calendar.MONTH) + 1);
+        ts.setDay(utc.get(Calendar.DAY_OF_MONTH));
+        ts.setHour(utc.get(Calendar.HOUR_OF_DAY));
+        ts.setMinute(utc.get(Calendar.MINUTE));
+        ts.setSecond(utc.get(Calendar.SECOND));
+        ts.setMillisecond(utc.get(Calendar.MILLISECOND));
+        return ts;
+    }
+
+    /**
+     * Converts XMLGregorianCalendar to java.util.Date in Java
+     *
+     * @param calendar the calendar object to be converted
+     * @return The equivalent Date object
+     */
+    public static Date toDate(final XMLGregorianCalendar calendar) {
+        if (calendar == null) {
+            return null;
+        }
+        return calendar.toGregorianCalendar().getTime();
+    }
+
+    /**
+     * Converts java Date to XMLGregorianCalendar.
+     *
+     * @param date The date to convert
+     * @return The XMLGregorianCalendar for the specified date
+     */
+    @SuppressWarnings("nls")
+    public static XMLGregorianCalendar toXMLCalendar(final Date date) {
+        GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
+        cal.setTime(date);
+
+        XMLGregorianCalendar xmlCal = null;
+        try {
+            xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
+        } catch (DatatypeConfigurationException e) {
+            LOG.error("toXMLCalendar", e);
+        }
+        return xmlCal;
+    }
+
+    /**
+     * Truncates the provided date so that only the date, hours, and minutes portions are
+     * significant. This method returns the date with the seconds and milliseconds forced to zero.
+     *
+     * @param date The date to truncate
+     * @return The date with only the year, month, day, hours, and minutes significant.
+     */
+    public static Date truncDate(final Date date) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal.getTime();
+    }
+
+    /**
+     * The UTC date that corresponds to the current date in the local time zone.
+     *
+     * @return The UTC date for now in the current time zone.
+     */
+    public static Date utcDate() {
+        return new Date();
+    }
+
+    /**
+     * The UTC date for the specified date in the current (default) time zone.
+     *
+     * @param date The local date for which the UTC date is desired.
+     * @return The UTC date that corresponds to the date in the current time zone.
+     */
+    public static Date utcDate(final Date date) {
+        TimeZone tz = TimeZone.getDefault();
+        return utcDate(date, tz);
+    }
+
+    /**
+     * Returns the UTC date for the specified date in the specified time zone.
+     *
+     * @param date The date for which the UTC date is desired in the specified zone
+     * @param tz The time zone that corresponds to the date to be converted to UTC
+     * @return The UTC date that corresponds to the local date in the local time zone.
+     */
+    public static Date utcDate(final Date date, final TimeZone tz) {
+        return new Date(utcTime(date.getTime(), tz));
+    }
+
+    /**
+     * Format incoming date as string in GMT or UTC.
+     *
+     * @param dt The date to be formatted
+     * @return The date formatted for UTC timezone
+     */
+    public static String utcFormat(final Date dt) {
+        String strDate = null;
+        DateFormat df = getDateFormatter();
+        synchronized (df) {
+            strDate = df.format(dt);
+        }
+        return strDate;
+    }
+
+    /**
+     * Parse previously formated Date object back to a Date object.
+     *
+     * @param dateStr The representation of a UTC date as a string
+     * @return The date object containing the parsed representation, or null if the representation
+     *         cannot be parsed
+     */
+    @SuppressWarnings("nls")
+    public static Date utcParse(final String dateStr) {
+        String[] adtl = {"yyyy-MM-dd"};
+        return utcParse(dateStr, adtl);
+    }
+
+    /**
+     * Parse previously formated Date object back to a Date object.
+     *
+     * @param dateStr The representation of a UTC date as a string
+     * @param adtlFormatStrings A list of strings that represent additional date format
+     *        representations to try and parse.
+     * @return The date object containing the parsed representation, or null if the representation
+     *         cannot be parsed
+     */
+    @SuppressWarnings("nls")
+    public static Date utcParse(final String dateStr, String... adtlFormatStrings) {
+        if (dateStr != null) {
+            // Build the list of formatters starting with the default defined in the class
+            List<DateFormat> formats = new ArrayList<>();
+            formats.add(getDateFormatter());
+
+            if (adtlFormatStrings != null) {
+                for (String s : adtlFormatStrings) {
+                    formats.add(new SimpleDateFormat(s));
+                }
+            }
+
+            // Return the first matching date formatter's result
+            for (DateFormat df : formats) {
+                df.setTimeZone(utcTZ);
+                try {
+                    return df.parse(dateStr);
+                } catch (ParseException e) {
+                    LOG.debug(String.format("IGNORE - Date string [%s] does not fit pattern [%s]",
+                            dateStr, df.toString()));
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This method returns the current time for the UTC timezone
+     *
+     * @return The time in the UTC time zone that corresponds to the current local time.
+     */
+    public static long utcTime() {
+        return new Date().getTime();
+    }
+
+    /**
+     * Get the UTC time that corresponds to the given time in the default time zone (current time
+     * zone for the system).
+     *
+     * @param localTime The time in the current time zone for which the UTC time is desired.
+     * @return The UTC time
+     */
+    public static long utcTime(final long localTime) {
+        TimeZone tz = TimeZone.getDefault();
+        return utcTime(localTime, tz);
+    }
+
+    /**
+     * Get the UTC time that corresponds to the given time in the specified timezone.
+     * <p>
+     * Note that the java <code>getOffset()</code> method works a little counter-intuitive. It
+     * returns the offset that would be added to the current UTC time to get the LOCAL time
+     * represented by the local time zone. That means to get the UTC time, we need to SUBTRACT this
+     * offset from the local time.
+     * </p>
+     *
+     * @param localTime The time in the specified time zone for which the UTC time is desired.
+     * @param localTZ The time zone which the local time is in.
+     * @return The UTC time for the specified local time in the specified local time zone.
+     */
+    public static long utcTime(final long localTime, final TimeZone localTZ) {
+        int offset = localTZ.getOffset(localTime);
+        return localTime - offset;
+
+    }
+
+    /**
+     * Creates a timestamp value from a time
+     *
+     * @param utcTime The UTC time to convert to a timestamp
+     * @return The timestamp
+     */
+    public static Timestamp utcTimestamp(final long utcTime) {
+        TimeZone tz = TimeZone.getDefault();
+        return new Timestamp(utcTime(utcTime, tz));
+    }
+
+    public static String dateToStringConverterMillis(Date date) {
+        SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
+        if (date != null) {
+            return customDate.format(date);
+        }
+        return null;
+    }
+
+    public static Date stringToDateConverterMillis(String dateString) throws ParseException {
+        SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
+        return customDate.parse(dateString);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/UnmodifiableProperties.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/UnmodifiableProperties.java
new file mode 100644 (file)
index 0000000..6d20b64
--- /dev/null
@@ -0,0 +1,355 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * This utility class is used to wrap a properties object and to delegate all read operations to the property object,
+ * while disallowing any write or modification to the property object.
+ * 
+ */
+public class UnmodifiableProperties extends Properties implements Cloneable {
+
+    /**
+     * Serial number
+     */
+    private static final long serialVersionUID = 1L;
+
+    private static final String PROPERTY_CANNOT_BE_MODIFIED_MSG = "Property cannot be modified!";
+
+    /**
+     * The properties object which we are wrapping
+     */
+    private Properties properties;
+
+    /**
+     * Create the unmodifiable wrapper around the provided properties object
+     * 
+     * @param properties
+     *            The properties to be wrapped and protected from modification
+     */
+    public UnmodifiableProperties(Properties properties) {
+        this.properties = properties;
+    }
+
+    /**
+     * @see java.util.Hashtable#clear()
+     */
+    @Override
+    public synchronized void clear() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#clone()
+     */
+    // @sonar:off
+    @Override
+    public synchronized Object clone() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    // @sonar:on
+
+    /**
+     * @see java.util.Hashtable#contains(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean contains(Object value) {
+        return properties.contains(value);
+    }
+
+    /**
+     * @see java.util.Hashtable#containsKey(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean containsKey(Object key) {
+        return properties.containsKey(key);
+    }
+
+    /**
+     * @see java.util.Hashtable#containsValue(java.lang.Object)
+     */
+    @Override
+    public boolean containsValue(Object value) {
+        return properties.containsValue(value);
+    }
+
+    /**
+     * @see java.util.Hashtable#elements()
+     */
+    @Override
+    public synchronized Enumeration<Object> elements() {
+        return properties.elements();
+    }
+
+    /**
+     * @see java.util.Hashtable#entrySet()
+     */
+    @Override
+    public Set<java.util.Map.Entry<Object, Object>> entrySet() {
+        return Collections.unmodifiableSet(properties.entrySet());
+    }
+
+    /**
+     * @see java.util.Hashtable#equals(java.lang.Object)
+     */
+    @Override
+    public synchronized boolean equals(Object o) {
+        return properties.equals(o);
+    }
+
+    /**
+     * @see java.util.Hashtable#get(java.lang.Object)
+     */
+    @Override
+    public synchronized Object get(Object key) {
+        return properties.get(key);
+    }
+
+    /**
+     * @see java.util.Properties#getProperty(java.lang.String)
+     */
+    @Override
+    public String getProperty(String key) {
+        return properties.getProperty(key);
+    }
+
+    /**
+     * @see java.util.Properties#getProperty(java.lang.String, java.lang.String)
+     */
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        return properties.getProperty(key, defaultValue);
+    }
+
+    /**
+     * @see java.util.Hashtable#hashCode()
+     */
+    @Override
+    public synchronized int hashCode() {
+        return properties.hashCode();
+    }
+
+    /**
+     * @see java.util.Hashtable#isEmpty()
+     */
+    @Override
+    public synchronized boolean isEmpty() {
+        return properties.isEmpty();
+    }
+
+    /**
+     * @see java.util.Hashtable#keys()
+     */
+    @Override
+    public synchronized Enumeration<Object> keys() {
+        return properties.keys();
+    }
+
+    /**
+     * @see java.util.Hashtable#keySet()
+     */
+    @Override
+    public Set<Object> keySet() {
+        return Collections.unmodifiableSet(properties.keySet());
+    }
+
+    /**
+     * @see java.util.Properties#list(java.io.PrintStream)
+     */
+    @Override
+    public void list(PrintStream out) {
+        properties.list(out);
+    }
+
+    /**
+     * @see java.util.Properties#list(java.io.PrintWriter)
+     */
+    @Override
+    public void list(PrintWriter out) {
+        properties.list(out);
+    }
+
+    /**
+     * @see java.util.Properties#load(java.io.InputStream)
+     */
+    @Override
+    public synchronized void load(InputStream inStream) throws IOException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#load(java.io.Reader)
+     */
+    @Override
+    public synchronized void load(Reader reader) throws IOException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#loadFromXML(java.io.InputStream)
+     */
+    @Override
+    public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#propertyNames()
+     */
+    @Override
+    public Enumeration<?> propertyNames() {
+        return properties.propertyNames();
+    }
+
+    /**
+     * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#putAll(java.util.Map)
+     */
+    @Override
+    public synchronized void putAll(Map<? extends Object, ? extends Object> t) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#rehash()
+     */
+    @Override
+    protected void rehash() {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#remove(java.lang.Object)
+     */
+    @Override
+    public synchronized Object remove(Object key) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Properties#save(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    @Deprecated
+    public synchronized void save(OutputStream out, String comments) {
+        properties.save(out, comments);
+    }
+
+    /**
+     * @see java.util.Properties#setProperty(java.lang.String, java.lang.String)
+     */
+    @Override
+    public synchronized Object setProperty(String key, String value) {
+        throw new UnsupportedOperationException(PROPERTY_CANNOT_BE_MODIFIED_MSG);
+    }
+
+    /**
+     * @see java.util.Hashtable#size()
+     */
+    @Override
+    public synchronized int size() {
+        return properties.size();
+    }
+
+    /**
+     * @see java.util.Properties#store(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    public void store(OutputStream out, String comments) throws IOException {
+        properties.store(out, comments);
+    }
+
+    /**
+     * @see java.util.Properties#store(java.io.Writer, java.lang.String)
+     */
+    @Override
+    public void store(Writer writer, String comments) throws IOException {
+        properties.store(writer, comments);
+    }
+
+    /**
+     * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String)
+     */
+    @Override
+    public synchronized void storeToXML(OutputStream os, String comment) throws IOException {
+        properties.storeToXML(os, comment);
+    }
+
+    /**
+     * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String, java.lang.String)
+     */
+    @Override
+    public synchronized void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
+        properties.storeToXML(os, comment, encoding);
+    }
+
+    /**
+     * @see java.util.Properties#stringPropertyNames()
+     */
+    @Override
+    public Set<String> stringPropertyNames() {
+        return properties.stringPropertyNames();
+    }
+
+    /**
+     * @see java.util.Hashtable#toString()
+     */
+    @Override
+    public synchronized String toString() {
+        return properties.toString();
+    }
+
+    /**
+     * @see java.util.Hashtable#values()
+     */
+    @Override
+    public Collection<Object> values() {
+        return Collections.unmodifiableCollection(properties.values());
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/httpClient.java b/appc-core/appc-common-bundle/src/main/java/org/onap/appc/util/httpClient.java
new file mode 100644 (file)
index 0000000..a2ce8af
--- /dev/null
@@ -0,0 +1,205 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.onap.appc.configuration.Configuration;
+import org.onap.appc.configuration.ConfigurationFactory;
+import org.onap.appc.exceptions.APPCException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+
+public class httpClient {
+
+    private static final EELFLogger logger = EELFManager.getInstance().getLogger(httpClient.class);
+
+    private static Configuration configuration = ConfigurationFactory.getConfiguration();
+
+    @SuppressWarnings("deprecation")
+    public static int postMethod(String protocol, String ip, int port, String path, String payload,
+            String contentType) throws APPCException {
+
+        logger.info("Sending POST request to " + path);
+
+        HttpPost post;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            post = new HttpPost(serviceUrl.toExternalForm());
+            post.setHeader("Content-Type", contentType);
+
+            StringEntity entity = new StringEntity(payload);
+            entity.setContentType(contentType);
+            post.setEntity(new StringEntity(payload));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + post);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        try {
+            HttpResponse response = client.execute(post);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+        return httpCode;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int putMethod(String protocol, String ip, int port, String path, String payload,
+            String contentType) throws APPCException {
+
+        logger.info("Sending PUT request to " + path);
+
+        HttpPut put;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            put = new HttpPut(serviceUrl.toExternalForm());
+            put.setHeader("Content-Type", contentType);
+
+            StringEntity entity = new StringEntity(payload);
+            entity.setContentType(contentType);
+            put.setEntity(new StringEntity(payload));
+        } catch (UnsupportedEncodingException | MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + put);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        try {
+            HttpResponse response = client.execute(put);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+        return httpCode;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static String getMethod(String protocol, String ip, int port, String path,
+            String contentType) throws APPCException {
+
+        logger.info("Sending GET request to " + path);
+
+        HttpGet get;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            get = new HttpGet(serviceUrl.toExternalForm());
+            get.setHeader("Content-Type", contentType);
+        } catch (MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + get);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+        String result;
+
+        try {
+            HttpResponse response = client.execute(get);
+            httpCode = response.getStatusLine().getStatusCode();
+            result = (httpCode == HttpStatus.SC_OK) ? response.getEntity().toString() : null;
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+
+        return result;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int deleteMethod(String protocol, String ip, int port, String path,
+            String contentType) throws APPCException {
+
+        logger.info("Sending DELETE request to " + path);
+
+        HttpDelete delete;
+        try {
+
+            URL serviceUrl = new URL(protocol, ip, port, path);
+            delete = new HttpDelete(serviceUrl.toExternalForm());
+            delete.setHeader("Content-Type", contentType);
+        } catch (MalformedURLException e) {
+            throw new APPCException(e);
+        }
+
+        logger.debug("Sending request " + delete);
+
+        CredentialsProvider credsProvider = new BasicCredentialsProvider();
+        credsProvider.setCredentials(new AuthScope(ip, port), new UsernamePasswordCredentials(
+                configuration.getProperty("username"), configuration.getProperty("password")));
+        CloseableHttpClient client =
+                HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
+
+        int httpCode;
+
+        try {
+            HttpResponse response = client.execute(delete);
+            httpCode = response.getStatusLine().getStatusCode();
+        } catch (IOException e) {
+            throw new APPCException(e);
+        }
+
+        return httpCode;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/MessageResources.properties b/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/MessageResources.properties
new file mode 100644 (file)
index 0000000..323476e
--- /dev/null
@@ -0,0 +1,1060 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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 property file contains all message definitions used by APPC
+#
+# Message resources are identified by a key, which is defined in the Msg enumeration.  This key is
+# assigned a value which consists of 4 parts separated by a pipe (|) symbol.  These parts are:
+#
+# 1. The message identifier
+# 2. The Message text to be formatted and issued to the user
+# 3. The suggested resolution text, how to fix the problem.
+# 4. The description text, what is the problem so the user can understand
+#
+CONFIGURATION_STARTED=APPC0001I|\
+  ECOMP Application Controller (APP-C) initialization started at {0}|\
+  No resolution is required, this is an informational message|\
+  The APP-C component configuration has been started because the component is being \
+    initialized or loaded for the first time, or a new instance of the component is \
+    being created.  This message indicates that the component is starting.
+
+CONFIGURATION_CLEARED=APPC0002I|\
+  All prior configuration has been cleared|\
+  No resolution is required, this is an informational message|\
+  The APP-C component is being started or restarted and any prior configuration \
+    (if present), is cleared.  This is normal.
+
+LOADING_CONFIGURATION_OVERRIDES=APPC0003I|\
+  Loading configuration properties from file "{0}"|\
+  No resolution is required, this is an informational message|\
+  This message indicates that the configuration of the APP-C component was located \
+    and is being loaded from the specified file.
+
+LOADING_DEFAULTS=APPC0004I|\
+  Configuration defaults loaded from resource file "{0}"|\
+  No resolution is required, this is an informational message|\
+  This is a normal indication that the default configuration settings were loaded \
+    from the resource file.  The APP-C components load a default configuration first \
+    so that all configuration values have valid default settings.  Any user configuation \
+    that may be specified then overrides these defaults.
+
+NO_DEFAULTS_FOUND=APPC0005E|\
+  No default property resource "{0}" was found!|\
+  This is an internal error.  Contact support.|\
+  This is an internal error that indicates that the default resource property file \
+    could not be located.  This is likely a packaging error and is indicative of \
+    a construction problem.  Refer this to development or level 3 support for assistance.
+
+PROPERTY_VALUE=APPC0006I|\
+  Property "{0}" ="{1}"|\
+  No resolution is required, this is an informational message|\
+  This message is issued to show the value of configuration properties and is used to \
+    debug start up of the component.
+
+NO_OVERRIDE_PROPERTY_FILE_LOADED=APPC0007E|\
+  No configuration file named [{0}] was found on the configuration search path [{1}]. \
+    If a configuration file should have been loaded, check the file name and search \
+    path specified.  APPC will proceed using the default values and command-line \
+    overrides (if any).|\
+  If a configuration file was expected, verify the file name and that it exists on \
+    the search path for the configuration properties.  The search path defaults to \
+    <em>&#36;{user.home},/opt/app/appc/etc,etc,../etc,/etc,.</em> and can be overridden \
+    by specification of the property <em>org.onap.appc.bootstrap.path</em>.  The \
+    property file name defaults to <em>appc.properties</em> and can also be \
+    overridden by the <em>org.onap.appc.bootstrap.file</em> property.|\
+  This message indicates that the bootstrap path was searched for the bootstrap \
+    property file (a file that can be supplied to configure APPC) and that no file \
+    with the specified name was found on any of the path elements of the path.
+
+SEARCHING_CONFIGURATION_OVERRIDES=APPC0008I|\
+  Searching path "{0}" for configuration settings "{1}"|\
+  No resolution is required|\
+  This message indicates that the specified path is being examined for a configuration \
+    file of the indicated name.  The configuration file defaults to <em>appc.properties</em> \
+    but can be overridden by specification of the <em>org.onap.appc.bootstrap.file</em> \
+    property (using a command-line override, for example).  This message is intended to \
+    assist in the debugging and analysis of configuration issues where the indicated \
+    file may not be processed or found.  The path that is searched is a comma-delimited \
+    list of directories and defaults to <em>&#36;{user.home},/opt/app/appc/etc,etc,../etc,/etc,.</em> \
+    but can also be overridden by specification of the <em>org.onap.appc.bootstrap.path</em> \
+    property.
+
+LOADING_APPLICATION_OVERRIDES=APPC0009I|\
+  Loading application-specific override properties|\
+  No resolution required|\
+  This message indicates that the APPC component was invoked as an embedded component \
+    and that the caller has supplied an override property object.
+
+NO_APPLICATION_OVERRIDES=APPC0010I|\
+  No application-specific override properties were provided!|\
+  No resolution required|\
+  This message indicates that the APPC component was invoked as an embedded component \
+    and that the caller has supplied an override property object, but that object was \
+    empty.
+
+MERGING_SYSTEM_PROPERTIES=APPC0011I|\
+  Merging system properties into configuration|\
+  No resolution is required|\
+  This message indicates that the java virtual machine system properties are being \
+    examined and merged into the APP-C component configuration.  This allows for command \
+    line specification of any APP-C configuration property as a standard java define \
+    JVM option (ex: -Dproperty=value).
+
+SETTING_SPECIAL_PROPERTY=APPC0012I|\
+  Setting property "{0}={1}" in system properties|\
+  No resolution required.|\
+  This message indicates that the specified property loaded from defaults, property \
+    file overrides, application overrides, or command-line overrides is being placed \
+    in the system (java virtual machine) properties object.  Some libraries that may \
+    be integrated with APP-C (for example, DME2 or AFT libraries) may only look for \
+    their properties in the system properties object.  This allows those components \
+    to be configured from the APP-C configuration.
+
+LOADING_RESOURCE_BUNDLE=APPC0013I|\
+  Loading resource bundle "{0}"|\
+  No resolution required|\
+  This message indicates that the specified resource bundle is being loaded.
+
+LOGGING_ALREADY_INITIALIZED=APPC0014W|\
+  Logging has already been initialized, check the container logging definitions to ensure \
+    they represent your desired logging configuration.|\
+  If logging is configured incorrectly, move the definitions to the container or component \
+    that first initialized logging.  If they are ok, no resolution is required.|\
+  This message indicates that the logging environment already exists and has been configured.
+
+SEARCHING_LOG_CONFIGURATION=APPC0015I|\
+  Searching path "{0}" for log configuration file "{1}"|\
+  No resolution is required|\
+  This message indicates that the APP-C component configuration file specified a logging \
+    configuration file and/or search path and the path is being searched.  This is used to \
+    assist in debugging the configuration process.
+
+LOADING_DEFAULT_LOG_CONFIGURATION=APPC0016I|\
+  Loading default logging configuration from system resource file "{0}"|\
+  No resolution is required|\
+  A default logging configuration for the component is loaded from system resources to \
+    ensure that a valid logging environment exists.  This is a normal message, and will \
+    be followed by APPC0019I if a user-specified logging configuration overrides the \
+    defaults.
+
+NO_LOG_CONFIGURATION=APPC0017E|\
+  No log configuration could be found or defaulted!|\
+  A valid logging configuration cannot be found, and no default configuration resource \
+    was loaded.  This is likely a packaging issue and should be referred to development \
+    or level 3 support for assistance.|\
+  This is an internal error.
+
+UNSUPPORTED_LOGGING_FRAMEWORK=APPC0018E|\
+  An unsupported logging framework is bound to SLF4J.  Only Logback or Log4J are supported.|\
+  This is a compatibility error with logging frameworks used in the application environment \
+    and should be referred to development or level 3 support for assistance.|\
+  This is an internal error.
+
+LOADING_LOG_CONFIGURATION=APPC0019I|\
+  Loading logging configuration from file "{0}"|\
+  No resolution is required|\
+  The specified logging configuration is being loaded.
+
+UNKNOWN_PROVIDER=APPC0020E|\
+  Provider {0} cannot be found or cannot be resolved to one of the known providers, [{1}].|\
+  Specify the name of a valid provider. The IAAS adapter contains a set of providers \
+    that are defined.  Each of these providers is assigned a logical name.  The call \
+    to the IAAS adapter must specify the name of the provider that is desired.  This \
+    could be the result of an incorrect call, or the IAAS adapter configuration is \
+    wrong.|\
+  The APP-C IAAS adapter is being called to request a service on a specific provider, but \
+    the name of the provider cannot be found in the list of defined providers.  This may \
+    be an error in the directed graph that contains the call to the IAAS adapter, or it \
+    may be an error in the request, or the configuration of the IAAS adapter may need \
+    to be updated.
+
+SERVER_STATE_CHANGE_TIMEOUT=APPC0021E|\
+  Server name "{0}" with id "{1}" in tenant "{2}" and region "{3}" did not change state \
+    within the alloted time. Current state is "{4}" and the desired state(s) are "{5}"|\
+  This is likely a provider issue.  If the provider is OpenStack, check the virtual \
+    machine on the horizon dashboard.  If the machine is in an invalid state, you may \
+    need to contact Openstack support.  The exact mechanisms for recovery of a machine \
+    in an invalid state are varied and will be different from provider to provider.|\
+  This message indicates that the IAAS adapter has performed some requested action \
+    on the specified server (virtual machine) but the server did not enter a valid \
+    state (running, stopped, etc) within the timeout period.  The last state (current state) \
+    is shown, as well as the state that was expected.  The servers name, UUID, containing \
+    tenant, and region are shown so that the correct provider can be examined.
+
+SERVER_DELETED=APPC0022E|\
+  Server name "{0}" with id "{1}" in tenant "{2}" has a state of deleted and cannot be {3}.|\
+  The specified server has been deleted on the provider.  This is likely an incorrect \
+    request.  Make sure that you are specifying the correct server ID/name, provider, \
+    and region.  If the self-link URL is used, make sure that the correct server resource \
+    is specified.  If the machine was correct, recreate or rebuild the machine to make \
+    it usable.  Correct the request.|\
+  This message indicates that the server specified was found to have been deleted in the \
+    target provider and that the requested action cannot be performed.  This may be caused \
+    by several things:\
+    <ol>\
+      <li>The UUID of the server is wrong and specifies a machine that no longer exists</li>\
+      <li>The machine was deleted by a different process or request</li>\
+      <li>The wrong provider was requested</li>\
+      <li>The request was out-of-order</li>\
+    </ol>
+
+UNKNOWN_SERVER_STATE=APPC0023E|\
+  Server name "{0}" with id "{1}" in tenant "{2}" has an unknown state of "{3}".|\
+  Check the machine to determine the state of the machine.  Correct that state to a valid \
+    state if possible.  This may also be caused by an internal error in the PAL (Provider \
+    Abstraction Layer) used by the IAAS if a new state definition has been added to the \
+    provider (such as a new version or the installation of an unknown or unsupported \
+    extension).  If the machine's state is valid, refer this error to development or \
+    level 3 support for assistance.|\
+  This message indicates that a request was made to the IAAS adapter to take some action \
+    on the specified virtual machine, but the machine was found to be in a state that \
+    prevents that action from being performed.
+
+COMPONENT_INITIALIZING=APPC0024I|\
+  {0} component {1} is being initialized...|\
+  No resolution needed|\
+  The IAAS adapter is being initialized
+
+COMPONENT_INITIALIZED=APPC0025I|\
+  {0} component {1} has completed initialization|\
+  No resolution needed|\
+  The IAAS adapter has been initialized
+
+COMPONENT_TERMINATING=APPC0026I|\
+  {0} component {1} is terminating...|\
+  No resolution needed|\
+  The IAAS adapter is being terminated
+
+COMPONENT_TERMINATED=APPC0027I|\
+  {0} component {1} has terminated|\
+  No resolution needed|\
+  The IAAS adapter has been terminated
+
+IAAS_ADAPTER_UNSUPPORTED_OPERATION=APPC0028E|\
+  Operation {0} is not supported or implemented at this time.|\
+  Change the request to a supported operation|\
+  The IAAS adapter has been requested to perform some operation that it cannot \
+    perform at this time.
+
+IAAS_ADAPTER_RPC_CALLED=APPC0029I|\
+  Operation [{0}] called.  Input document:\n{1}|\
+  No resolution required|\
+  The IAAS adapter operation indicated was called with the requested input \
+    parameters.
+
+NO_SERVICE_FOUND=APPC0030E|\
+  Unable to locate the [{0}] service in the OSGi container|\
+  Ensure that the feature containing that service is installed and running|\
+  This indicates that the required feature could not be located
+
+CONTEXT_PARAMETERS_DISPLAY=APPC0031I|\
+  Dump of context parameters for module [{0}], RPC [{1}], and version [{2}]|\
+  No resolution required|\
+  The specified RPC is being called and the context properties are being \
+    displayed.  This is a debugging message and preceeds the display of \
+    each context property.
+
+RESPONSE_PARAMETERS_DISPLAY=APPC0032I|\
+  Response properties from execution of module [{0}], RPC [{1}], and version [{2}] are:|\
+  No resolution required|\
+  The service logic directed graph has been executed and returned the response properties. \
+  This message preceeds the dump of the response properties.  It is used for debugging \
+  of service logic and execution problems.
+
+NULL_OR_INVALID_ARGUMENT=APPC0033E|\
+  Service {0}:{1} was provided a null (empty) or invalid argument, [{2}] = [{3}]|\
+  This is likely an internal error, refer to support for assistance|\
+  The indicated service was called, but the specified parameter or argument was either \
+    null or empty, or it was invalid.  If it has a value, the value is shown.  If the \
+    value is null, the value is shown as 'null'.
+
+PROCESSING_REQUEST=APPC0034I|\
+  Service {0}:{1} is processing service [{2}] with request id [{3}]|\
+  No resolution required|\
+  The indicated application and RPC is processing the specified service request.
+
+INVALID_SERVICE_REQUEST=APPC0035E|\
+  Service {0}:{1} received request for service [{2}] but that service is invalid or unknown.|\
+  Correct the service request, likely a directed graph issue|\
+  The RPC was invoked to process a service request, but the service is not valid.
+
+REGISTERING_SERVICE=APPC0036I|\
+  {0} registering service {1} using class {2}|\
+  No resolution required|\
+  The indicated application service is registering itself with the OSGi container using the \
+    indicated java class name.
+
+UNREGISTERING_SERVICE=APPC0037I|\
+  {0} unregistering service {1}|\
+  No resolution required|\
+  The application service is being unregistered from the OSGi container services list.
+
+LOADING_PROVIDER_DEFINITIONS=APPC0038I|\
+  {0} IAAS Adapter initializing provider {1} as {2}|\
+  No resolution is required|\
+  The IAAS adapter is loading the definition of the specified provider from its \
+    configuration file.
+
+RESTARTING_SERVER=APPC0039I|\
+  {0} IAAS Adapter restart of server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the restart of a server.  The \
+    properties that govern the request are echoed immediately following this message.
+
+REBUILDING_SERVER=APPC0040I|\
+  {0} IAAS Adapter rebuild of server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the rebuilding of a server.  The \
+    properties that govern the request are echoed immediately following this message.
+
+INVALID_SELF_LINK_URL=APPC0041E|\
+  {0} IAAS Adapter cannot perform requested service, VM url [{1}] is invalid|\
+  Correct the call to the adapter with a valid self-link URL|\
+  The IAAS adapter has been called to perform some operation on a virtual machine \
+    but the vm_id of the virtual machine is not valid.
+
+SERVER_FOUND=APPC0042I|\
+  Located server {0} on tenant [{1}] and in state [{2}]|\
+  No resolution required|\
+  This message indicates that a service request was made to perform some action on the server \
+    and the indicated server was located on the specified tenant.\
+
+
+STACK_FOUND=APPC0042I|\
+  Located stack {0} on tenant [{1}] and in state [{2}]|\
+  No resolution required|\
+  This message indicates that a service request was made to perform some action on the server \
+    and the indicated server was located on the specified tenant.
+
+
+
+SERVER_NOT_FOUND=APPC0043E|\
+  No server found in provider with self-link URL [{0}]|\
+  Correct the server URL|\
+  The requested server, identified by its self link URL, could not be found in the provider
+
+SERVER_OPERATION_EXCEPTION=APPC0044E|\
+  Exception {0} was caught attempting {1} of server [{2}] on tenant [{3}]|\
+  Contact support for assistance|\
+  An exception was caught while trying to perform the indicated operation on the server. The \
+    exception may yield more information about the cause of the error.  This may be because \
+    of access security, or the server is in an invalid state, or any number of reasons.  This \
+    message should be referred to support for assistance.
+
+
+STACK_NOT_FOUND=APPC0043E|\
+  No stack found in provider with self-link URL [{0}]|\
+  Correct the server URL|\
+  The requested stack, identified by its self link URL, could not be found in the provider
+
+STACK_OPERATION_EXCEPTION=APPC0044E|\
+  Exception {0} was caught attempting {1} of server [{2}] on tenant [{3}]|\
+  Contact support for assistance|\
+  An exception was caught while trying to perform the indicated operation on the stack. The \
+    exception may yield more information about the cause of the error.  This may be because \
+    of access security, or the stack is in an invalid state, or any number of reasons.  This \
+    message should be referred to support for assistance.
+
+MISSING_REQUIRED_PROPERTIES=APPC0045E|\
+  One or more properties for [{0}] are missing, null, or empty.  They are:|\
+  A request to execute the adapter indicated was made from a directed graph, but the properties \
+    of the request that are required by the adapter are missing or do not have a value.  Correct \
+    the directed graph to supply the missing properties.|\
+  The specified properties for the indicated adapter operation are invalid or missing.
+
+SERVER_ERROR_STATE=APPC0046E|\
+  The server [{0}] (id={1}) in tenant {2} is in error state, {3} is not allowed|\
+  Destroy and recreate the instance|\
+  A request to restart or rebuild a server in an error state was received, but those operations \
+    are not allowed on a server in this state.  OpenStack only allows a deletion of a server \
+    that is in the error state.
+
+IMAGE_NOT_FOUND=APPC0047E|\
+  The image {0} could not be located for {1}.|\
+  The image indicated could not be found.  If the operation being requested is a rebuild of \
+    a server, then there is no action that can be taken other than to destroy the server and \
+    rebuild it using an image that exists.|\
+  This is likely caused by an image being deleted after it was used to build a server.  If the \
+    request is for a server rebuild, then the image used to create the server was later deleted \
+    and no longer exists.  The server cannot be rebuilt, because the image doesnt exist. \
+    The server must be deleted and reconstructed using a valid, existing image.
+
+STATE_CHANGE_TIMEOUT=APPC0048E|\
+  Time out waiting for {0} with name {1} (and id {2}) to reach one of {3} states, current state is {4}|\
+  Recover the resource in whatever means is appropriate|\
+  The resource indicated (by name and id) was expected to change it's state (status) to one of the \
+    indicated expected states within a specified timeout but the resource did not complete the \
+    state change.  It's current state is also shown. This can be caused by any number of factors \
+    but is normally a problem or conflict within the IaaS provider (OpenStack).
+
+STATE_CHANGE_EXCEPTION=APPC0049E|\
+  Exception {0} waiting for {1} with name {2} (and id {3}) to reach one of {4} states, current state is {5}\n\
+    cause={6}|\
+  Recover the resource in whatever means is appropriate|\
+  The resource indicated (by name and id) was expected to change it's state (status) to one of the \
+    indicated expected states within a specified timeout but the resource did not complete the \
+    state change.  It's current state is also shown. This can be caused by any number of factors \
+    but is normally a problem or conflict within the IaaS provider (OpenStack).
+
+STOP_SERVER=APPC0050I|\
+  Server {0} is being stopped...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be stopped.
+
+START_SERVER=APPC0051I|\
+  Server {0} is being started...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be started.
+
+RESUME_SERVER=APPC0052I|\
+  Server {0} is being resumed...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be resumed from a suspended state.
+
+UNPAUSE_SERVER=APPC0053I|\
+  Server {0} is being unpaused...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be unpaused from a paused state.
+
+CONNECTION_FAILED_RETRY=APPC0054E|\
+  Connection to provider {0} at identity {1} using tenant name {2} (id {3}) failed, reason={4}, \
+    retrying in {5} seconds, attempt {6} of {7}.|\
+  The connection to the provider could not be obtained for the indicated reason.  The application \
+    controller will retry the attempt to connect to the provider a maximum number of times.  The \
+    message contains the amount of time the system will wait to retry the connection, and the \
+    current attempt and the maximum number of attempts.|\
+  Correct the cause of the connection failure as indicated by the reason.
+
+CONNECTION_FAILED=APPC0055E|\
+ Connection to provider {0} at service {1} failed after all retry attempts.|\
+ The connection to the named provider at the indicated service URL cannot be opened.  All \
+   retries have been exhausted.  The application controller is giving up on the connection and will \
+   fail the request.|\
+ Correct the cause of the connection failure as indicated by the reason(s) in previous APPC0054E \
+   messages.
+
+STOPPING_SERVER=APPC0056I|\
+  {0} IAAS Adapter stop server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the server to be stopped.  The \
+    properties that govern the request are echoed immediately following this message.
+
+STARTING_SERVER=APPC0057I|\
+  {0} IAAS Adapter start server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the server to be start.  The \
+    properties that govern the request are echoed immediately following this message.
+
+REBUILD_SERVER_FAILED=APPC0057E|\
+  Server {0} (id {1}) failed to rebuild, reason {2}|\
+  The server rebuild failed for the indicated reason. Correct the cause of the failure and \
+    rerun, if applicable.|\
+  The adapter has attempted to rebuild the indicated server but the rebuild request has \
+    been failed by the provider for some reason.  The reason returned by the provider is \
+    included in the message.
+
+PARAMETER_IS_MISSING=APPC0058E|\
+  Application {0} graph {1} response did not set the {2} parameter. This parameter is \
+    required for synchronization with the controller. Absence of this parameter is assumed \
+    to be a failure. Please correct the DG.|\
+  The indicated directed graph was called from the application controller but when the \
+    graph returned the indicated property was not defined in the return parameters.  The \
+    controller requires that property to be defined and set to a value that is used to \
+    inform the controller of the outcome of operations in the graph.  Failure to set \
+    the required parameter is assumed to be a failure regardless if the graph actually \
+    succeeded or not.|\
+  Correct the DG to set the specified parameter to a value that is expected and understood \
+    by the controller.
+
+PARAMETER_NOT_NUMERIC=APPC0059E|\
+  Application {0} graph {1} did not set parameter {2} to a valid numeric value ({3}). \
+    Please correct the DG.|\
+  The indicated directed graph was called by the application controller and the graph \
+    did set the specified property, however the property is not a valid numeric \
+    value.  The parameter is used to convey a numeric quantity and the controller \
+    cannot convert the value specified to a number. |\
+  Correct the DG.
+
+DG_FAILED_RESPONSE=APPC0060E|\
+  Application {0} graph {1} completed with failure: error code = {2}, message = {3}|\
+  The directed graph indicated was called by the application controller and when \
+    the graph returned, an error code was set indicating that the graph failed. This \
+    is a message that echoes the results of the graph, and shows the returned error \
+    code and message.|\
+  Correct the cause of the error.
+
+EXCEPTION_CALLING_DG=APPC0061E|\
+  Application {0} received exception {1} attempting to call graph {2}, exception \
+    message = {3}|\
+  The application controller attempted to call the service logic interpreter (SLI) \
+    to execute the indicated graph, but an exception was caught.  The class of the \
+    exception is shown, as is the message associated with the exception.  An \
+    abbreviated stack trace is also displayed to provide information as to the \
+    state of the thread at the time of the exception.|\
+  Correct the cause of the exception and rerun.
+
+GRAPH_NOT_FOUND=APPC0062E|\
+  Application {0} was unable to locate graph {1}|\
+  The application controller attempted to call the service logic interpreter (SLI) \
+    to execute the specified graph but the graph does not exist in the SLI database.|\
+  Correct the database and install the correct graph.
+
+DEBUG_GRAPH_RESPONSE_HEADER=APPC0063D|\
+  Application {0} graph {1} responded with {2} properties|\
+  This is a debugging message that is output immediately after the call to the \
+    directed graph and before any processing is performed to determine the success \
+    or failure of that call.  The heading is output prior to dumping all the parameters \
+    that were returned by the graph.|\
+  No recovery action is required.
+
+DEBUG_GRAPH_RESPONSE_DETAIL=APPC0064D|\
+  {0}:{1} - {2} = {3}|\
+  This is a debugging message that is output immediately after the call to the \
+    directed graph and before any processing is performed to determine the success \
+    or failure of that call.  This message is repeated for each parameter that \
+    exists in the return context from the graph.|\
+  No recovery action is required.
+
+INVALID_REQUIRED_PROPERTY=APPC0065E|\
+  Application {0} request "{1}" was supplied a property "{2}" with the value "{3}" \
+    that does not meet the required form(s):|\
+  This message indicates that the specified requested operation was passed the \
+    specific property named and the property value did not meet the expected \
+    format requirements.  For example, if the property is expected to be a \
+    numeric quantity and it contains alphabetic characters, or if it is expected \
+    to be a URL and it is not valid.  The message also contains a list of one \
+    or more regular expressions that were used to validate the input, and which \
+    supply the syntax required for the property.|\
+  Correct the property and retry.
+
+ATTACHINGVOLUME_SERVER=APPC0068I|\
+  {0} IAAS Adapter attaching of volume to server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the attaching of volume to server.  The \
+    properties that govern the request are echoed immediately following this message.
+
+DETTACHINGVOLUME_SERVER=APPC0069I|\
+  {0} IAAS Adapter detaching of volume from server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the detaching of volume from server.  The \
+   properties that govern the request are echoed immediately following this message.
+
+MIGRATING_SERVER=APPC066I|\
+  {0} IAAS Adapter migrate of server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the migration of a server.  The \
+    properties that govern the request are echoed immediately following this message.
+
+EVACUATING_SERVER=APPC0067I|\
+  {0} IAAS Adapter evacuate of server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the evacuation of a server.  The \
+    properties that govern the request are echoed immediately following this message.
+
+MIGRATE_SERVER_FAILED=APPC0068E|\
+  Server {0} (id {1}) failed to migrate during {2} phase, reason {3}|\
+  The server migration failed for the indicated reason. Correct the cause of the failure and \
+    rerun, if applicable.|\
+  The adapter has attempted to migrate the indicated server but the migration request has \
+    been failed by the provider for some reason.  The reason returned by the provider is \
+    included in the message.
+
+EVACUATE_SERVER_FAILED=APPC0069E|\
+  Server {0} (id {1}) failed to evacuate, reason {2}|\
+  The server evacuation failed for the indicated reason. Correct the cause of the failure and \
+    rerun, if applicable.|\
+  The adapter has attempted to evacuate the indicated server but the evacuation request has \
+    been failed by the provider for some reason.  The reason returned by the provider is \
+    included in the message.
+
+APPC_TOO_BUSY=APPC0080E|\
+  APP-C instance is too busy|\
+  The APP-C instance handles too many requests and cannot accept new ones as its internal \
+  execution queue is full. The problem can appear when the APP-C instance gets more requests \
+  than it can handle simultaneously.|\
+  Check the server KPIs for possible performance issues (e.g. insufficient memory, \
+  high network latency, slow responsiveness of southbound systems and so on) which can affect \
+  the system throughput.
+
+VF_SERVER_BUSY=APPC0081E|\
+  Concurrent access to server "{0}"|\
+  APP-C currently executes a command on the specified server and cannot accept yet another request \
+  for the same one.|\
+  Try to resubmit the request at later time.
+
+VF_ILLEGAL_COMMAND=APPC0082E|\
+  Server "{0}" does not support command "{1}" in the current state "{2}"|\
+  APP-C cannot perform the requested command on the server in the current state as no state transition \
+  is defined for that.|\
+  Contact support for assistance.
+
+VF_UNDEFINED_STATE=APPC0083E|\
+  Server "{0}" cannot handle command "{1}" because of its doubtful state|\
+  The resource has undefined working state as result of abnormal termination of a previous command.|\
+  Recover the resource in whatever means is appropriate.
+
+APPC_NO_RESOURCE_FOUND=APPC0084E|\
+  No resource found with ID "{0}" in A&AI system.|\
+  APP-C is unable to resolve the VF details given the instance ID.|\
+  Check whether the resource has been deleted (terminated) before.
+
+APPC_EXPIRED_REQUEST=APPC0085E|\
+  The request "{0}" for server "{1}" has exceeded its TTL limit of "{2}" seconds|\
+  The received expired event won't be handled by APP-C instance. Normally the problem might be \
+  related to asynchronous requests arriving to APP-C instance via DMaaP channel.|\
+  Try to submit a new request if still relevant.
+
+APPC_WORKFLOW_NOT_FOUND=APPC0086E|\
+  Workflow for vnfType = "{0}" and  command = "{1}" not found.|\
+  Unable to retrive Workflow related to mention VNF type and command.|\
+  Check provided VNF and Command details are correct.
+
+APPC_INVALID_INPUT=APPC0087E|\
+  Null vnfId and command provided|\
+  Request contains Null vnfId and command|\
+  Provided non-null VNF and Command details.
+
+APPC_AUDIT_MSG=APPC0090A|\
+  Operation "{0}" for VNF type "{1}" from Source "{2}" with RequestID "{3}" \
+  was started at "{4}" and ended at "{5}" with status code "{6}"|\
+  Audit detailed msg|\
+  Audit detailed msg.
+
+AAI_CONNECTION_FAILED=APPC0106E|\
+  APP-C is unable to communicate with A&AI|\
+  Connection to A&AI at service {0} failed after all retry attempts.|\
+  The connection to the A&AI at the indicated service URL cannot be opened. \
+  All retries have been exhausted. APP-C is giving up on the connection and will \
+  reject the operation request.|\
+  .
+
+AAI_UPDATE_FAILED=APPC0107E|\
+  APP-C is unable to update COMPONENT_ID {0} to {1} for reason {2}|\
+  The update at the end of the operation wasn't performed as a result of \
+  A&AI communication failure or its internal error.|\
+  .
+
+AAI_GET_DATA_FAILED=APPC0108E|\
+  APP-C is unable to retrieve VF/VFC {0} data for Transaction ID {1} as a \
+  result of A&AI communication failure or its internal error.|\
+  Operation request will be rejected by APP-C|\
+  .
+
+AAI_CONNECTION_FAILED_RETRY=APPC0105W|\
+  A&AI at identity {0} using VNF_ID {1} failed, reason={2}, retrying in {3} seconds, attempt {4} of {5}.|\
+  The connection to the A&AI could not be obtained for the indicated reason. APP-C will retry to connect \
+  to the A&AI. The message contains the retry delay, the current attempt and the maximum number of attempts.|\
+  Correct the cause of the connection failure as indicated by the reason.
+
+AAI_DELETE_FAILED=APPC0114E|\
+  APP-C is unable to delete COMPONENT_ID {0} for reason {1}|\
+  The deletion at the end of the operation wasn't performed as a result of \
+  A&AI communication failure or its internal error.|\
+  .
+
+AAI_QUERY_FAILED=APPC0115E|\
+  Error Querying AAI with vnfID = {0}|\
+  Querying AAI for the given vnf id returns failure to APPC|\
+  .
+
+VNF_CONFIGURED=APPC0118I|\
+  VNF {0} is configured|\
+  No resolution is required, this is an informational message|\
+  The VNF configuration has been completed.
+
+VNF_CONFIGURATION_STARTED=APPC0116I|\
+  VNF {0} is being configured|\
+  No resolution is required, this is an informational message|\
+  The VNF configuration has been started
+
+VNF_CONFIGURATION_FAILED=APPC0119E|\
+  VNF {0} configuration failed for reason {1}|\
+  The configuration operation wasn't performed as a result of VNF communication failure or its internal error.|\
+  .
+
+VNF_TEST_STARTED=APPC0120I|\
+  VNF {0} is being tested|\
+  No resolution is required, this is an informational message|\
+  The VNF test has been started
+
+VNF_TESTED=APPC0121I|\
+  VNF {0} was tested|\
+  No resolution is required, this is an informational message|\
+  The VNF test has been completed
+
+VNF_TEST_FAILED=APPC0122E|\
+  VNF {0} test failed for reason {1}|\
+  The test operation wasn't performed as a result of VNF communication failure or its internal error.|\
+  .
+
+VNF_NOT_FOUND=APPC0123E|\
+  VNF not found with vnf_id {0}|\
+  The VNF wasn't found for the given vnf-id.|\
+  .
+
+VNF_HEALTHCECK_FAILED=APPC0124E|\
+  VNF {0} Healthcheck operation failed, reason {1}|\
+  The health check operation wasn't performed as a result of VNF communication failure or its internal error.|\
+  .
+
+VM_HEALTHCECK_FAILED=APPC0125E|\
+  VM {0} Healthcheck operation failed, reason {1}|\
+  The health check operation wasn't performed as a result of VNF communication failure or its internal error.|\
+  .
+
+STOP_SERVER_FAILED=APPC0112E|\
+  Server {0} (id {1}) failed to stop during {2} phase, reason {3}|\
+  The server stop failed for the indicated reason. Correct the cause of the failure and \
+  rerun, if applicable.|\
+  The adapter has attempted to stop the indicated server but the stop request has \
+  been failed by the provider for some reason. The reason returned by the provider is \
+  included in the message.
+
+TERMINATE_SERVER_FAILED=APPC0113E|\
+  Server {0} (id {1}) failed to terminate during {2} phase, reason {3}|\
+  The server termination failed for the indicated reason. Correct the cause of the failure and \
+  rerun, if applicable.|\
+  The adapter has attempted to terminate the indicated server but the migration request has \
+  been failed by the provider for some reason. The reason returned by the provider is \
+  included in the message.
+
+TERMINATE_STACK_FAILED=APPC0113E|\
+  Server {0} (id {1}) failed to terminate during {2} phase, reason {3}|\
+  The server termination failed for the indicated reason. Correct the cause of the failure and \
+  rerun, if applicable.|\
+  The adapter has attempted to terminate the indicated server but the migration request has \
+  been failed by the provider for some reason. The reason returned by the provider is \
+  included in the message.
+
+TERMINATING_SERVER=APPC0114I|\
+  {0} IAAS Adapter terminate server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the server to be terminated. The \
+  properties that govern the request are echoed immediately following this message.
+
+
+TERMINATING_STACK=APPC0115I|\
+  {0} IAAS Adapter terminate stack requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the server to be terminated. The \
+  properties that govern the request are echoed immediately following this message.
+
+TERMINATE_SERVER=APPC0116I|\
+  Server {0} is being terminated...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be terminated.
+
+TERMINATE_STACK=APPC0117I|\
+  Stack {0} is being terminated...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be terminated.
+
+MIGRATE_COMPLETE=APPC0118I|\
+  Migrate {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...|\
+  No resolution is required, this is an informational message|\
+  APP-C Migrate Operation has completed.
+
+RESTART_COMPLETE=APPC0119I|\
+  Restart {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...|\
+  No resolution is required, this is an informational message|\
+  APP-C Restart Operation has completed.
+
+REBUILD_COMPLETE=APPC0120I|\
+  Rebuild {0} finished with status {1}. Start Time: {2}. End Time: {3}. Request ID: {4}. Reason:{5}...|\
+  No resolution is required, this is an informational message|\
+  APP-C Rebuild Operation has completed.
+
+CLOSE_CONTEXT_FAILED=APPC0121E|\
+  Exception {0} was caught attempting to close provider context for {1}.|\
+  Contact support for assistance|\
+  An exception was caught while trying to close the provider context. The \
+    exception may yield more information about the cause of the error.  This may be because \
+    of access security, or the server is in an invalid state, or any number of reasons.  This \
+    message should be referred to support for assistance.
+
+SNAPSHOTING_STACK=APPC0122I|\
+  Stack {0} is being snapshoted...|\
+  No resolution is required|\
+  Stack snapshot.
+
+STACK_SNAPSHOTED==APPC0123I|\
+  Stack {0} snapshoted, snapshot ID = [{1}].|\
+  No resolution is required|\
+  Stack snapshoted successfully.
+
+
+RESTORING_STACK=APPC0124I|\
+  Stack {0} is being restored to snapshot {1}...|\
+  No resolution is required|\
+  Stack restore.
+
+STACK_RESTORED=APPC0125I|\
+  Stack {0} is restored to snapshot {1}.|\
+  No resolution is required|\
+  Stack restored successfully.
+
+MISSING_PARAMETER_IN_REQUEST=APPC0126E|\
+  Parameter {0} is missing in svc request of {1}.|\
+  Check DG node definition to pass missing parameter's value.|\
+  Node definition in DG missing indicated parameter value or value is incorrect, \
+  check the graph definition.
+
+CANNOT_ESTABLISH_CONNECTION=APPC0127E|\
+  Cannot establish connection to server {0} port {1} with user {2}.|\
+  Check server IP, port and user credentials.|\
+  Wrong data sent in request's payload.
+
+
+APPC_METRIC_MSG=APPC0128I|\
+  Operation "{0}" for VNF type "{1}" from Source "{2}" with RequestID "{3}" on "{4}" with action "{5}" \
+  ended in {6} ms with result "{7}"|\
+  No resolution is required, this is an informational message|\
+  This message indicates that the APPC logged some operation to metric
+
+ SNAPSHOTING_SERVER=APPC0129I|\
+{0} IAAS Adapter create snapshot of server requested|\
+No resolution is required, this is an informational message|\
+This message indicates that a IAAS Adapter create snapshot of server was requested.
+
+INPUT_PAYLOAD_PARSING_FAILED = APPC0130E|\
+   Failed to parsing the input payload: {0}|\
+   Please provide correct input string for parsing.|\
+  .
+
+APPC_EXCEPTION = APPC0132E|\
+  Error occurred for VNF type : {0}, reason {1}|\
+  Runtime exception thrown by APPC.|\
+  .
+
+SSH_DATA_EXCEPTION = APPC0133E|\
+  SSH Data Exception occurred, reason {0}|\
+  SSH Data exception occurred.|\
+  .
+
+JSON_PROCESSING_EXCEPTION = APPC0134E|\
+  Json processing exception occurred, reason {0}|\
+  Json processing Exception|\
+  .
+
+SUCCESS_EVENT_MESSAGE = APPC0136I|\
+  Operation {0} succeed for {1}|\
+  Success message.|\
+  .
+DEPENDENCY_MODEL_NOT_FOUND = APPC0137E|\
+  Dependency model not found for VNF type {0}, reason {1}|\
+  Please provide dependency model|\
+  .
+
+INVALID_DEPENDENCY_MODEL = APPC0138E|\
+  Invalid Dependency model for VNF Type {0}, reason {1}|\
+  Invalid dependency model found |\
+  .
+
+
+FAILURE_RETRIEVE_VNFC_DG = APPC0139E|\
+  Failed to retrieve DG for VNFC Type: {0}|\
+  Failed to retrieve VNFC DG |\
+  .
+
+
+SERVER_NETWORK_ERROR=APPC0140E|\
+  Server {0} either has a port {1} that is NOT online, or the status of the network to which the port is connected to is not ACTIVE|\
+  Please ensure they are UP and running before requested operation|\
+  It is critical that the VM Server is reachable by the Provider(ex: OpenStack) in order to be able to perform \
+  the requested operation on it.
+  .
+
+REBUILD_SERVER=APPC0140I|\
+  Server {0} is being rebuilt...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the indicated server be rebuilt.
+
+HYPERVISOR_DOWN_ERROR=APPC0141E|\
+  Hypervisor {0} for the Server {1} is either NOT ENABLED, or its status is DOWN or UNKNOWN|\
+  Please ensure the Hypervisor is UP and running before proceeding with the requested operation|\
+  It is critical that the Hypervisor that manages the Virtual Machine for the Server is reachable by the Provider(ex: OpenStack) in order to be able to perform \
+  the requested operation on it.
+  .
+
+HYPERVISOR_STATUS_UKNOWN=APPC0158E|\
+  Unable to determine the status of the Hypervisor for the Server {0} |\
+  Please ensure the userid has privileges enabled to query for the Hypervisor status. |\
+  If you wish to proceed with the requested operation, either obtain the privileges from the Cloud provider, or skip the Hypervisor check and retry the request.
+  .
+
+HYPERVISOR_NETWORK_ERROR=APPC0142E|\
+  Hypervisor {0} for the Server {1} is NOT Reachable by APPC for initiating the requested operation|\
+  Please ensure the Hypervisor is connected to the network before proceeding with the requested operation|\
+  It is critical that the Hypervisor that manages the Virtual Machine for the Server is reachable by the Provider(ex: OpenStack) in order to be able to perform \
+  the requested operation on it.
+
+EVACUATE_SERVER_REBUILD_FAILED=APPC0143E|\
+  Server {0} evacuate from host {1} to host {2} failed during the rebuild on host {2}, reason {3}|\
+  The server rebuild after evacuation failed for the indicated reason. Correct the cause of the failure and \
+    run a rebuild, if applicable.|\
+  The adapter has attempted to rebuild after evacuating the indicated server but the rebuild request has \
+    been failed by the provider for some reason.  The reason returned by the provider is \
+    included in the message.
+
+RESTART_APPLICATION=APPC0144I|\
+  Application on server {0} is being restarted...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the application on the indicated server be restarted.
+
+START_APPLICATION=APPC0145I|\
+  Application on server {0} is being started...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the application on the indicated server be started.
+
+APPLICATION_RESTART_FAILED=APPC0146E|\
+  Restart application operation failed on server : {0}, reason {1}|\
+  Restart application operation failure.|\
+  Correct the cause of the failure as indicated by the reason. 
+
+APPLICATION_START_FAILED=APPC0147E|\
+  Start application operation failed on server : {0}, reason {1}|\
+  Start application operation failure.|\
+  Correct the cause of the failure as indicated by the reason. 
+
+LOOKING_SERVER_UP=APPC0148I|\
+{0} IAAS Adapter looking up for the server requested|\
+No resolution is required, this is an informational message|\
+This message indicates that a IAAS Adapter lookup of server was requested.
+
+EVACUATE_SERVER_REBUILD_FAILED=APPC0149E|\
+  Server {0} evacuate from host {1} to host {2} failed during the rebuild on host {2}, reason {3}|\
+  The server rebuild after evacuation failed for the indicated reason. Correct the cause of the failure and \
+    run a rebuild, if applicable.|\
+  The adapter has attempted to rebuild after evacuating the indicated server but the rebuild request has \
+    been failed by the provider for some reason.  The reason returned by the provider is \
+    included in the message.
+
+APPLICATION_STOP_FAILED=APPC0150E|\
+  Stop application operation failed on server : {0}, reason {1}|\
+  Stop application operation failure.|\
+  Correct the cause of the failure as indicated by the reason.
+
+STOP_APPLICATION=APPC0151I|\
+  Application on server {0} is being stopped...|\
+  No recovery required|\
+  The processing being performed by APPC requires that the application on the indicated server be stopped.
+
+LCM_OPERATIONS_DISABLED=APPC0152E|\
+  APPC LCM operations have been administratively disabled|\
+  No recovery required|\
+  This is a indication that the APPC LCM operations are disabled.
+
+OAM_OPERATION_EXCEPTION=APPC0153E|\
+  Application {0} received exception {1} while attempting to execute oam operation {2}, exception message = {3}|\
+  The application controller attempted to perform an OAM operation \
+    but an exception was caught.  The class of the \
+    exception is shown, as is the message associated with the exception.  An \
+    abbreviated stack trace is also displayed to provide information as to the \
+    state of the thread at the time of the exception.|\
+  Correct the cause of the exception and rerun.
+
+OAM_OPERATION_ENTERING_MAINTENANCE_MODE=APPC0154W|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC will no longer accept new LCM requests. Previously accepted LCM requests will be allowed to complete.
+
+OAM_OPERATION_MAINTENANCE_MODE=APPC0155W|\
+  Application {0} is in {1}|\
+  No recovery required|\
+  The APPC is not accepting new LCM requests and all previously accepted LCM requests have completed.
+
+OAM_OPERATION_STARTING=APPC0156I|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC has initiated its startup procedure. Its internal components are coming online.  Once completed it will start accepting LCM requests.
+
+OAM_OPERATION_STARTED=APPC0157I|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC will now accept new LCM requests for processing.
+
+INVALID_STATE_TRANSITION=APPC0158E|\
+  A {1} API is not allowed when {0} in the {2} state|\
+  No recovery required|\
+  The Operation requested cannot be performed as per the current state of APPC.
+
+OAM_OPERATION_STOPPING=APPC0159W|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC has initiated its stop procedure. Its internal LCM bundles are stopping.
+
+OAM_OPERATION_STOPPED=APPC0160W|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC LCM bundles have now stopped.
+
+REQUEST_HANDLER_UNAVAILABLE=APPC0161E|\
+  Application {0} was unable to find the Request Handler service |\
+  The application controller attempted to get a handle on Request Handler service \
+    but was unable to locate it in  the OSGi Service Registry.|\
+  Verify if the Request Handler bundle is running.
+
+OAM_OPERATION_RESTARTING=APPC0162W|\
+  Application {0} is {1}|\
+  No recovery required|\
+  The APPC has initiated its restart procedure. Its internal LCM bundles are stopping and will then start again.
+
+OAM_OPERATION_RESTARTED=APPC0163W|\
+  Application {0} is {1} for restart|\
+  No recovery required|\
+  The APPC LCM bundles have been restared (stopped and then started).
+
+OAM_OPERATION_INVALID_INPUT=APPC0162E|\
+  {0}|\
+  No recovery required|\
+  Fix the input parameter and retry.
+
+IAAS_UNSUPPORTED_IDENTITY_SERVICE=APPC0163E|\
+  Unsupported identity service version, unable to retrieve ServiceCatalog for identity service {0}|\
+  Verify the identity url provided is correct. Currently supported version of the OpenStack identity servicer\
+    are v2 and v3. If a support for a new version in required contact development.|\
+  This message indicates that a request was made to connect to an unsupported version of \
+    identity service.
+
+SFTP_TRANSFER_FAILED=APPC0164E|\
+  Sftp data transfer failed on connection to host {0} with user {1} for {2} operation, reason : {3}|\
+  Correct the cause of the failure as indicated by the reason and retry.|\
+  This message indicates that a failure occured during data transfer over sftp connection.\
+    The reason returned by the target instance is included in the message.
+
+SSH_CONNECTION_TIMEOUT=APPC0165E|\
+  Ssh session with host {0} has timed out during command {1} execution|\
+  Check connection to host and validate executed command.|\
+  The APPC tried to execute ssh command on specified host, and the execution took longer time than expected.
+
+SSH_SESSION_CONFIG_ERROR=APPC0166E|\
+  Could not configure existing ssh session, reason: {0}|\
+  Correct the cause of the failure as indicated by the reason.|\
+  This message indicates that additional configuration for already opened ssh session has failed.\
+    The reason returned by the session provider is included in the message.
+
+REBOOT_SERVER=APPC0167I|\
+  {0} IAAS Adapter reboot of server requested|\
+  No resolution required|\
+  A graph has invoked the IAAS adapter and has requested the reboot of a server.  The \
+    properties that govern the request are echoed immediately following this message.
diff --git a/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/auth.properties b/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/i18n/auth.properties
new file mode 100644 (file)
index 0000000..6985853
--- /dev/null
@@ -0,0 +1,25 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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=========================================================
+###
+
+username=admin
+password=admin
diff --git a/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/org.ops4j.pax.logging.cfg b/appc-core/appc-common-bundle/src/main/resources/org/onap/appc/org.ops4j.pax.logging.cfg
new file mode 100644 (file)
index 0000000..a3a3f58
--- /dev/null
@@ -0,0 +1,149 @@
+    ################################################################################
+    #
+    #    Licensed to the Apache Software Foundation (ASF) under one or more
+    #    contributor license agreements.  See the NOTICE file distributed with
+    #    this work for additional information regarding copyright ownership.
+    #    The ASF licenses this file to You under the Apache License, Version 2.0
+    #    (the "License"); you may not use this file except in compliance with
+    #    the License.  You may obtain a copy of the License at
+    #
+    #       http://www.apache.org/licenses/LICENSE-2.0
+    #
+    #    Unless required by applicable law or agreed to in writing, software
+    #    distributed under the License is distributed on an "AS IS" BASIS,
+    #    WITH WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    #    See the License for the specific language governing permissions and
+    #    limitations under the License.
+    #
+    ################################################################################
+
+    # Root
+    #log4j.rootLogger=TRACE, osgi:VmLogAppender
+    log4j.rootLogger=TRACE, out, sift, osgi:*
+    log4j.throwableRenderer=org.apache.log4j.OsgiThrowableRenderer
+
+    # CONSOLE appender not used by default
+    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+    log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
+
+    # Async appender forwarding to file appender
+    log4j.appender.async=org.apache.log4j.AsyncAppender
+    log4j.appender.async.appenders=out
+
+    # Karaf appenders
+    # File appender
+    log4j.appender.out=org.apache.log4j.RollingFileAppender
+    log4j.appender.out.layout=org.apache.log4j.PatternLayout
+    log4j.appender.out.layout.ConversionPattern=%d{ISO8601} | %-5.5p | %-16.16t | %-32.32c{1} | %X{bundle.id} - %X{bundle.name} - %X{bundle.version} | %m%n
+    log4j.appender.out.file=${karaf.data}/log/karaf.log
+    log4j.appender.out.append=true
+    log4j.appender.out.maxFileSize=10MB
+    log4j.appender.out.maxBackupIndex=100
+
+
+    # Sift appender
+    log4j.appender.sift=org.apache.log4j.sift.MDCSiftingAppender
+    log4j.appender.sift.key=bundle.name
+    log4j.appender.sift.default=karaf
+    log4j.appender.sift.appender=org.apache.log4j.RollingFileAppender
+    log4j.appender.sift.appender.layout=org.apache.log4j.PatternLayout
+    log4j.appender.sift.appender.layout.ConversionPattern=%d{MM/dd-HH:mm:ss.SSS}|%X{RequestId}|%X{ServiceInstanceId}|%t|%X{ServiceName} - %X{bundle.id} - %X{bundle.name} - %X{bundle.version}|%-5.5p|%X{AlertSeverity}|%X{ServerFQDN}|%X{ServerIPAddress}|[%c{3}]|%m%n
+    log4j.appender.sift.appender.file=${karaf.data}/log/eelf/karaf.log
+    log4j.appender.sift.appender.append=true
+
+    log4j.category.org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPusherImpl=DEBUG
+    log4j.category.org.opendaylight.controller.netconf.persist.impl.osgi.ConfigPersisterActivator=DEBUG
+
+
+    #ECOMP Debug appender
+    log4j.appender.debug=org.apache.log4j.RollingFileAppender
+    log4j.appender.debug.key=bundle.name
+    log4j.appender.debug.default=karaf
+
+    log4j.appender.debug.appName=EELFDebug
+    log4j.appender.debug.layout=org.apache.log4j.PatternLayout
+    log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd'T'hh:mm:ss.SSSXXX}|%X{RequestId}|%m%n
+    #log4j.appender.debug.filter.f1=org.apache.log4j.varia.LevelRangeFilter
+    #log4j.appender.debug.filter.f1.LevelMax=WARN
+    #log4j.appender.debug.filter.f1.LevelMin=TRACE
+
+    
+    log4j.appender.debug.file=${karaf.data}/log/APPC/appc-debug.log
+    log4j.appender.debug.append=true
+    log4j.appender.debug.maxFileSize=100MB
+    log4j.appender.debug.maxBackupIndex=10
+
+
+    #Error appender
+    log4j.appender.error=org.apache.log4j.RollingFileAppender
+    log4j.appender.error.appName=EELFError
+    log4j.appender.error.File=${karaf.data}/log/APPC/appc-error.log
+    log4j.appender.error.Threshold=ERROR
+    log4j.appender.error.MaxBackupIndex=1
+    log4j.appender.error.MaxFileSize=100MB
+    log4j.appender.error.layout=org.apache.log4j.PatternLayout
+    log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd'T'hh:mm:ss.SSSXXX}|%X{RequestId}|%t|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%-5.5p|%X{ErrorCode}|%X{ErrorDescription}|%m%n
+
+    #Metrics appender
+    log4j.appender.metric=org.apache.log4j.RollingFileAppender
+    log4j.appender.metric.appName=EELFMetrics
+    log4j.appender.metric.File=${karaf.data}/log/APPC/appc-metric.log
+    log4j.appender.metric.MaxBackupIndex=1
+    log4j.appender.metric.MaxFileSize=100MB
+    log4j.appender.metric.layout=org.apache.log4j.PatternLayout
+    log4j.appender.metric.layout.ConversionPattern=%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%t|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%-5.5p|%X{Severity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ClassName}||%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%m%n
+
+    #Audit appender
+    log4j.appender.audit=org.apache.log4j.RollingFileAppender
+    log4j.appender.audit.appName=EELFAudit
+    log4j.appender.audit.File=${karaf.data}/log/APPC/appc-audit.log
+    log4j.appender.audit.MaxBackupIndex=1
+    log4j.appender.audit.MaxFileSize=100MB
+    log4j.appender.audit.layout=org.apache.log4j.PatternLayout
+    log4j.appender.audit.layout.ConversionPattern=%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%t|%X{ServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%-5.5p|%X{Severity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{ClientIPAddress}|%X{ClassName}||%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}|%m%n
+
+    #Loggers
+
+    #Routing of all messages from root logger
+    log4j.logger.org.openecomp=TRACE, debug, error
+    #Store to the same log file messages from upper level appender or not
+    log4j.additivity.org.openecomp=false
+
+    #org.openecomp logger
+    log4j.logger.org.openecomp=TRACE, debug, error
+    log4j.additivity.org.openecomp=false
+
+    #EELFManager loggers
+    #EELF parent logger
+    log4j.logger.com.att.eelf=TRACE, debug
+    log4j.additivity.com.att.eelf=false
+    #Audit logger routing
+    log4j.logger.com.att.eelf.audit=DEBUG, audit
+    log4j.additivity.com.att.eelf.audit=false     
+    
+    #Metric logger routing
+    log4j.logger.com.att.eelf.metrics=DEBUG, metric
+    log4j.additivity.com.att.eelf.metrics=false
+
+    #Performance logger routing
+    log4j.logger.com.att.eelf.perf=DEBUG, metric
+    log4j.additivity.com.att.eelf.perf=false 
+
+    #Server logger routing
+    log4j.logger.com.att.eelf.server=DEBUG, debug
+    log4j.additivity.com.att.eelf.server=false 
+
+    #Policy logger routing
+    log4j.logger.com.att.eelf.policy=DEBUG, debug
+    log4j.additivity.com.att.eelf.policy=false 
+    #Error logger routing
+    log4j.logger.com.att.eelf.error=DEBUG, error
+    log4j.additivity.com.att.eelf.error=false 
+
+    #Debug logger routing
+    log4j.logger.com.att.eelf.debug=DEBUG, debug
+    log4j.additivity.com.att.eelf.debug=false 
+
diff --git a/appc-core/appc-common-bundle/src/main/resources/org/opendaylight/blueprint/blueprint.xml b/appc-core/appc-common-bundle/src/main/resources/org/opendaylight/blueprint/blueprint.xml
new file mode 100644 (file)
index 0000000..7d8ad17
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  ONAP : APPC
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Copyright (C) 2017 Amdocs
+  =============================================================================
+  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.
+  
+  ECOMP is a trademark and service mark of AT&T Intellectual Property.
+  ============LICENSE_END=========================================================
+  -->
+
+<!--
+    Starter Blueprint Camel Definition appc-common
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+           xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+    <reference id="dbLibServiceRef" interface="org.onap.ccsdk.sli.core.dblib.DbLibService" />
+    <!--reference id="dbLibServiceRef" availability="mandatory" activation="eager" interface="org.onap.ccsdk.sli.core.dblib.DbLibService" /-->
+
+    <bean id="MetadataServiceImplBean" class="org.onap.appc.metadata.impl.MetadataServiceImpl" scope="singleton">
+        <property name="dbLibService" ref="dbLibServiceRef" />
+    </bean>
+
+    <service id="MetadataService" interface="org.onap.appc.metadata.MetadataService" ref="MetadataServiceImplBean"/>
+
+</blueprint>
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/CmdLineTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/CmdLineTest.java
new file mode 100644 (file)
index 0000000..1162d76
--- /dev/null
@@ -0,0 +1,41 @@
+/*-\r
+ * ============LICENSE_START=======================================================\r
+ * ONAP : APPC\r
+ * ================================================================================\r
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+ * =============================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ * ============LICENSE_END=========================================================\r
+ */\r
+\r
+package org.onap.appc;\r
+\r
+import static org.junit.Assert.assertNotNull;\r
+import org.junit.Test;\r
+\r
+public class CmdLineTest {\r
+    @Test\r
+    public void testMain() {\r
+        String argv[];\r
+        argv = new String[] {"encrypt","abc","ghi"};\r
+        CmdLine.main(argv);\r
+        argv = new String[0];\r
+        CmdLine.main(argv);\r
+        argv = new String[] {"encrypt","abc"};\r
+        CmdLine.main(argv);\r
+        \r
+        CmdLine cmdLine = new CmdLine();\r
+        assertNotNull(cmdLine);\r
+    }\r
+}\r
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/ConstantsTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/ConstantsTest.java
new file mode 100644 (file)
index 0000000..47f3e6a
--- /dev/null
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc;
+
+import org.junit.Test;
+
+public class ConstantsTest {
+    @Test (expected = IllegalAccessError.class)
+    public void testConstructor() throws Exception {
+        Constants constants = new Constants();
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/CacheStrategiesTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/CacheStrategiesTest.java
new file mode 100644 (file)
index 0000000..901130e
--- /dev/null
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CacheStrategiesTest {
+    private CacheStrategies cacheStrategies = CacheStrategies.LRU;
+
+    @Test
+    public void testName() throws Exception {
+        Assert.assertEquals("Should have name LRU", "LRU", cacheStrategies.name());
+    }
+
+    @Test
+    public void testToString() throws Exception {
+        Assert.assertEquals("Should return String LRU", "LRU", cacheStrategies.toString());
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        Assert.assertTrue(cacheStrategies.equals(CacheStrategies.LRU));
+        Assert.assertFalse(cacheStrategies.equals(null));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/LRUCacheTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/LRUCacheTest.java
new file mode 100644 (file)
index 0000000..2eca72a
--- /dev/null
@@ -0,0 +1,59 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+
+import java.util.Map;
+
+public class LRUCacheTest {
+
+    @Test
+    public void testConstructor() throws Exception {
+        LRUCache cache = new LRUCache(20);
+        Map internalMap = Whitebox.getInternalState(cache, "map");
+        Assert.assertTrue(internalMap != null);
+        Assert.assertTrue(internalMap.size() == 0);
+    }
+
+    @Test
+    public void testGetAndPutObject() throws Exception {
+        LRUCache cache = new LRUCache(20);
+
+        String key = "testing key";
+        Assert.assertTrue(cache.getObject(key) == null);
+
+        String value = "testing value";
+        cache.putObject(key, value);
+        Map internalMap = Whitebox.getInternalState(cache, "map");
+        Assert.assertTrue(internalMap.containsKey(key));
+        Assert.assertTrue(internalMap.containsValue(value));
+        Assert.assertTrue(internalMap.size() == 1);
+
+        Assert.assertEquals(value, cache.getObject(key));
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheFactoryTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheFactoryTest.java
new file mode 100644 (file)
index 0000000..9f2d1a0
--- /dev/null
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import static org.mockito.Mockito.mock;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.onap.appc.cache.CacheStrategies;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.reflect.Whitebox;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({MetadataCacheFactory.class, MetadataCacheImpl.class})
+public class MetadataCacheFactoryTest {
+    @Test
+    public void testConstructor() throws Exception {
+        Whitebox.invokeConstructor(MetadataCacheFactory.class);
+    }
+
+    @Test
+    public void testGetInstance() throws Exception {
+        Assert.assertTrue("Should not return null", MetadataCacheFactory.getInstance() != null);
+        Assert.assertEquals("Should always return the same object",
+                MetadataCacheFactory.getInstance(), MetadataCacheFactory.getInstance());
+    }
+
+    @Test
+    public void testGetMetadataCacheWithNoArgument() throws Exception {
+        MetadataCacheImpl mockImpl = mock(MetadataCacheImpl.class);
+        PowerMockito.whenNew(MetadataCacheImpl.class).withNoArguments().thenReturn(mockImpl);
+        Assert.assertEquals(mockImpl, MetadataCacheFactory.getInstance().getMetadataCache());
+    }
+
+    @Test
+    public void testGetMetadataCacheWithArgument() throws Exception {
+        CacheStrategies cacheStrategies = CacheStrategies.LRU;
+        MetadataCacheImpl mockImpl = mock(MetadataCacheImpl.class);
+        PowerMockito.whenNew(MetadataCacheImpl.class).withArguments(cacheStrategies)
+                .thenReturn(mockImpl);
+        Assert.assertEquals(mockImpl,
+                MetadataCacheFactory.getInstance().getMetadataCache(cacheStrategies));
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheImplTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/cache/impl/MetadataCacheImplTest.java
new file mode 100644 (file)
index 0000000..f3c6784
--- /dev/null
@@ -0,0 +1,61 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.cache.impl;
+
+import static org.mockito.Mockito.spy;
+import org.junit.Assert;
+import org.junit.Test;
+import org.onap.appc.cache.CacheStrategies;
+import org.powermock.reflect.Whitebox;
+
+public class MetadataCacheImplTest {
+    @Test
+    public void testConstructor() throws Exception {
+        // test without parameter
+        MetadataCacheImpl impl = new MetadataCacheImpl<>();
+        Assert.assertTrue("Should have initialized strategy",
+                Whitebox.getInternalState(impl, "strategy") != null);
+
+        // test with parameter
+        impl = new MetadataCacheImpl<>(CacheStrategies.LRU);
+        Assert.assertTrue("Should have initialized strategy",
+                Whitebox.getInternalState(impl, "strategy") != null);
+
+        impl = new MetadataCacheImpl<>(null);
+        Assert.assertTrue("Should not initialized strategy",
+                Whitebox.getInternalState(impl, "strategy") == null);
+    }
+
+    @Test
+    public void testGetAndPutObject() throws Exception {
+        MetadataCacheImpl impl = spy(new MetadataCacheImpl<>());
+
+        String key = "testing key";
+        Assert.assertTrue(impl.getObject(key) == null);
+
+        String value = "testing value";
+        impl.putObject(key, value);
+        Assert.assertEquals(value, impl.getObject(key));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/concurrent/TestSignal.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/concurrent/TestSignal.java
new file mode 100644 (file)
index 0000000..4b5eadd
--- /dev/null
@@ -0,0 +1,155 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Modification Copyright (C) 2018 IBM
+ * =============================================================================
+ * 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.appc.concurrent;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Test;
+import org.onap.appc.concurrent.Signal;
+
+
+
+public class TestSignal {
+
+    private static final DateFormat formatter = new SimpleDateFormat("HH:mm:ss.SSS");
+    public static final String SIGNAL_READY = "READY";
+    public static final String SIGNAL_SHUTDOWN = "SHUTDOWN";
+
+    @Test
+    public void TestSimpleSignal() throws TimeoutException {
+
+        Signal mySignal = new Signal(Thread.currentThread());
+        mySignal.setTimeout(5000L);
+        Fred fred = new Fred(mySignal);
+        Thread t1 = new Thread(fred);
+
+        /*
+         * Verify that fred is dead, then start him and wait for him to signal us he is ready to proceed
+         */
+        assertFalse(t1.isAlive());
+        t1.start();
+        System.out.println(formatter.format(new Date()) + " MAIN: Waiting for Ready...");
+        mySignal.waitFor(SIGNAL_READY);
+        System.out.println(formatter.format(new Date()) + " MAIN: Signal Ready received");
+
+        /*
+         * Verify that fred is still alive and we will sleep for a while (simulate doing things)
+         */
+        assertTrue(t1.isAlive());
+        try {
+            Thread.sleep(250L);
+        } catch (InterruptedException e) {
+            // ignored
+        }
+
+        /*
+         * Verify that fred is still alive and signal him to shutdown
+         */
+        assertTrue(t1.isAlive());
+        System.out.println(formatter.format(new Date()) + " MAIN: Signaling shutdown");
+        fred.getSignal().signal(SIGNAL_SHUTDOWN);
+
+        /*
+         * Wait a little bit
+         */
+        try {
+            Thread.sleep(250L);
+        } catch (InterruptedException e) {
+            // ignored
+        }
+
+        /*
+         * Verify that fred is dead now and that he completed normally
+         */
+        System.out.println(formatter.format(new Date()) + " MAIN: Shutting down...");
+        assertFalse(t1.isAlive());
+        assertTrue(fred.isCompleted());
+    }
+
+    public class Fred implements Runnable {
+        private Signal signal;
+        private Signal parentSignal;
+        private boolean completed = false;
+
+        public Fred(Signal parentSignal) {
+            this.parentSignal = parentSignal;
+        }
+
+        @Override
+        public void run() {
+            signal = new Signal(Thread.currentThread());
+            signal.setTimeout(5000L);
+            try {
+                Thread.sleep(250L);
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+
+            System.out.println(formatter.format(new Date()) + " FRED: Signaling ready...");
+            parentSignal.signal(SIGNAL_READY);
+
+            try {
+                System.out.println(formatter.format(new Date()) + " FRED: Waiting for shutdown...");
+                signal.waitFor(SIGNAL_SHUTDOWN);
+                System.out.println(formatter.format(new Date()) + " FRED: Received shutdown");
+                completed = true;
+            } catch (TimeoutException e) {
+                
+            }
+        }
+
+        public boolean isCompleted() {
+            return completed;
+        }
+
+        public Signal getSignal() {
+            return signal;
+        }
+    }
+    
+    @Test
+    public void testWaitForAny() throws Exception
+    {
+        Signal mySignal = new Signal(Thread.currentThread());
+        mySignal.setTimeout(50L);
+        String receivedSignal= mySignal.waitForAny(SIGNAL_READY);
+        assertEquals("READY", receivedSignal);
+    }
+    
+    @Test(expected=TimeoutException.class)
+    public void testWaitForAnyForEmptySignal() throws TimeoutException
+    {
+        Signal mySignal = new Signal(Thread.currentThread());
+        mySignal.setTimeout(50L);
+        mySignal.waitForAny();
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/ConfigurationFactoryTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/ConfigurationFactoryTest.java
new file mode 100644 (file)
index 0000000..7d02064
--- /dev/null
@@ -0,0 +1,15 @@
+package org.onap.appc.configuration;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.onap.appc.configuration.ConfigurationFactory.getConfiguration;
+
+public class ConfigurationFactoryTest {
+    @Test
+    public void should_returnDefaultConfiguration(){
+        Configuration conf = null;
+
+        Assert.assertTrue(getConfiguration() instanceof DefaultConfiguration);
+    }
+}
\ No newline at end of file
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/DefaultConfigurationTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/configuration/DefaultConfigurationTest.java
new file mode 100644 (file)
index 0000000..aed4141
--- /dev/null
@@ -0,0 +1,347 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Modification Copyright (C) 2018 IBM.
+ * =============================================================================
+ * 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.appc.configuration;
+
+import static org.mockito.Mockito.mock;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.powermock.reflect.Whitebox;
+
+public class DefaultConfigurationTest {
+    private static final String propKey1 = "testKey1";
+    private static final String propKey2 = "testKey2";
+    private static final String propValue1 = "testValue1";
+    private static final String propValue2 = "testValue2";
+
+    private Properties prop = new Properties();
+    private DefaultConfiguration defaultConfiguration;
+
+    @Before
+    public void setUp() throws Exception {
+        prop.setProperty(propKey1, propValue1);
+        prop.setProperty(propKey2, propValue2);
+
+        defaultConfiguration = new DefaultConfiguration();
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        Whitebox.setInternalState(defaultConfiguration, "properties", prop);
+        defaultConfiguration.clear();
+        Properties internalProp = Whitebox.getInternalState(defaultConfiguration, "properties");
+        Assert.assertTrue("internal properties should be cleared", internalProp.isEmpty());
+    }
+
+    @Test
+    public void testClone() throws Exception {
+        Object clonedObject = defaultConfiguration.clone();
+        Assert.assertTrue("Should be DefaultConfiguration",
+                clonedObject instanceof DefaultConfiguration);
+        Properties internalProp = Whitebox.getInternalState(defaultConfiguration, "properties");
+        Properties clonedInternalProp = Whitebox.getInternalState(clonedObject, "properties");
+        Assert.assertEquals(internalProp, clonedInternalProp);
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        // test compare with null
+        Assert.assertFalse(defaultConfiguration.equals(null));
+        // test with non-DefaultConfiguration object
+        Assert.assertFalse(defaultConfiguration.equals("abc"));
+
+        // test with not match DefaultConfiguration object
+        defaultConfiguration.setProperties(prop);
+        DefaultConfiguration newConfig = new DefaultConfiguration();
+        Assert.assertFalse(defaultConfiguration.equals(newConfig));
+
+        // test with matching DefaultConfiguration object
+        newConfig.setProperties(prop);
+        Assert.assertTrue(defaultConfiguration.equals(newConfig));
+    }
+
+    @Test
+    public void testSetPropAndGetBooleanProperty() throws Exception {
+        String booleanKey = "booleanKey";
+        // test default value
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey));
+        // test match value true
+        defaultConfiguration.setProperty(booleanKey, "true");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey));
+        defaultConfiguration.setProperty(booleanKey, "True");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey));
+        defaultConfiguration.setProperty(booleanKey, "TrUe");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey));
+        // test not matching true values
+        defaultConfiguration.setProperty(booleanKey, "false");
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey));
+        defaultConfiguration.setProperty(booleanKey, "abc");
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey));
+    }
+    
+    @Test
+    public void testSetPropAndGetBooleanPropertyForEncryptedValue()
+    {
+        String booleanKey = "booleanKey";
+        defaultConfiguration.setProperty(booleanKey, "enc:true");
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey));
+    }
+    
+   
+    @Test
+    public void testSetPropAndGetBooleanPropertyWithDefaultValue() throws Exception {
+        String booleanKey = "booleanKey";
+        // test default value
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey, false));
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey, true));
+        // test match value true
+        defaultConfiguration.setProperty(booleanKey, "true");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey, false));
+        defaultConfiguration.setProperty(booleanKey, "True");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey, false));
+        defaultConfiguration.setProperty(booleanKey, "TrUe");
+        Assert.assertTrue(defaultConfiguration.getBooleanProperty(booleanKey, false));
+        // test not matching true values
+        defaultConfiguration.setProperty(booleanKey, "false");
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey, true));
+        defaultConfiguration.setProperty(booleanKey, "abc");
+        Assert.assertFalse(defaultConfiguration.getBooleanProperty(booleanKey, true));
+    }
+
+    @Test
+    public void testSetPropAndGetDoubleProperty() throws Exception {
+        String doubleKey = "doubleKey";
+        // test default value
+        Assert.assertTrue(0.0 == defaultConfiguration.getDoubleProperty(doubleKey));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(doubleKey, "abc");
+        Assert.assertTrue(0.0 == defaultConfiguration.getDoubleProperty(doubleKey));
+        // test normal
+        defaultConfiguration.setProperty(doubleKey, "1.1");
+        Assert.assertTrue(1.1 == defaultConfiguration.getDoubleProperty(doubleKey));
+    }
+
+    @Test
+    public void testSetPropAndGetDoublePropertyWithDefaultValue() throws Exception {
+        String doubleKey = "doubleKey";
+        // test default value
+        Assert.assertTrue(2.2 == defaultConfiguration.getDoubleProperty(doubleKey, 2.2));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(doubleKey, "abc");
+        Assert.assertTrue(0.0 == defaultConfiguration.getDoubleProperty(doubleKey, 2.2));
+        // test normal
+        defaultConfiguration.setProperty(doubleKey, "1.1");
+        Assert.assertTrue(1.1 == defaultConfiguration.getDoubleProperty(doubleKey, 2.2));
+    }
+
+    @Test
+    public void testSetPropAndGetIntegerProperty() throws Exception {
+        String integerKey = "integerKey";
+        // test default value
+        Assert.assertTrue(0 == defaultConfiguration.getIntegerProperty(integerKey));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(integerKey, "abc");
+        Assert.assertTrue(0 == defaultConfiguration.getIntegerProperty(integerKey));
+        // test normal
+        defaultConfiguration.setProperty(integerKey, "100");
+        Assert.assertTrue(100 == defaultConfiguration.getIntegerProperty(integerKey));
+    }
+
+    @Test
+    public void testSetPropAndGetIntegerPropertyWithDefaultValue() throws Exception {
+        String integerKey = "integerKey";
+        // test default value
+        Assert.assertTrue(100 == defaultConfiguration.getIntegerProperty(integerKey, 100));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(integerKey, "abc");
+        Assert.assertTrue(0 == defaultConfiguration.getIntegerProperty(integerKey, 100));
+        // test normal
+        defaultConfiguration.setProperty(integerKey, "100");
+        Assert.assertTrue(100 == defaultConfiguration.getIntegerProperty(integerKey, 10));
+    }
+
+    @Test
+    public void testSetPropAndGetLongProperty() throws Exception {
+        String longKey = "longKey";
+        // test default value
+        Assert.assertTrue(0 == defaultConfiguration.getLongProperty(longKey));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(longKey, "abc");
+        Assert.assertTrue(0 == defaultConfiguration.getLongProperty(longKey));
+        // test normal
+        defaultConfiguration.setProperty(longKey, "100");
+        Assert.assertTrue(100 == defaultConfiguration.getLongProperty(longKey));
+    }
+
+    @Test
+    public void testSetPropAndGetLongPropertyWithDefaultVaue() throws Exception {
+        String longKey = "longKey";
+        // test default value
+        Assert.assertTrue(10 == defaultConfiguration.getLongProperty(longKey, 10));
+        // test NumberFormatException
+        defaultConfiguration.setProperty(longKey, "abc");
+        Assert.assertTrue(0 == defaultConfiguration.getLongProperty(longKey, 10));
+        // test normal
+        defaultConfiguration.setProperty(longKey, "100");
+        Assert.assertTrue(100 == defaultConfiguration.getLongProperty(longKey, 10));
+    }
+
+    @Test
+    public void testSetAndGetProperties() throws Exception {
+        Properties internalProp = Whitebox.getInternalState(defaultConfiguration, "properties");
+        Assert.assertEquals(internalProp, defaultConfiguration.getProperties());
+
+        defaultConfiguration.setProperties(prop);
+        internalProp = Whitebox.getInternalState(defaultConfiguration, "properties");
+        Assert.assertEquals(internalProp, defaultConfiguration.getProperties());
+    }
+
+    @Test
+    public void testSetAndGetProperty() throws Exception {
+        String key = "key";
+        // test default value
+        Assert.assertTrue(null == defaultConfiguration.getProperty(key));
+        // test normal
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertEquals("abc", defaultConfiguration.getProperty(key));
+    }
+
+    @Test
+    public void testSetPropAndGetPropertyWithDefaultValue() throws Exception {
+        String key = "key";
+        // test default value
+        Assert.assertTrue(null == defaultConfiguration.getProperty(key, null));
+        Assert.assertEquals("abc", defaultConfiguration.getProperty(key, "abc"));
+        // test normal
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertEquals("abc", defaultConfiguration.getProperty(key, "abcd"));
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        Properties properties = null;
+        Whitebox.setInternalState(defaultConfiguration, "properties", properties);
+        Assert.assertEquals(0, defaultConfiguration.hashCode());
+
+
+        Whitebox.setInternalState(defaultConfiguration, "properties", prop);
+        Assert.assertEquals(prop.hashCode(), defaultConfiguration.hashCode());
+    }
+
+    @Test
+    public void testIsPropertyDefined() throws Exception {
+        String key = "key";
+        // test not exist
+        Assert.assertFalse(defaultConfiguration.isPropertyDefined(key));
+        // test exist
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertTrue(defaultConfiguration.isPropertyDefined(key));
+    }
+
+    @Test
+    public void testIsValidBoolean() throws Exception {
+        String key = "key";
+        // test not exist
+        Assert.assertFalse(defaultConfiguration.isValidBoolean(key));
+        // test exist with invalid
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertFalse(defaultConfiguration.isValidBoolean(key));
+        // test exist with valid
+        defaultConfiguration.setProperty(key, "True");
+        Assert.assertTrue(defaultConfiguration.isPropertyDefined(key));
+        defaultConfiguration.setProperty(key, "FaLse");
+        Assert.assertTrue(defaultConfiguration.isPropertyDefined(key));
+    }
+
+    @Test
+    public void testIsValidDouble() throws Exception {
+        String key = "key";
+        // test not exist
+        Assert.assertFalse(defaultConfiguration.isValidDouble(key));
+        // test exist with invalid
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertFalse(defaultConfiguration.isValidDouble(key));
+        // test exist with valid
+        defaultConfiguration.setProperty(key, "2");
+        Assert.assertTrue(defaultConfiguration.isValidDouble(key));
+        defaultConfiguration.setProperty(key, "3.45");
+        Assert.assertTrue(defaultConfiguration.isValidDouble(key));
+    }
+
+    @Test
+    public void testIsValidInteger() throws Exception {
+        String key = "key";
+        // test not exist
+        Assert.assertFalse(defaultConfiguration.isValidInteger(key));
+        // test exist with invalid
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertFalse(defaultConfiguration.isValidInteger(key));
+        defaultConfiguration.setProperty(key, "3.45");
+        Assert.assertFalse(defaultConfiguration.isValidInteger(key));
+        // test exist with valid
+        defaultConfiguration.setProperty(key, "2");
+        Assert.assertTrue(defaultConfiguration.isValidInteger(key));
+    }
+
+    @Test
+    public void testIsValidLong() throws Exception {
+        String key = "key";
+        // test not exist
+        Assert.assertFalse(defaultConfiguration.isValidLong(key));
+        // test exist with invalid
+        defaultConfiguration.setProperty(key, "abc");
+        Assert.assertFalse(defaultConfiguration.isValidLong(key));
+        defaultConfiguration.setProperty(key, "3.45");
+        Assert.assertFalse(defaultConfiguration.isValidLong(key));
+        // test exist with valid
+        defaultConfiguration.setProperty(key, "2");
+        Assert.assertTrue(defaultConfiguration.isValidLong(key));
+    }
+
+    @Test
+    public void testSetPropertiesWithInputStream() throws Exception {
+        InputStream mockIS = mock(InputStream.class);
+        defaultConfiguration.setProperties(mockIS);
+
+        Properties mockProp = mock(Properties.class);
+        Mockito.doThrow(new IOException("testing exception")).when(mockProp).load(mockIS);
+        Whitebox.setInternalState(defaultConfiguration, "properties", mockProp);
+        defaultConfiguration.setProperties(mockIS);
+        // Should come here without exception
+    }
+
+    @Test
+    public void testToString() throws Exception {
+        Properties internalProp = Whitebox.getInternalState(defaultConfiguration, "properties");
+        Assert.assertEquals(String.format("Configuration: %d properties, keys:[%s]",
+                internalProp.size(), internalProp.keySet().toString()),
+                defaultConfiguration.toString());
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/EncryptionToolTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/EncryptionToolTest.java
new file mode 100644 (file)
index 0000000..ae6de6d
--- /dev/null
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.encryption;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class EncryptionToolTest {
+
+    private static final String PLAIN_TEXT = "text to encrypt";
+    private static final String EMPTY_STR = "";
+
+    private EncryptionTool encryptionTool = EncryptionTool.getInstance();
+
+    @Test
+    public void should_return_prefix_given_empty_string() {
+        assertEquals("enc:", encryptionTool.encrypt(EMPTY_STR));
+    }
+
+    @Test
+    public void should_return_null_given_null() {
+        assertNull(encryptionTool.encrypt(null));
+    }
+
+    @Test
+    public void should_encrypt_given_string() {
+        String encrypted = encryptionTool.encrypt(PLAIN_TEXT);
+
+        assertNotEquals(encrypted, PLAIN_TEXT);
+        assertTrue(encrypted.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX));
+    }
+
+    @Test
+    public void should_not_decrypt_string_when_not_starting_with_prefix() {
+
+        assertNull(encryptionTool.decrypt(null));
+        assertEquals("mdi/12!dsao91", encryptionTool.decrypt("mdi/12!dsao91"));
+    }
+
+    @Test
+    public void should_decrypt_given_encrypted_string() {
+        String encrypted = encryptionTool.encrypt(PLAIN_TEXT);
+
+        assertEquals(PLAIN_TEXT, encryptionTool.decrypt(encrypted));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/HexHelperTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/encryption/HexHelperTest.java
new file mode 100644 (file)
index 0000000..3af421a
--- /dev/null
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2018 Nokia Solutions and Networks
+ * =============================================================================
+ * 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.appc.encryption;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import org.junit.Test;
+
+public class HexHelperTest {
+
+    private final List<Character> hexChars =
+        newArrayList('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B','C', 'D', 'E', 'F');
+
+    @Test(expected = EncryptionException.class)
+    public void convertHexToBytes_should_throw_given_null() throws EncryptionException {
+
+        HexHelper.convertHexToBytes(null);
+    }
+
+    @Test(expected = EncryptionException.class)
+    public void convertHexToBytes_should_throw_given_non_hexadecimal_string() throws EncryptionException {
+
+        HexHelper.convertHexToBytes("125FET4A");
+    }
+
+    @Test
+    public void convertHexToBytes_should_convert_hexadecimal_string_to_byte_array() throws EncryptionException {
+
+        byte[] result = HexHelper.convertHexToBytes("125FE4A");
+
+        assertNotEquals(0, result.length);
+    }
+
+
+    @Test(expected = EncryptionException.class)
+    public void convertBytesToHex_should_throw_given_null() throws EncryptionException {
+
+        HexHelper.convertBytesToHex(null);
+    }
+
+
+    @Test
+    public void convertBytesToHex_should_convert_byte_array_to_hexadecimal_string() throws EncryptionException {
+
+        String resultString = HexHelper.convertBytesToHex(new byte[]{24, -1, 85, 99});
+        for (char ch : resultString.toCharArray()) {
+            assertTrue(hexChars.contains(ch));
+        }
+
+        byte[] resultArray = HexHelper.convertHexToBytes("A56C9ED17");
+        assertEquals("0A56C9ED17", HexHelper.convertBytesToHex(resultArray));
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/APPCExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/APPCExceptionTest.java
new file mode 100644 (file)
index 0000000..f79be0e
--- /dev/null
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+
+
+public class APPCExceptionTest {
+
+    @Test
+    public void testConstructorNoArgument() throws Exception {
+        APPCException appcException = new APPCException();
+        Assert.assertTrue(appcException.getCause() == null);
+        Assert.assertTrue(appcException.getLocalizedMessage() == null);
+        Assert.assertTrue(appcException.getMessage() == null);
+    }
+
+    @Test
+    public void testConstructorWithMessaqge() throws Exception {
+        String message = "testing message";
+        APPCException appcException = new APPCException(message);
+        Assert.assertTrue(appcException.getCause() == null);
+        Assert.assertEquals(message, appcException.getLocalizedMessage());
+        Assert.assertEquals(message, appcException.getMessage());
+    }
+
+    @Test
+    public void testConstructorWithThrowable() throws Exception {
+        String message = "testing message";
+        Throwable throwable = new Throwable(message);
+        APPCException appcException = new APPCException(throwable);
+        Assert.assertEquals(throwable, appcException.getCause());
+        Assert.assertTrue(appcException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(appcException.getMessage().contains(message));
+    }
+
+    @Test
+    public void testConstructorWithMessageAndThrowable() throws Exception {
+        String message = "testing message";
+        String tMessage = "throwable message";
+        Throwable throwable = new Throwable(tMessage);
+        APPCException appcException = new APPCException(message, throwable);
+        Assert.assertEquals(throwable, appcException.getCause());
+        Assert.assertTrue(appcException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(appcException.getMessage().contains(message));
+    }
+
+    @Test
+    public void testConstructorWithFourArguments() throws Exception {
+        String message = "testing message";
+        String tMessage = "throwable message";
+        Throwable throwable = new Throwable(tMessage);
+        APPCException appcException = new APPCException(message, throwable, true, true);
+        Assert.assertEquals(throwable, appcException.getCause());
+        Assert.assertTrue(appcException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(appcException.getMessage().contains(message));
+
+        Assert.assertTrue(Whitebox.getInternalState(appcException, "stackTrace") != null);
+        Assert.assertTrue(Whitebox.getInternalState(appcException, "suppressedExceptions") != null);
+
+        appcException = new APPCException(message, throwable, false, false);
+        Assert.assertTrue(Whitebox.getInternalState(appcException, "stackTrace") == null);
+        Assert.assertTrue(Whitebox.getInternalState(appcException, "suppressedExceptions") == null);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidInputExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidInputExceptionTest.java
new file mode 100644 (file)
index 0000000..4e30ed5
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class InvalidInputExceptionTest {
+    @Test
+    public void testConstructor() throws Exception {
+        String message = "testing message";
+        InvalidInputException invalidInputException = new InvalidInputException(message);
+        Assert.assertTrue(invalidInputException.getCause() == null);
+        Assert.assertEquals(message, invalidInputException.getLocalizedMessage());
+        Assert.assertEquals(message, invalidInputException.getMessage());
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidStateExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/InvalidStateExceptionTest.java
new file mode 100644 (file)
index 0000000..21374da
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class InvalidStateExceptionTest {
+    @Test
+    public void testConstructor() throws Exception {
+        String message = "testing message";
+        InvalidStateException invalidStateException = new InvalidStateException(message);
+        Assert.assertTrue(invalidStateException.getCause() == null);
+        Assert.assertEquals(message, invalidStateException.getLocalizedMessage());
+        Assert.assertEquals(message, invalidStateException.getMessage());
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/UnknownProviderExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/exceptions/UnknownProviderExceptionTest.java
new file mode 100644 (file)
index 0000000..c969c0c
--- /dev/null
@@ -0,0 +1,94 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.exceptions;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+
+public class UnknownProviderExceptionTest {
+
+    @Test
+    public void testConstructorNoArgument() throws Exception {
+        UnknownProviderException unknownProviderException = new UnknownProviderException();
+        Assert.assertTrue(unknownProviderException.getCause() == null);
+        Assert.assertTrue(unknownProviderException.getLocalizedMessage() == null);
+        Assert.assertTrue(unknownProviderException.getMessage() == null);
+    }
+
+    @Test
+    public void testConstructorWithMessaqge() throws Exception {
+        String message = "testing message";
+        UnknownProviderException unknownProviderException = new UnknownProviderException(message);
+        Assert.assertTrue(unknownProviderException.getCause() == null);
+        Assert.assertEquals(message, unknownProviderException.getLocalizedMessage());
+        Assert.assertEquals(message, unknownProviderException.getMessage());
+    }
+
+    @Test
+    public void testConstructorWithThrowable() throws Exception {
+        String message = "testing message";
+        Throwable throwable = new Throwable(message);
+        UnknownProviderException unknownProviderException = new UnknownProviderException(throwable);
+        Assert.assertEquals(throwable, unknownProviderException.getCause());
+        Assert.assertTrue(unknownProviderException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(unknownProviderException.getMessage().contains(message));
+    }
+
+    @Test
+    public void testConstructorWithMessageAndThrowable() throws Exception {
+        String message = "testing message";
+        String tMessage = "throwable message";
+        Throwable throwable = new Throwable(tMessage);
+        UnknownProviderException unknownProviderException =
+                new UnknownProviderException(message, throwable);
+        Assert.assertEquals(throwable, unknownProviderException.getCause());
+        Assert.assertTrue(unknownProviderException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(unknownProviderException.getMessage().contains(message));
+    }
+
+    @Test
+    public void testConstructorWithFourArguements() throws Exception {
+        String message = "testing message";
+        String tMessage = "throwable message";
+        Throwable throwable = new Throwable(tMessage);
+        UnknownProviderException unknownProviderException =
+                new UnknownProviderException(message, throwable, true, true);
+        Assert.assertEquals(throwable, unknownProviderException.getCause());
+        Assert.assertTrue(unknownProviderException.getLocalizedMessage().contains(message));
+        Assert.assertTrue(unknownProviderException.getMessage().contains(message));
+
+        Assert.assertTrue(
+                Whitebox.getInternalState(unknownProviderException, "stackTrace") != null);
+        Assert.assertTrue(Whitebox.getInternalState(unknownProviderException,
+                "suppressedExceptions") != null);
+
+        unknownProviderException = new UnknownProviderException(message, throwable, false, false);
+        Assert.assertTrue(
+                Whitebox.getInternalState(unknownProviderException, "stackTrace") == null);
+        Assert.assertTrue(Whitebox.getInternalState(unknownProviderException,
+                "suppressedExceptions") == null);
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/i18n/MsgTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/i18n/MsgTest.java
new file mode 100644 (file)
index 0000000..5fbcac1
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.i18n;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MsgTest {
+    @Test
+    public void testNameAndToString() throws Exception {
+        for (Msg msg : Msg.values()) {
+            Assert.assertEquals(msg.name(), msg.toString());
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingConstantsTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingConstantsTest.java
new file mode 100644 (file)
index 0000000..b2519fe
--- /dev/null
@@ -0,0 +1,59 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.logging;
+
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+
+public class LoggingConstantsTest {
+    @Test (expected = IllegalAccessError.class)
+    public void testConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.class);
+    }
+
+    @Test (expected = IllegalAccessError.class)
+    public void testMdcKeysConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.MDCKeys.class);
+    }
+
+    @Test (expected = IllegalAccessError.class)
+    public void testStatusCodesConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.StatusCodes.class);
+    }
+
+    @Test (expected = IllegalAccessError.class)
+    public void testTargetNamesConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.TargetNames.class);
+    }
+
+    @Test (expected = IllegalAccessError.class)
+    public void testTargetServiceNamesConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.TargetServiceNames.class);
+    }
+
+    @Test (expected = IllegalAccessError.class)
+    public void testAAIServiceNamesConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingConstants.TargetServiceNames.AAIServiceNames.class);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingUtilsTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/logging/LoggingUtilsTest.java
new file mode 100644 (file)
index 0000000..cc72160
--- /dev/null
@@ -0,0 +1,357 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2018 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.appc.logging;
+
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+import org.slf4j.MDC;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import java.lang.Class;
+import java.lang.reflect.Method;
+import java.time.Instant;
+
+public class LoggingUtilsTest {
+    @Test(expected = IllegalAccessError.class)
+    public void testConstructor() throws Exception {
+        Whitebox.invokeConstructor(LoggingUtils.class);
+    }
+
+    @Test
+    public void testLogErrorMessageStringStringStringStringStringString() {
+        try {
+            LoggingUtils.logErrorMessage("ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking logErrorMessage: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testLogErrorMessageStringStringStringString() {
+        try {
+            LoggingUtils.logErrorMessage("TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking logErrorMessage: " + e.toString());
+        }
+        }
+
+    @Test
+    public void testLogErrorMessageStringStringString() {
+        try {
+            LoggingUtils.logErrorMessage("TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking logErrorMessage: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testLogError() {
+        try {
+            Class<?>[] paramString = { String.class, String.class, String.class, String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("logError", paramString);
+            m.setAccessible(true);
+            m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking logError: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testLogAuditMessage() {
+        try {
+            Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("logAuditMessage", paramString);
+            m.setAccessible(true);
+            java.util.Date timestamp = new java.util.Date();
+            m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking logAuditMessage: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testAuditInfo() {
+        try {
+            EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+            auditLogger.info("Audit logging test info");
+        } catch (Exception e) {
+            fail("Exception invoking testAuditInfo: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testAuditWarn() {
+        try {
+            EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+            auditLogger.warn("Audit logging test warning");
+        } catch (Exception e) {
+            fail("Exception invoking testAuditWarn: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testLogMetricsMessage() {
+        try {
+            java.util.Date timestamp = new java.util.Date();
+            LoggingUtils.logMetricsMessage(timestamp.toInstant(), timestamp.toInstant(), "TARGET_ENTITY", "TARGET_SERVICE_NAME", "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME");
+            assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+
+        } catch (Exception e) {
+            fail("Exception invoking logMetricsMessage: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateAuditLogContext() {
+        try {
+            Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateAuditLogContext", paramString);
+            m.setAccessible(true);
+            java.util.Date timestamp = new java.util.Date();
+            m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "100", "RESPONSE_DESCRIPTION", "CLASS_NAME");
+            assertEquals("COMPLETE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+            assertEquals("100", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE));
+            assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking populateAuditLogContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanAuditErrorContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanAuditErrorContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, "STATUS_CODE");
+            MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, "RESPONSE_CODE");
+            MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION, "RESPONSE_DESCRIPTION");
+            MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking cleanAuditErrorLogContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateErrorLogContext() {
+        try {
+            Class<?>[] paramString = { String.class, String.class, String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateErrorLogContext", paramString);
+            m.setAccessible(true);
+            m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICENAME", "CLASS_NAME");
+            assertEquals("CLASS_NAME", MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking populateErrorLogContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanErrorLogContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanErrorLogContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking cleanErrorLogContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateMetricLogContext() {
+        try {
+            Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class,
+                    String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateMetricLogContext", paramString);
+            m.setAccessible(true);
+            java.util.Date timestamp = new java.util.Date();
+            m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "TARGET_ENTITY", "TARGET_SERVICE_NAME", "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME");
+            assertEquals("STATUS_CODE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+            assertEquals("RESPONSE_CODE", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE));
+            assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking populateMetricLogContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanMetricContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanMetricContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking cleanMetricContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateTargetContext() {
+        try {
+            Class<?>[] paramString = { String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateTargetContext", paramString);
+            m.setAccessible(true);
+            m.invoke(null, "TARGET_ENTITY", "TARGET_SERVICE_NAME");
+            assertEquals("TARGET_ENTITY", MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY));
+            assertEquals("TARGET_SERVICE_NAME", MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking populateTargetContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanTargetContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanTargetContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, "TARGET_ENTITY");
+            MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME, "TARGET_SERVICE_NAME");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME));
+        } catch (Exception e) {
+            fail("Exception invoking cleanTargetContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateTimeContext() {
+        try {
+            Class<?>[] paramString = { Instant.class, Instant.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateTimeContext", paramString);
+            m.setAccessible(true);
+            java.util.Date timestamp = new java.util.Date();
+            m.invoke(null, timestamp.toInstant(), timestamp.toInstant());
+        } catch (Exception e) {
+            fail("Exception invoking populateTimeContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testGenerateTimestampStr() {
+        try {
+            Class<?>[] paramString = { Instant.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("generateTimestampStr", paramString);
+            m.setAccessible(true);
+            java.util.Date timestamp = new java.util.Date();
+            assertNotNull((String) m.invoke(null, timestamp.toInstant()));
+        } catch (Exception e) {
+            fail("Exception invoking testGenerateTimestampStr: " + e.toString());
+        }
+
+    }
+
+    @Test
+    public void testCleanTimeContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanTimeContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, "BEGIN_TIMESTAMP");
+            MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, "END_TIMESTAMP");
+            MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, "ELAPSED_TIME");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.END_TIMESTAMP));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.ELAPSED_TIME));
+        } catch (Exception e) {
+            fail("Exception invoking cleanErrorContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateResponseContext() {
+        try {
+            Class<?>[] paramString = { String.class, String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateResponseContext", paramString);
+            m.setAccessible(true);
+            m.invoke(null, "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION");
+            assertEquals("STATUS_CODE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+            assertEquals("RESPONSE_CODE", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE));
+            assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking populateResponseContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanResponseContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanResponseContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, "STATUS_CODE");
+            MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, "RESPONSE_CODE");
+            MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION, "RESPONSE_DESCRIPTION");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking cleanErrorContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testPopulateErrorContext() {
+        try {
+            Class<?>[] paramString = { String.class, String.class };
+            Method m = LoggingUtils.class.getDeclaredMethod("populateErrorContext", paramString);
+            m.setAccessible(true);
+            m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION");
+            assertEquals("ERROR_CODE", MDC.get(LoggingConstants.MDCKeys.ERROR_CODE));
+            assertEquals("ERROR_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.ERROR_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking populateErrorContext: " + e.toString());
+        }
+    }
+
+    @Test
+    public void testCleanErrorContext() {
+        try {
+            Method m = LoggingUtils.class.getDeclaredMethod("cleanErrorContext");
+            m.setAccessible(true);
+            MDC.put(LoggingConstants.MDCKeys.ERROR_CODE, "ERROR_CODE");
+            MDC.put(LoggingConstants.MDCKeys.ERROR_DESCRIPTION, "ERROR_DESCRIPTION");
+            m.invoke(null);
+            assertNull(MDC.get(LoggingConstants.MDCKeys.ERROR_CODE));
+            assertNull(MDC.get(LoggingConstants.MDCKeys.ERROR_DESCRIPTION));
+        } catch (Exception e) {
+            fail("Exception invoking cleanErrorContext: " + e.toString());
+        }
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/impl/MetadataServiceImplTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/impl/MetadataServiceImplTest.java
new file mode 100644 (file)
index 0000000..90ad524
--- /dev/null
@@ -0,0 +1,137 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2018 Nokia Solutions and Networks
+ * =============================================================================
+ * 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.appc.metadata.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import javax.sql.rowset.CachedRowSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.appc.cache.MetadataCache;
+import org.onap.appc.metadata.objects.DependencyModelIdentifier;
+import org.onap.ccsdk.sli.core.dblib.DbLibService;
+
+public class MetadataServiceImplTest {
+
+
+    private MetadataServiceImpl metadataService = new MetadataServiceImpl();
+    private DbLibService mockDbLibService = mock(DbLibService.class);
+    private CachedRowSet mockCachedRowSet = mock(CachedRowSet.class);
+    private MetadataCache<DependencyModelIdentifier, String> mockCache = mock(MetadataCache.class);
+    private DependencyModelIdentifier mockModelIdentifier = mock(DependencyModelIdentifier.class);
+
+    @Before
+    public void setup() throws SQLException {
+        metadataService.setDbLibService(mockDbLibService);
+        metadataService.setCache(mockCache);
+    }
+
+    @Test
+    public void getVnfModel_should_return_vnfModel_when_present_in_cache() throws SQLException {
+        when(mockCache.getObject(mockModelIdentifier)).thenReturn("test-vnf-model");
+
+        assertEquals("test-vnf-model", metadataService.getVnfModel(mockModelIdentifier));
+
+        verify(mockCache).getObject(mockModelIdentifier);
+        verify(mockDbLibService, never()).getData(anyString(), any(ArrayList.class), anyString());
+        verify(mockCache, never()).putObject(any(DependencyModelIdentifier.class), anyString());
+    }
+
+    @Test
+    public void getVnfModel_should_read_from_database_when_null_vnfName_and_return_when_found()
+        throws SQLException {
+
+        when(mockCache.getObject(any(DependencyModelIdentifier.class))).thenReturn(null);
+        when(mockModelIdentifier.getCatalogVersion()).thenReturn("test-vnf-catalog-version");
+        when(mockDbLibService.getData(anyString(), any(ArrayList.class), anyString())).thenReturn(mockCachedRowSet);
+        when(mockCachedRowSet.first()).thenReturn(true);
+        when(mockCachedRowSet.getString("ARTIFACT_CONTENT")).thenReturn("test-vnf-model");
+
+        assertEquals("test-vnf-model", metadataService.getVnfModel(mockModelIdentifier));
+
+        verify(mockDbLibService).getData(anyString(), any(ArrayList.class), anyString());
+        verify(mockCachedRowSet).getString("ARTIFACT_CONTENT");
+        verify(mockCache).putObject(mockModelIdentifier, "test-vnf-model");
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void getVnfModel_should_read_from_database_when_null_vnfName_and_throw_when_invalid_dependency_model()
+        throws SQLException {
+
+        when(mockCache.getObject(any(DependencyModelIdentifier.class))).thenReturn(null);
+        when(mockModelIdentifier.getCatalogVersion()).thenReturn(null);
+
+        when(mockDbLibService.getData(anyString(), any(ArrayList.class), anyString())).thenReturn(mockCachedRowSet);
+        when(mockCachedRowSet.first()).thenReturn(true);
+        when(mockCachedRowSet.getString("ARTIFACT_CONTENT")).thenReturn(null);
+
+        assertEquals(null, metadataService.getVnfModel(mockModelIdentifier));
+
+        verify(mockDbLibService).getData(anyString(), any(ArrayList.class), anyString());
+        verify(mockCachedRowSet).getString("ARTIFACT_CONTENT");
+        verify(mockCache, never()).putObject(mockModelIdentifier, "test-vnf-model");
+
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void getVnfModel_should_read_from_database_when_null_vnfName_and_throw_when_database_error()
+        throws SQLException {
+
+        when(mockCache.getObject(any(DependencyModelIdentifier.class))).thenReturn(null);
+        when(mockModelIdentifier.getCatalogVersion()).thenReturn(null);
+        when(mockDbLibService.getData(anyString(), any(ArrayList.class), anyString())).thenThrow(new SQLException());
+
+        assertEquals(null, metadataService.getVnfModel(mockModelIdentifier));
+
+        verify(mockDbLibService).getData(anyString(), any(ArrayList.class), anyString());
+        verify(mockCachedRowSet, times(0)).getString("ARTIFACT_CONTENT");
+        verify(mockCache, never()).putObject(any(DependencyModelIdentifier.class), anyString());
+    }
+
+
+    @Test
+    public void getVnfModel_should_read_from_database_when_null_vnfName_and_return_null_when_not_found()
+        throws SQLException {
+
+        when(mockCache.getObject(any(DependencyModelIdentifier.class))).thenReturn(null);
+        when(mockModelIdentifier.getCatalogVersion()).thenReturn(null);
+        when(mockDbLibService.getData(anyString(), any(ArrayList.class), anyString())).thenReturn(mockCachedRowSet);
+        when(mockCachedRowSet.first()).thenReturn(false);
+
+        assertEquals(null, metadataService.getVnfModel(mockModelIdentifier));
+
+        verify(mockDbLibService).getData(anyString(), any(ArrayList.class), anyString());
+        verify(mockCachedRowSet, times(0)).getString("ARTIFACT_CONTENT");
+        verify(mockCache, never()).putObject(any(DependencyModelIdentifier.class), anyString());
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/objects/DependencyModelIdentifierTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/metadata/objects/DependencyModelIdentifierTest.java
new file mode 100644 (file)
index 0000000..f9aae99
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.metadata.objects;
+
+import static org.onap.appc.metadata.objects.DependencyModelIdentifier.prime;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.powermock.reflect.Whitebox;
+
+public class DependencyModelIdentifierTest {
+    private static final String vnfType = "vnfType";
+    private static final String vnfType2 = "vnfType2";
+    private static final String cVersion = "catalogVersion";
+    private DependencyModelIdentifier identifier;
+    private DependencyModelIdentifier identifier1;
+    private DependencyModelIdentifier identifier2;
+    private DependencyModelIdentifier identifier3;
+
+    @Before
+    public void setUp() throws Exception {
+        identifier = new DependencyModelIdentifier(vnfType, cVersion);
+        identifier1 = new DependencyModelIdentifier(null, null);
+        identifier2 = new DependencyModelIdentifier(vnfType, null);
+        identifier3 = new DependencyModelIdentifier(null, cVersion);
+    }
+
+    @Test
+    public void testConstructorAndGetterAndToString() throws Exception {
+        Assert.assertEquals(vnfType, Whitebox.getInternalState(identifier, "vnfType"));
+        Assert.assertEquals(cVersion, Whitebox.getInternalState(identifier, "catalogVersion"));
+
+        Assert.assertEquals(vnfType, identifier.getVnfType());
+        Assert.assertEquals(cVersion, identifier.getCatalogVersion());
+
+        Assert.assertEquals(
+                String.format(DependencyModelIdentifier.TO_STRING_FORMAT, vnfType, cVersion),
+                identifier.toString());
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        Assert.assertEquals((prime + vnfType.hashCode()) * prime + cVersion.hashCode(),
+                identifier.hashCode());
+        Assert.assertEquals(prime * prime, identifier1.hashCode());
+        Assert.assertEquals((prime + vnfType.hashCode()) * prime, identifier2.hashCode());
+        Assert.assertEquals(prime * prime + cVersion.hashCode(), identifier3.hashCode());
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        // other object is null
+        Assert.assertFalse(identifier.equals(null));
+        // other object is wrong data type
+        Assert.assertFalse(identifier.equals("abc"));
+
+        // my vnfType is null
+        Assert.assertFalse(identifier1.equals(identifier));
+        // different vnfType
+        DependencyModelIdentifier identifier4 = new DependencyModelIdentifier(vnfType2, cVersion);
+        Assert.assertFalse(identifier.equals(identifier4));
+        // same vnfType, my catalogVerson is null
+        Assert.assertFalse(identifier2.equals(identifier));
+        // same vnfType and both catalogVersion are null
+        identifier4 = new DependencyModelIdentifier(vnfType, null);
+        Assert.assertTrue(identifier2.equals(identifier4));
+
+        Assert.assertFalse(identifier.equals(identifier1));
+        Assert.assertFalse(identifier.equals(identifier2));
+        Assert.assertFalse(identifier.equals(identifier3));
+
+        Assert.assertFalse(identifier2.equals(identifier1));
+        Assert.assertFalse(identifier2.equals(identifier3));
+
+
+        Assert.assertFalse(identifier3.equals(identifier));
+        Assert.assertFalse(identifier3.equals(identifier1));
+        Assert.assertFalse(identifier3.equals(identifier2));
+
+        identifier4 = new DependencyModelIdentifier(vnfType, cVersion);
+        Assert.assertTrue(identifier.equals(identifier4));
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/CachedElementTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/CachedElementTest.java
new file mode 100644 (file)
index 0000000..02bdd3b
--- /dev/null
@@ -0,0 +1,275 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.appc.pool.Allocator;
+import org.onap.appc.pool.CachedElement;
+import org.onap.appc.pool.Destructor;
+import org.onap.appc.pool.Pool;
+import org.onap.appc.pool.PoolDrainedException;
+import org.onap.appc.pool.PoolExtensionException;
+import org.onap.appc.pool.PoolSpecificationException;
+import org.onap.appc.pool.*;
+
+
+public class CachedElementTest implements Allocator<Testable>, Destructor<Testable> {
+    private static final int MIN = 10;
+    private static final int MAX = 100;
+    private Pool<Testable> pool;
+    private int index = 0;
+    private int destroyCount = 0;
+
+    /**
+     * setup
+     *
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    @Before
+    public void setup() throws PoolSpecificationException {
+        pool = new Pool<>(MIN, MAX);
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testAllocator() {
+        assertNull(pool.getAllocator());
+        pool.setAllocator(this);
+        assertNotNull(pool.getAllocator());
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testDestructor() {
+        assertNull(pool.getDestructor());
+        pool.setDestructor(this);
+        assertNotNull(pool.getDestructor());
+    }
+
+    /**
+     * Test that we can allocate and release elements and that the pool maintains them in MRU order
+     *
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @Test
+    public void testAllocateAndRelease() throws PoolExtensionException, PoolDrainedException {
+        pool.setAllocator(this);
+
+        assertFalse(pool.isDrained());
+
+        /*
+         * Allocate three elements
+         */
+        Testable value1 = pool.reserve();
+        assertNotNull(value1);
+        assertEquals(Integer.valueOf(MIN - 1), Integer.valueOf(value1.getId()));
+        assertEquals(1, pool.getAllocatedSize());
+        assertEquals(MIN - 1, pool.getFreeSize());
+        assertEquals(1, pool.getAllocatedSize());
+
+        Testable value2 = pool.reserve();
+        assertNotNull(value2);
+        assertEquals(Integer.valueOf(MIN - 2), Integer.valueOf(value2.getId()));
+        assertEquals(2, pool.getAllocatedSize());
+        assertEquals(MIN - 2, pool.getFreeSize());
+        assertEquals(2, pool.getAllocatedSize());
+
+        Testable value3 = pool.reserve();
+        assertNotNull(value3);
+        assertEquals(Integer.valueOf(MIN - 3), Integer.valueOf(value3.getId()));
+        assertEquals(3, pool.getAllocatedSize());
+        assertEquals(MIN - 3, pool.getFreeSize());
+        assertEquals(3, pool.getAllocatedSize());
+
+        /*
+         * Now, release them in the order obtained
+         */
+        pool.release(value1);
+        pool.release(value2);
+        pool.release(value3);
+
+        assertEquals(0, pool.getAllocatedSize());
+        assertEquals(MIN, pool.getFreeSize());
+
+        /*
+         * Now, allocate them again, but their values should be reversed (3, 2, 1) representing the most recently used
+         * to the least recently used.
+         */
+        value1 = pool.reserve();
+        assertNotNull(value1);
+        assertEquals(Integer.valueOf(MIN - 3), Integer.valueOf(value1.getId()));
+
+        value2 = pool.reserve();
+        assertNotNull(value2);
+        assertEquals(Integer.valueOf(MIN - 2), Integer.valueOf(value2.getId()));
+
+        value3 = pool.reserve();
+        assertNotNull(value3);
+        assertEquals(Integer.valueOf(MIN - 1), Integer.valueOf(value3.getId()));
+    }
+
+    /**
+     * Test that we can trim the pool to a desired size
+     *
+     * @throws PoolDrainedException
+     *             If the caller is trying to release or reserve an element from a drained pool
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws IllegalAccessException
+     *             if this Method object is enforcing Java language access control and the underlying method is
+     *             inaccessible.
+     * @throws IllegalArgumentException
+     *             if the method is an instance method and the specified object argument is not an instance of the class
+     *             or interface declaring the underlying method (or of a subclass or implementor thereof); if the number
+     *             of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or
+     *             if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal
+     *             parameter type by a method invocation conversion.
+     * @throws InvocationTargetException
+     *             if the underlying method throws an exception.
+     * @throws SecurityException
+     *             If a security manager, s, is present and any of the following conditions is met:
+     *             <ul>
+     *             <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared method</li>
+     *             <li>the caller's class loader is not the same as or an ancestor of the class loader for the current
+     *             class and invocation of s.checkPackageAccess() denies access to the package of this class</li>
+     *             </ul>
+     * @throws NoSuchMethodException
+     *             if a matching method is not found.
+     */
+    @SuppressWarnings("nls")
+    @Test
+    public void testTrim() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
+        PoolDrainedException, PoolExtensionException, NoSuchMethodException, SecurityException {
+
+        pool.setAllocator(this);
+        int SIZE = 50;
+        Testable[] array = new Testable[SIZE];
+
+        assertEquals(0, pool.getAllocatedSize());
+        for (int i = 0; i < SIZE; i++) {
+            array[i] = pool.reserve();
+        }
+        assertEquals(SIZE, pool.getAllocatedSize());
+
+        for (int i = 0; i < SIZE; i++) {
+            pool.release(array[i]);
+        }
+        assertEquals(0, pool.getAllocatedSize());
+
+        assertEquals(SIZE, pool.getFreeSize());
+
+        Method trimMethod = Pool.class.getDeclaredMethod("trim", new Class[] {
+            Integer.TYPE
+        });
+        trimMethod.setAccessible(true);
+        trimMethod.invoke(pool, new Object[] {
+            SIZE - MIN
+        });
+
+        assertEquals(MIN, pool.getFreeSize());
+    }
+
+    /**
+     * Test that we can drain a pool containing a mix of free and allocated elements
+     *
+     * @throws PoolDrainedException
+     *             If the caller is trying to release or reserve an element from a drained pool
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws IOException
+     *             if an I/O error occurs
+     */
+    @Test
+    public void testDrain() throws PoolExtensionException, PoolDrainedException, IOException {
+        int SIZE = 50;
+        int FREE = 20;
+        int ALLOC = SIZE - FREE;
+
+        Testable[] array = new Testable[SIZE];
+        pool.setAllocator(this);
+        pool.setDestructor(this);
+
+        assertFalse(pool.isDrained());
+
+        assertEquals(0, pool.getAllocatedSize());
+        for (int i = 0; i < SIZE; i++) {
+            array[i] = pool.reserve();
+        }
+        assertEquals(SIZE, pool.getAllocatedSize());
+
+        for (int i = 0; i < FREE; i++) {
+            array[i].close();
+        }
+        assertEquals(ALLOC, pool.getAllocatedSize());
+        assertEquals(FREE, pool.getFreeSize());
+
+        pool.drain();
+        assertEquals(0, pool.getFreeSize());
+        assertEquals(0, pool.getAllocatedSize());
+        assertTrue(pool.isDrained());
+
+        assertEquals(SIZE, destroyCount);
+    }
+
+    /**
+     * @see org.onap.appc.pool.Allocator#allocate(org.onap.appc.pool.Pool)
+     */
+    @Override
+    public Testable allocate(Pool<Testable> pool) {
+        Testable element = new Element(index++);
+        Testable ce = CachedElement.newInstance(pool, element, new Class[] {
+            Testable.class
+        });
+        return ce;
+    }
+
+    /**
+     * @see org.onap.appc.pool.Destructor#destroy(java.io.Closeable, org.onap.appc.pool.Pool)
+     */
+    @Override
+    public void destroy(Testable obj, Pool<Testable> pool) {
+        destroyCount++;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Element.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Element.java
new file mode 100644 (file)
index 0000000..14f3e0e
--- /dev/null
@@ -0,0 +1,77 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.IOException;
+
+public class Element implements Testable {
+    private boolean closed;
+    private Integer id;
+
+    public Element(int id) {
+        this.id = Integer.valueOf(id);
+        closed = false;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        boolean result = false;
+        if (obj instanceof Element) {
+            Element other = (Element) obj;
+            result = this.id.equals(other.id);
+        }
+
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    /**
+     * @see java.io.Closeable#close()
+     */
+    @Override
+    public void close() throws IOException {
+        closed = true;
+    }
+
+    @Override
+    public Boolean isClosed() {
+        return Boolean.valueOf(closed);
+    }
+
+    @Override
+    public String toString() {
+        return Integer.toString(id);
+    }
+
+    @Override
+    public Integer getId() {
+        return id;
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolDrainedExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolDrainedExceptionTest.java
new file mode 100644 (file)
index 0000000..c7b03f3
--- /dev/null
@@ -0,0 +1,36 @@
+/*-\r
+* ============LICENSE_START=======================================================\r
+* ONAP : APPC\r
+* ================================================================================\r
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+* =============================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*      http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+package org.onap.appc.pool;\r
+\r
+import org.junit.Assert;\r
+\r
+import org.junit.Test;\r
+\r
+public class PoolDrainedExceptionTest {\r
+\r
+    @Test\r
+    public void testPoolDrainedException() {\r
+        String message = "test message";\r
+        PoolDrainedException poolDrainedExp = new PoolDrainedException(message);\r
+        Assert.assertEquals(message, poolDrainedExp.getMessage());\r
+        Assert.assertEquals(message, poolDrainedExp.getLocalizedMessage());\r
+    }\r
+\r
+}\r
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExceptionTest.java
new file mode 100644 (file)
index 0000000..34ecd85
--- /dev/null
@@ -0,0 +1,73 @@
+/*-\r
+* ============LICENSE_START=======================================================\r
+* ONAP : APPC\r
+* ================================================================================\r
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+* =============================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*      http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+package org.onap.appc.pool;\r
+\r
+import org.junit.Assert;\r
+\r
+import org.junit.Test;\r
+\r
+public class PoolExceptionTest {\r
+\r
+    @Test\r
+    public void testPoolException() {\r
+        PoolException poolException = new PoolException();\r
+        Assert.assertTrue(poolException.getCause() == null);\r
+        Assert.assertTrue(poolException.getMessage() == null);\r
+    }\r
+\r
+    @Test\r
+    public void testPoolExceptionString() {\r
+        String message = "test message";\r
+        PoolException poolException = new PoolException(message);\r
+        Assert.assertEquals(message, poolException.getMessage());\r
+        Assert.assertEquals(message, poolException.getLocalizedMessage());\r
+    }\r
+\r
+    @Test\r
+    public void testPoolExceptionThrowable() {\r
+        String tMessage = "throwable message";\r
+        Throwable throwable = new Throwable(tMessage);\r
+        PoolException poolException = new PoolException(throwable);\r
+        Assert.assertEquals(throwable, poolException.getCause());\r
+    }\r
+\r
+    @Test\r
+    public void testPoolExceptionStringThrowable() {\r
+        String message = "my test message";\r
+        String tMessage = "throwable message";\r
+        Throwable throwable = new Throwable(tMessage);\r
+        PoolException poolException = new PoolException(message, throwable);\r
+        Assert.assertEquals(throwable, poolException.getCause());\r
+        Assert.assertTrue(poolException.getMessage().contains(message));\r
+        Assert.assertEquals(message, poolException.getLocalizedMessage());\r
+    }\r
+\r
+    @Test\r
+    public void testPoolExceptionStringThrowableBooleanBoolean() {\r
+        String message = "my test message";\r
+        String tMessage = "throwable message";\r
+        Throwable throwable = new Throwable(tMessage);\r
+        PoolException poolException = new PoolException(message, throwable, true, true);\r
+        Assert.assertEquals(throwable, poolException.getCause());\r
+        Assert.assertTrue(poolException.getMessage().contains(message));\r
+        Assert.assertEquals(message, poolException.getLocalizedMessage());\r
+    }\r
+\r
+}\r
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExtensionExceptionTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolExtensionExceptionTest.java
new file mode 100644 (file)
index 0000000..615233d
--- /dev/null
@@ -0,0 +1,36 @@
+/*-\r
+* ============LICENSE_START=======================================================\r
+* ONAP : APPC\r
+* ================================================================================\r
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+* =============================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*      http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+package org.onap.appc.pool;\r
+\r
+import org.junit.Assert;\r
+\r
+import org.junit.Test;\r
+\r
+public class PoolExtensionExceptionTest {\r
+\r
+    @Test\r
+    public void testPoolExtensionException() {\r
+        String message = "test message";\r
+        PoolExtensionException poolExtExcpt = new PoolExtensionException(message);\r
+        Assert.assertEquals(message, poolExtExcpt.getMessage());\r
+        Assert.assertEquals(message, poolExtExcpt.getLocalizedMessage());\r
+    }\r
+\r
+}\r
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/PoolTest.java
new file mode 100644 (file)
index 0000000..d61296a
--- /dev/null
@@ -0,0 +1,332 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Modifications Copyright (C) 2018 IBM.
+ * =============================================================================
+ * 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.appc.pool;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.appc.pool.Allocator;
+import org.onap.appc.pool.Destructor;
+import org.onap.appc.pool.Pool;
+import org.onap.appc.pool.PoolDrainedException;
+import org.onap.appc.pool.PoolExtensionException;
+import org.onap.appc.pool.PoolSpecificationException;
+import org.onap.appc.pool.*;
+
+
+public class PoolTest implements Allocator<Testable>, Destructor<Testable> {
+
+    private Pool<Testable> pool;
+    private static final int MIN = 10;
+    private static final int MAX = 100;
+    private int index = 0;
+    private int destroyCount = 0;
+
+    /**
+     * Set up the test by allocating a pool with MIN-MAX size (bounded pool)
+     *
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    @Before
+    public void setup() throws PoolSpecificationException {
+        pool = new Pool<>(MIN, MAX);
+        index = 0;
+        destroyCount = 0;
+    }
+
+    /**
+     * Test that trying to construct a pool with a bad minimum throws an exception
+     *
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    @Test(expected = PoolSpecificationException.class)
+    public void testInvalidMinSize() throws PoolSpecificationException {
+        pool = new Pool<>(-1, MAX);
+    }
+
+    /**
+     * Test that trying to construct a pool with a bad maximum throws an exception
+     *
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    @Test(expected = PoolSpecificationException.class)
+    public void testInvalidMaxSize() throws PoolSpecificationException {
+        pool = new Pool<>(MIN, -1);
+    }
+
+    /**
+     * Test creation of a pool where max is less than min fails
+     *
+     * @throws PoolSpecificationException
+     *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
+     */
+    @Test(expected = PoolSpecificationException.class)
+    public void testInvalidSizeRange() throws PoolSpecificationException {
+        pool = new Pool<>(MAX, MIN);
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testMinPool() {
+        assertEquals(MIN, pool.getMinPool());
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testMaxPool() {
+        assertEquals(MAX, pool.getMaxPool());
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testAllocator() {
+        assertNull(pool.getAllocator());
+        pool.setAllocator(this);
+        assertNotNull(pool.getAllocator());
+    }
+
+    /**
+     * Test state
+     */
+    @Test
+    public void testDestructor() {
+        assertNull(pool.getDestructor());
+        pool.setDestructor(this);
+        assertNotNull(pool.getDestructor());
+    }
+
+    /**
+     * Test that we can allocate and release elements and that the pool maintains them in MRU order
+     *
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @Test
+    public void testAllocateAndRelease() throws PoolExtensionException, PoolDrainedException {
+        pool.setAllocator(this);
+
+        assertFalse(pool.isDrained());
+
+        /*
+         * Allocate three elements
+         */
+        Testable value1 = pool.reserve();
+        assertNotNull(value1);
+        assertEquals(Integer.valueOf(MIN - 1), value1.getId());
+        assertEquals(1, pool.getAllocatedSize());
+        assertEquals(MIN - 1, pool.getFreeSize());
+        assertEquals(1, pool.getAllocatedSize());
+
+        Testable value2 = pool.reserve();
+        assertNotNull(value2);
+        assertEquals(Integer.valueOf(MIN - 2), value2.getId());
+        assertEquals(2, pool.getAllocatedSize());
+        assertEquals(MIN - 2, pool.getFreeSize());
+        assertEquals(2, pool.getAllocatedSize());
+
+        Testable value3 = pool.reserve();
+        assertNotNull(value3);
+        assertEquals(Integer.valueOf(MIN - 3), value3.getId());
+        assertEquals(3, pool.getAllocatedSize());
+        assertEquals(MIN - 3, pool.getFreeSize());
+        assertEquals(3, pool.getAllocatedSize());
+
+        /*
+         * Now, release them in the order obtained
+         */
+        pool.release(value1);
+        pool.release(value2);
+        pool.release(value3);
+
+        assertEquals(0, pool.getAllocatedSize());
+        assertEquals(MIN, pool.getFreeSize());
+
+        /*
+         * Now, allocate them again, but their values should be reversed (3, 2, 1) representing the most recently used
+         * to the least recently used.
+         */
+        value1 = pool.reserve();
+        assertNotNull(value1);
+        assertEquals(Integer.valueOf(MIN - 3), value1.getId());
+
+        value2 = pool.reserve();
+        assertNotNull(value2);
+        assertEquals(Integer.valueOf(MIN - 2), value2.getId());
+
+        value3 = pool.reserve();
+        assertNotNull(value3);
+        assertEquals(Integer.valueOf(MIN - 1), value3.getId());
+    }
+
+    /**
+     * Test that we can trim the pool to a desired size
+     *
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws NoSuchMethodException
+     *             if a matching method is not found.
+     * @throws SecurityException
+     *             if the request is denied.
+     * @throws IllegalAccessException
+     *             if this Method object is enforcing Java language access control and the underlying method is
+     *             inaccessible.
+     * @throws IllegalArgumentException
+     *             if the method is an instance method and the specified object argument is not an instance of the class
+     *             or interface declaring the underlying method (or of a subclass or implementor thereof); if the number
+     *             of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or
+     *             if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal
+     *             parameter type by a method invocation conversion.
+     * @throws InvocationTargetException
+     *             if the underlying method throws an exception.
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @SuppressWarnings("nls")
+    @Test
+    public void testTrim() throws PoolExtensionException, NoSuchMethodException, SecurityException,
+        IllegalAccessException, IllegalArgumentException, InvocationTargetException, PoolDrainedException {
+        pool.setAllocator(this);
+        int SIZE = 50;
+        Proxy[] array = new Proxy[SIZE];
+
+        assertEquals(0, pool.getAllocatedSize());
+        for (int i = 0; i < SIZE; i++) {
+            array[i] = (Proxy) pool.reserve();
+        }
+        assertEquals(SIZE, pool.getAllocatedSize());
+
+        for (int i = 0; i < SIZE; i++) {
+            pool.release((Testable) array[i]);
+        }
+        assertEquals(0, pool.getAllocatedSize());
+
+        assertEquals(SIZE, pool.getFreeSize());
+
+        Method trimMethod = Pool.class.getDeclaredMethod("trim", new Class[] {
+            Integer.TYPE
+        });
+        trimMethod.setAccessible(true);
+        trimMethod.invoke(pool, new Object[] {
+            SIZE - MIN
+        });
+
+        assertEquals(MIN, pool.getFreeSize());
+    }
+
+    /**
+     * Test that we can drain a pool containing a mix of free and allocated elements
+     *
+     * @throws PoolExtensionException
+     *             If the pool cannot be extended
+     * @throws PoolDrainedException
+     *             If the caller is trying to reserve an element from a drained pool
+     */
+    @Test
+    public void testDrain() throws PoolExtensionException, PoolDrainedException {
+        int SIZE = 50;
+        int FREE = 20;
+        int ALLOC = SIZE - FREE;
+
+        Proxy[] array = new Proxy[SIZE];
+        pool.setAllocator(this);
+        pool.setDestructor(this);
+
+        assertFalse(pool.isDrained());
+
+        assertEquals(0, pool.getAllocatedSize());
+        for (int i = 0; i < SIZE; i++) {
+            array[i] = (Proxy) pool.reserve();
+        }
+        assertEquals(SIZE, pool.getAllocatedSize());
+
+        for (int i = 0; i < FREE; i++) {
+            pool.release((Testable) array[i]);
+        }
+        assertEquals(ALLOC, pool.getAllocatedSize());
+        assertEquals(FREE, pool.getFreeSize());
+
+        pool.drain();
+        assertEquals(0, pool.getFreeSize());
+        assertEquals(0, pool.getAllocatedSize());
+        assertTrue(pool.isDrained());
+
+        assertEquals(SIZE, destroyCount);
+    }
+
+    /**
+     * @see org.onap.appc.pool.Destructor#destroy(java.io.Closeable, org.onap.appc.pool.Pool)
+     */
+    @Override
+    public void destroy(Testable obj, Pool<Testable> pool) {
+        destroyCount++;
+        try {
+            obj.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @see org.onap.appc.pool.Allocator#allocate(org.onap.appc.pool.Pool)
+     */
+    @Override
+    public Testable allocate(Pool<Testable> pool) {
+        Testable e = new Element(index++);
+
+        return e;
+    }
+    
+    @Test
+    public void testGetAndSetProperties() throws PoolSpecificationException
+    {
+        pool= new Pool<Testable>(3, 5);
+        pool.setProperty("key1", "value1");
+        assertEquals("value1", pool.getProperty("key1"));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Testable.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/pool/Testable.java
new file mode 100644 (file)
index 0000000..22c9408
--- /dev/null
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.pool;
+
+import java.io.Closeable;
+
+public interface Testable extends Closeable {
+
+    Integer getId();
+
+    Boolean isClosed();
+}
+
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/JsonUtilTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/JsonUtilTest.java
new file mode 100644 (file)
index 0000000..9de4554
--- /dev/null
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonParseException;
+import java.io.FileNotFoundException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+
+public class JsonUtilTest {
+
+    @Test(expected = NullPointerException.class)
+    public void should_throw_exception_when_json_string_is_null() throws IOException {
+
+        JsonUtil.convertJsonStringToFlatMap(null);
+    }
+
+    @Test(expected = JsonParseException.class)
+    public void should_throw_exception_when_invalid_json_string() throws IOException {
+
+        JsonUtil.convertJsonStringToFlatMap("{key: value}");
+    }
+
+    @Test
+    public void should_convert_json_string_to_flat_map() throws IOException {
+
+        String jsonString = "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}";
+        Map<String, String> flatMap = JsonUtil.convertJsonStringToFlatMap(jsonString);
+
+        Map<String, String> expectedMap = new HashMap<>();
+        expectedMap.put("A", "A-value");
+        expectedMap.put("B.C", "B.C-value");
+        expectedMap.put("B.D", "B.D-value");
+
+        assertEquals(expectedMap, flatMap);
+        assertNotNull(flatMap);
+    }
+
+    @Test
+    public void should_convert_json_string_to_flat_map_with_nested_json() throws IOException {
+
+        String jsonString = "{\"A\":\"A-value\",\"B\":\"{\\\"C\\\":\\\"C-value\\\",\\\"D\\\":\\\"D-value\\\"}\"}";
+        Map<String, String> flatMap = JsonUtil.convertJsonStringToFlatMap(jsonString);
+
+        Map<String, String> expectedMap = new HashMap<>();
+        expectedMap.put("A", "A-value");
+        expectedMap.put("B", "{\"C\":\"C-value\",\"D\":\"D-value\"}");
+
+        assertEquals(expectedMap, flatMap);
+        assertNotNull(flatMap);
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void should_throw_exception_when_not_found_json_file() throws IOException {
+        JsonUtil.readInputJson("not-existing.json", DummyClass.class);
+    }
+
+
+    @Test(expected = JsonParseException.class)
+    public void should_throw_exception_when_invalid_json_file() throws IOException {
+        JsonUtil.readInputJson("/invalid.json", DummyClass.class);
+    }
+
+    @Test
+    public void should_parse_valid_json_file () throws IOException {
+        DummyClass dummyClass = JsonUtil.readInputJson("/valid.json", DummyClass.class);
+
+        assertEquals("dummy name", dummyClass.getName());
+        assertEquals(99, dummyClass.getValue());
+    }
+
+    private static class DummyClass {
+
+        private String name;
+        private int value;
+
+        public DummyClass(@JsonProperty("name") String name, @JsonProperty("value") int someValue) {
+            this.name = name;
+            this.value = someValue;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+}
+
+
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/MessageFormatterTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/MessageFormatterTest.java
new file mode 100644 (file)
index 0000000..fe7d1a5
--- /dev/null
@@ -0,0 +1,78 @@
+package org.onap.appc.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Maps;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+
+public class MessageFormatterTest {
+
+    @Test
+    public void format_should_return_empty_string_when_given_null_or_empty_message_template() {
+        assertEquals(StringUtils.EMPTY, MessageFormatter.format(null, Maps.newHashMap()));
+        assertEquals(StringUtils.EMPTY, MessageFormatter.format(StringUtils.EMPTY, Maps.newHashMap()));
+    }
+
+    @Test
+    public void should_return_same_string_when_given_null_or_empty_params() {
+        String message = "message";
+
+        assertEquals(message, MessageFormatter.format(message, null));
+        assertEquals(message, MessageFormatter.format(message, Maps.newHashMap()));
+    }
+
+    @Test
+    public void should_return_same_string_when_given_non_dollar_string() {
+        String msg = "vnfid";
+
+        Map<String, Object> respMsg = new HashMap<>();
+        respMsg.put("vnfid", "SYNC_NEW201");
+
+        assertEquals(msg, MessageFormatter.format(msg, respMsg));
+    }
+
+
+    @Test
+    public void should_replace_dollar_sign_statement_with_map_value() {
+        String message = "${vnfid} some sample text ${pnfid} additional sample text";
+
+        Map<String, Object> respMsg = new HashMap<>();
+        respMsg.put("vnfid", "SYNC_NEW201");
+        respMsg.put("pnfid", "TEST-ID");
+
+        assertEquals("SYNC_NEW201 some sample text TEST-ID additional sample text",
+            MessageFormatter.format(message, respMsg));
+    }
+
+    @Test
+    public void getParamsNamesList_should_return_null_when_given_null_or_empty_message_template() {
+        assertEquals(null, MessageFormatter.getParamsNamesList(null));
+        assertEquals(null, MessageFormatter.getParamsNamesList(StringUtils.EMPTY));
+
+        assertEquals(null, MessageFormatter.getParamsNamesSet(null));
+        assertEquals(null, MessageFormatter.getParamsNamesSet(StringUtils.EMPTY));
+    }
+
+    @Test
+    public void should_recognize_params_inside_message_string() {
+        String message = "${vnfid} some sample text ${pnfid} additional sample text";
+
+        List<String> resultList = MessageFormatter.getParamsNamesList(message);
+
+        assertEquals(2, resultList.size());
+        assertTrue(resultList.contains("vnfid"));
+        assertTrue(resultList.contains("pnfid"));
+
+        Set<String> resultSet = MessageFormatter.getParamsNamesSet(message);
+
+        assertEquals(2, resultList.size());
+        assertTrue(resultSet.contains("vnfid"));
+        assertTrue(resultSet.contains("pnfid"));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/PathContextTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/PathContextTest.java
new file mode 100644 (file)
index 0000000..ef538d2
--- /dev/null
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2018 Nokia Solutions and Networks
+ * =============================================================================
+ * 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.appc.util;
+
+import static org.junit.Assert.*;
+
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PathContextTest {
+
+    private PathContext pathContext;
+
+    @Before
+    public void setup() {
+        pathContext = new PathContext();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void should_throw_exception_when_pushed_null_token() {
+        pathContext.pushToken(null);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void should_throw_exception_when_popped_token_from_empty_path() {
+        pathContext.popToken();
+    }
+
+    @Test
+    public void should_delimit_tokens_with_dot() {
+        pathContext.pushToken("test");
+        pathContext.pushToken("token");
+
+        assertEquals("test.token", pathContext.getPath());
+    }
+
+    @Test
+    public void should_pop_tokens() {
+        pathContext.pushToken("test");
+        pathContext.pushToken("token");
+        pathContext.pushToken("token2");
+
+        pathContext.popToken();
+
+        assertEquals("test.token", pathContext.getPath());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void should_throw_exception_when_pushed_null_modifier() {
+        pathContext.pushModifier(null);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void should_throw_exception_when_popped_modifier_from_empty_path() {
+        pathContext.popModifier();
+    }
+
+    @Test
+    public void should_not_delimit_modifiers() {
+        pathContext.pushModifier("test");
+        pathContext.pushModifier("modifier");
+
+        assertEquals("testmodifier", pathContext.getPath());
+    }
+
+    @Test
+    public void should_pop_modifiers() {
+        pathContext.pushModifier("test");
+        pathContext.pushModifier("modifier");
+        pathContext.pushModifier("modifier2");
+
+        pathContext.popModifier();
+
+        assertEquals("testmodifier", pathContext.getPath());
+    }
+
+    @Test
+    public void should_pop_modifiers_and_tokens() {
+        pathContext.pushModifier("test");
+        pathContext.pushModifier("modifier");
+        pathContext.pushToken("token");
+
+        //TODO popToken() and popModifier() actually work the same.
+        //TODO Is there sense to keep same method under different names then?
+
+        pathContext.popToken();
+        assertEquals("testmodifier", pathContext.getPath());
+
+        pathContext.popModifier();
+        assertEquals("test", pathContext.getPath());
+    }
+
+    @Test
+    public void should_add_entries(){
+        pathContext.entry("name", "value");
+
+        Map<String, String> entries = pathContext.entries();
+        assertEquals("value", entries.get("name"));
+    }
+
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StreamHelperTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StreamHelperTest.java
new file mode 100644 (file)
index 0000000..73c32d6
--- /dev/null
@@ -0,0 +1,86 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * 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.appc.util;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+
+import org.junit.Test;
+import org.onap.appc.util.StreamHelper;
+
+public class StreamHelperTest {
+
+    private static final String text = "Filler text (also placeholder text or dummy text) is text that shares "
+        + "some characteristics of a real written text, but is random or otherwise generated. It may be used "
+        + "to display a sample of fonts, generate text for testing, or to spoof an e-mail spam filter. The "
+        + "process of using filler text is sometimes called greeking, although the text itself may be nonsense, "
+        + "or largely Latin, as in Lorem ipsum.\nASDF is the sequence of letters that appear on the first four "
+        + "keys on the home row of a QWERTY or QWERTZ keyboard. They are often used as a sample or test case "
+        + "or as random, meaningless nonsense. It is also a common learning tool for keyboard classes, since "
+        + "all four keys are located on Home row.\nETAOIN SHRDLU is the approximate order of frequency of the "
+        + "twelve most commonly used letters in the English language, best known as a nonsense phrase that "
+        + "sometimes appeared in print in the days of \"hot type\" publishing due to a custom of Linotype "
+        + "machine operators.\nLorem ipsum... is one of the most common filler texts, popular with "
+        + "typesetters and graphic designers. \"Li Europan lingues...\" is another similar example.\n"
+        + "Now is the time for all good men to come to the aid of the party\" is a phrase first proposed "
+        + "as a typing drill by instructor Charles E. Weller; its use is recounted in his book The Early "
+        + "History of the Typewriter, p. 21 (1918).[1] Frank E. McGurrin, an expert on the early Remington "
+        + "typewriter, used it in demonstrating his touch typing abilities in January 1889.[2] It has "
+        + "appeared in a number of typing books, often in the form \"Now is the time for all good men to "
+        + "come to the aid of their country.\"\nThe quick brown fox jumps over the lazy dog - A coherent, "
+        + "short phrase that uses every letter of the alphabet. See pangram for more examples.\nNew Petitions"
+        + " and Building Code - Many B movies of the 1940s, 50s, and 60s utilized the \"spinning newspaper\" "
+        + "effect to narrate important plot points that occurred offscreen. The effect necessitated the "
+        + "appearance of a realistic front page, which consisted of a main headline relevant to the plot, "
+        + "and several smaller headlines used as filler. A large number of these spinning newspapers "
+        + "included stories titled \"New Petitions Against Tax\" and \"Building Code Under Fire.\" These "
+        + "phrases have become running jokes among B movie fans, and particularly fans of Mystery "
+        + "Science Theater 3000. \nCharacter Generator Protocol - The Character Generator Protocol "
+        + "(CHARGEN) service is an Internet protocol intended for testing, debugging, and measurement "
+        + "purposes.\n!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefgh\n\""
+        + "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghi\n"
+        + "#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghij\n"
+        + "$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijk\n";
+
+    @Test
+    public void should_return_empty_string_when_given_null_input_stream() {
+        assertNotNull(StreamHelper.getStringFromInputStream(null));
+        assertEquals("", StreamHelper.getStringFromInputStream(null));
+    }
+
+    @Test
+    public void should_return_empty_string_when_given_empty_byte_array() {
+        ByteArrayInputStream emptyInputStream = new ByteArrayInputStream(new byte[0]);
+
+        assertEquals("", StreamHelper.getStringFromInputStream(emptyInputStream));
+    }
+
+    @Test
+    public void should_return_string_when_given_byte_array() {
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(text.getBytes());
+
+        assertEquals(text, StreamHelper.getStringFromInputStream(inputStream));
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StringHelperTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/StringHelperTest.java
new file mode 100644 (file)
index 0000000..1022440
--- /dev/null
@@ -0,0 +1,403 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2018 Nokia Solutions and Networks
+ * =============================================================================
+ * Modifications Copyright (C) 2018 IBM
+ * =============================================================================
+ * 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.appc.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Date;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+import org.onap.appc.util.StringHelper;
+
+
+public class StringHelperTest {
+
+    //TODO write more tests for convertToRegex method
+
+    @Test
+    public void convertToRegex_should_return_regex_matching_all_string_when_given_null_or_empty_string(){
+        assertEquals(".*", StringHelper.convertToRegex(null));
+        assertEquals(".*", StringHelper.convertToRegex(""));
+        assertEquals(".*", StringHelper.convertToRegex("  "));
+    }
+    
+    @Test
+    public void convertToRegex_should_return_proper_regex_when_we_provide_a_proper_string_expression(){
+        String expected=".*test\\.jpg.test123\\.jpeg$";
+        assertEquals(expected,StringHelper.convertToRegex("*test.jpg+test123.jpeg"));
+    }
+    
+    @Test
+    public void test_ResolveToType_with_null_as_input(){
+        assertNull(StringHelper.resolveToType(null));
+    }
+    
+    @Test
+    public void test_ResolveToType_with_integer_as_input(){
+       Integer expected=-112;
+       assertEquals(expected,StringHelper.resolveToType("-112"));
+    }
+    
+    @Test
+    public void test_ResolveToType_with_double_as_input(){
+       Double expected=-112.12;
+       assertEquals(expected,StringHelper.resolveToType("-112.12"));
+    }
+    
+    @Test
+    public void test_ResolveToType_with_boolean_as_input(){
+       Boolean expected=true;
+       assertEquals(expected,StringHelper.resolveToType("true"));
+    }
+  
+    @Test
+    public void test_ResolveToType_with_date_as_input(){
+       assertTrue(StringHelper.resolveToType("1994-11-05T08:15:30-05:00") instanceof Date);
+    }
+    
+
+    @Test
+    public void getShortenedString_should_return_null_when_given_null(){
+        assertNull(StringHelper.getShortenedString(null, 2));
+    }
+
+    @Test
+    public void getShortenedString_should_return_given_string_when_length_is_lower_than_4(){
+        assertEquals("str", StringHelper.getShortenedString("str", 3));
+        assertEquals("str", StringHelper.getShortenedString("str", 2));
+        assertEquals("test", StringHelper.getShortenedString("test", 3));
+    }
+
+    @Test
+    public void getShortenedString_should_shorten_string_and_append_ellipsis(){
+
+        assertEquals("s...", StringHelper.getShortenedString("sample", 4));
+        assertEquals("test...", StringHelper.getShortenedString("test string", 7));
+    }
+
+    @Test
+    public void isNotNullNotEmpty_should_return_true_if_string_is_not_null_or_not_empty(){
+        assertFalse(StringHelper.isNotNullNotEmpty(null));
+        assertFalse(StringHelper.isNotNullNotEmpty(""));
+        assertFalse(StringHelper.isNotNullNotEmpty(" "));
+        assertTrue(StringHelper.isNotNullNotEmpty("test"));
+    }
+
+    @Test
+    public void isNullOrEmpty_should_return_true_if_string_is_null_or_empty(){
+        assertTrue(StringHelper.isNullOrEmpty(null));
+        assertTrue(StringHelper.isNullOrEmpty(""));
+        assertTrue(StringHelper.isNullOrEmpty(" "));
+        assertFalse(StringHelper.isNullOrEmpty("test"));
+    }
+
+    @Test
+    public void areEqual_should_return_true_when_both_null(){
+        assertTrue(StringHelper.areEqual(null, null));
+    }
+
+    @Test
+    public void areEqual_should_return_false_when_one_string_is_null(){
+        assertFalse(StringHelper.areEqual(null, "test"));
+    }
+
+    @Test
+    public void areEqual_should_compare_two_string(){
+        assertFalse(StringHelper.areEqual("test2", "test"));
+        assertFalse(StringHelper.areEqual("test", "Test"));
+    }
+
+    @Test
+    public void equalsIgnoreCase_should_compare_two_string_case_insensitive(){
+        assertFalse(StringHelper.equalsIgnoreCase("test2", "test"));
+        assertTrue(StringHelper.equalsIgnoreCase("test", "Test"));
+    }
+
+    @Test
+    public void mangleName_should_pad_string_when_given_null_or_empty(){
+        assertEquals("aaaa", StringHelper.mangleName(null, 3, 6));
+        assertEquals("aaaa", StringHelper.mangleName(StringUtils.EMPTY, 3, 6));
+
+        assertEquals("aa", StringHelper.mangleName(null, 1, 6));
+        assertEquals("aa", StringHelper.mangleName(StringUtils.EMPTY, 1, 6));
+
+        assertEquals("aaaaaaaaa", StringHelper.mangleName(null, 8, 12));
+        assertEquals("aaaaaaaaa", StringHelper.mangleName(StringUtils.EMPTY, 8, 12));
+
+    }
+
+    @Test
+    public void mangleName_should_remove_all_illegal_characters(){
+        assertEquals("ab45", StringHelper.mangleName("ab45 ", 3, 6));
+        assertEquals("ab45", StringHelper.mangleName("ab!45", 3, 6));
+        assertEquals("ab45", StringHelper.mangleName("a b!45", 3, 6));
+    }
+
+    @Test
+    public void mangleName_should_convert_all_character_to_lowercase(){
+        assertEquals("test", StringHelper.mangleName("TeSt", 3, 6));
+        assertEquals("abb45fgr", StringHelper.mangleName("abB!4 5FGR", 6, 8));
+    }
+
+    @Test
+    public void mangleName_should_pad_string_when_result_is_too_short(){
+        assertEquals("testaaa", StringHelper.mangleName("TeSt", 6, 10));
+        assertEquals("abb45fgraaaaa", StringHelper.mangleName("abB!4 5FGR", 12, 15));
+    }
+
+    @Test
+    public void mangleName_should_truncate_string_when_too_long(){
+        assertEquals("tst", StringHelper.mangleName("TeSt", 0, 3));
+        assertEquals("tt", StringHelper.mangleName("TeSt", 0, 2));
+        assertEquals("agr", StringHelper.mangleName("abb45fgr", 0, 3));
+        assertEquals("abgr", StringHelper.mangleName("abb45fgr", 0, 4));
+    }
+
+    @Test
+    public void normalizeString_should_return_null_when_given_null_or_empty_string(){
+        assertNull(StringHelper.normalizeString(null));
+        assertNull(StringHelper.normalizeString(StringUtils.EMPTY));
+    }
+
+    @Test
+    public void normalizeString_should_trim_string(){
+        assertEquals("this is test sequence",
+            StringHelper.normalizeString("  this is test sequence "));
+        assertEquals("this  is test   sequence",
+            StringHelper.normalizeString("  this  is test   sequence   "));
+    }
+
+    @Test
+    public void stripCRLFs_should_return_null_when_given_null() {
+        assertNull(StringHelper.stripCRLF(null));
+    }
+
+    @Test
+    public void stripCRLF_should_strip_all_CRLF_and_LF() {
+        assertEquals(StringUtils.EMPTY, StringHelper.toUnixLines(StringUtils.EMPTY));
+        assertEquals("this is test sequence", StringHelper.stripCRLF("this is test sequence"));
+        assertEquals("this is testsequence", StringHelper.stripCRLF("this is test\nsequence"));
+        assertEquals("this istestsequence", StringHelper.stripCRLF("this is\ntest\r\nsequence"));
+        assertEquals("this istestsequence", StringHelper.stripCRLF("this is\r\ntest\n\rsequence"));
+    }
+
+    @Test
+    public void toDOSLines_should_return_null_when_given_null() {
+        assertNull(StringHelper.toDOSLines(null));
+    }
+
+    @Test
+    public void toUnixLines_should_replace_LF_with_CRLF() {
+        assertEquals(StringUtils.EMPTY, StringHelper.toUnixLines(StringUtils.EMPTY));
+        assertEquals("this is test sequence", StringHelper.toDOSLines("this is test sequence"));
+        assertEquals("this is test\r\nsequence", StringHelper.toDOSLines("this is test\nsequence"));
+        assertEquals("this is test\rsequence", StringHelper.toDOSLines("this is test\rsequence"));
+        assertEquals("this is\r\ntest\n\rsequence", StringHelper.toDOSLines("this is\r\ntest\n\rsequence"));
+    }
+
+    @Test
+    public void toUnixLines_should_return_null_when_given_null() {
+        assertNull(StringHelper.toUnixLines(null));
+    }
+
+    @Test
+    public void toUnixLines_should_replace_CRLF_with_LF() {
+        assertEquals(StringUtils.EMPTY, StringHelper.toUnixLines(StringUtils.EMPTY));
+        assertEquals("this is test sequence", StringHelper.toUnixLines("this is test sequence"));
+        assertEquals("this is test\nsequence", StringHelper.toUnixLines("this is test\nsequence"));
+        assertEquals("this is\ntest\nsequence", StringHelper.toUnixLines("this is\r\ntest\n\rsequence"));
+    }
+
+    @Test
+    public void translate_should_return_null_when_given_null_sequence() {
+        assertNull(StringHelper.translate(null, "abc", "def"));
+    }
+
+    @Test
+    public void translate_should_translate_sequence() {
+
+        assertEquals(StringUtils.EMPTY, StringHelper.translate(StringUtils.EMPTY, "abc", "def"));
+        assertEquals("ahis is absa sbqubccb",
+            StringHelper.translate("this is test sequence", "ten", "abc"));
+    }
+
+
+    @Test
+    public void translate_should_translate_sequence_given_replacement_longer_then_match() {
+        assertEquals("ahis is absa sbqubccb",
+            StringHelper.translate("this is test sequence", "ten", "abcde"));
+    }
+
+    @Test
+    public void translate_should_translate_sequence_given_replacement_shorter_then_match() {
+        assertEquals("ahas as absa sbqubccb",
+            StringHelper.translate("this is test sequence", "teni", "abc"));
+    }
+
+    @Test
+    public void validIdentifier_should_return_null_when_given_null() {
+        assertNull(StringHelper.validIdentifier(null));
+    }
+
+
+    @Test
+    public void validIdentifier_should_return_valid_identifier() {
+        assertEquals(StringUtils.EMPTY, StringHelper.validIdentifier(StringUtils.EMPTY));
+        assertEquals("abcd", StringHelper.validIdentifier("abcd"));
+        assertEquals("abc_", StringHelper.validIdentifier("abc!"));
+        assertEquals("ab_cd", StringHelper.validIdentifier("ab cd"));
+        assertEquals("ab_cd_", StringHelper.validIdentifier("ab cd!"));
+    }
+
+    @Test
+    public void verify_should_return_null_when_given_null_sequence() {
+        assertNull(StringHelper.verify(null, "abc", 'r'));
+    }
+
+    @Test
+    public void verify_should_return_empty_string_when_given_empty_sequence() {
+        assertEquals(StringUtils.EMPTY, StringHelper.verify("", "abc", 'r'));
+    }
+
+    @Test
+    public void verify_should_replace_illegal_characters() {
+        assertEquals("trir ir tert rerterre",
+            StringHelper.verify("this is test sentence", "iet ", 'r'));
+    }
+
+    @Test
+    public void toList_should_return_empty_string_when_given_null_or_empty_list() {
+        assertEquals(StringUtils.EMPTY, StringHelper.asList((List<String>) null));
+        assertEquals(StringUtils.EMPTY, StringHelper.asList((Lists.newArrayList())));
+    }
+
+    @Test
+    public void toList_should_return_element_when_given_one_element_list() {
+        assertEquals("test", StringHelper.asList(Lists.newArrayList("test")));
+    }
+
+    @Test
+    public void toList_should_convert_to_string_given_list() {
+        assertEquals("test, test2, test3",
+            StringHelper.asList(Lists.newArrayList("test", "test2", "test3")));
+    }
+
+    @Test
+    public void toList_should_return_empty_string_when_given_null_or_empty_map() {
+        assertEquals(StringUtils.EMPTY, StringHelper.asList((Map<String, String>) null));
+        assertEquals(StringUtils.EMPTY, StringHelper.asList((Maps.newHashMap())));
+    }
+
+    @Test
+    public void toList_should_return_entry_when_given_one_entry_map() {
+        Map<String, String> testMap = new HashMap<>();
+        testMap.put("key1", "value1");
+
+        assertEquals("key1=value1", StringHelper.asList(testMap));
+    }
+
+    @Test
+    public void toList_should_convert_to_string_given_map() {
+        Map<String, String> testMap = new HashMap<>();
+        testMap.put("key1", "value1");
+        testMap.put("key2", "value2");
+
+        assertEquals("key1=value1, key2=value2", StringHelper.asList(testMap));
+    }
+
+    @Test
+    public void toList_should_return_string_representation_of_empty_array_when_given_null() {
+        String value = StringHelper.asList((String[]) null);
+        assertNotNull(value);
+        assertEquals("[]", value);
+    }
+
+    @Test
+    public void toList_should_return_string_representation_of_empty_array_when_given_empty_array() {
+        String value = StringHelper.asList(new String[]{});
+        assertNotNull(value);
+        assertEquals("[]", value);
+    }
+
+    @Test
+    public void toList_should_return_string_representation_of_one_element_array() {
+        String value = StringHelper.asList("one");
+        assertNotNull(value);
+        assertEquals("[one]", value);
+    }
+
+    @Test
+    public void toList_should_return_string_representation_of_array() {
+        String value = StringHelper.asList("one", "two", "three", "four", "five");
+        assertNotNull(value);
+        assertEquals("[one,two,three,four,five]", value);
+    }
+
+    @Test
+    public void propertiesToString_should_return_null_when_given_null_properties() {
+
+        assertEquals(null, StringHelper.propertiesToString(null));
+    }
+
+    @Test
+    public void propertiesToString_should_return_string_representation_of_empty_array_when_given_empty_properties() {
+
+        Properties props = new Properties();
+
+        String result = StringHelper.propertiesToString(props);
+        assertNotNull(result);
+        assertEquals("[ ]", result);
+    }
+
+    @Test
+    public void propertiesToString_should_return_convert_properties_to_string() {
+        Properties props = new Properties();
+        props.setProperty("key1", "value1");
+        props.setProperty("key2", "value2");
+
+        String result = StringHelper.propertiesToString(props);
+
+        assertTrue(result.startsWith("[ "));
+        assertTrue(result.contains("key1"));
+        assertTrue(result.contains("value1"));
+        assertTrue(result.contains("key2"));
+        assertTrue(result.contains("value2"));
+        assertTrue(result.endsWith(" ]"));
+        assertTrue(result.lastIndexOf(",") < result.length() - 3);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TestStructuredPropertyHelper.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TestStructuredPropertyHelper.java
new file mode 100644 (file)
index 0000000..e61531a
--- /dev/null
@@ -0,0 +1,284 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Copyright (C) 2017 Amdocs
+ * =============================================================================
+ * Modifications Copyright (C) 2018 IBM.
+ * =============================================================================
+ * 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.appc.util;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onap.appc.util.StructuredPropertyHelper;
+import org.onap.appc.util.StructuredPropertyHelper.Node;
+
+/**
+ * This class is used to test the structured property helper class.
+ * <p>
+ * A structured property is one where the name is constructed from a compound set of elements, concatenated by a period,
+ * and optionally being enumerated using a sequence number suffix. A java package name is an example of a structured
+ * name, where each element of the name represents a directory or name in the namespace hierarchy. Property names may
+ * also be structured. This class constructs a graph of the structured properties and this test case is used to verify
+ * its operation.
+ * </p>
+ *
+ */
+public class TestStructuredPropertyHelper {
+
+    /**
+     * The properties to be parsed
+     */
+    private Properties properties;
+
+    /**
+     * The result of parsing the properties
+     */
+    private List<Node> nodes = new ArrayList<>();
+
+    /**
+     * Initialize the test environment
+     */
+    @SuppressWarnings("nls")
+    @Before
+    public void setup() {
+        nodes.clear();
+
+        properties = new Properties();
+
+        properties.setProperty("provider1.name", "provider1Name");
+        properties.setProperty("provider1.type", "provider1type");
+        properties.setProperty("provider1.URL", "provider1URL");
+        properties.setProperty("provider2.name", "provider2Name");
+        properties.setProperty("provider2.type", "provider2type");
+        properties.setProperty("provider2.URL", "provider2URL");
+        properties.setProperty("provider003.name", "provider3Name");
+        properties.setProperty("provider003.type", "provider3type");
+        properties.setProperty("provider003.URL", "provider3URL");
+
+        properties.setProperty("node1.level1.value1.key", "1.1.1");
+        properties.setProperty("node1.level1.value2.key", "1.1.2");
+        properties.setProperty("node1.level1.value3.key", "1.1.3");
+        properties.setProperty("node1.level2.value1.key", "1.2.1");
+        properties.setProperty("node1.level2.value2.key", "1.2.2");
+        properties.setProperty("node1.level2.value3.key", "1.2.3");
+        properties.setProperty("node1.level3.value1.key", "1.3.1");
+        properties.setProperty("node1.level3.value2.key", "1.3.2");
+        properties.setProperty("node1.level3.value3.key", "1.3.3");
+        properties.setProperty("node2.level1.value1.key", "2.1.1");
+        properties.setProperty("node2.level1.value2.key", "2.1.2");
+        properties.setProperty("node2.level1.value3.key", "2.1.3");
+        properties.setProperty("node2.level2.value1.key", "2.2.1");
+        properties.setProperty("node2.level2.value2.key", "2.2.2");
+        properties.setProperty("node2.level2.value3.key", "2.2.3");
+        properties.setProperty("node2.level3.value1.key", "2.3.1");
+        properties.setProperty("node2.level3.value2.key", "2.3.2");
+        properties.setProperty("node2.level3.value3.key", "2.3.3");
+        properties.setProperty("node3.level1.value1.key", "3.1.1");
+        properties.setProperty("node3.level1.value2.key", "3.1.2");
+        properties.setProperty("node3.level1.value3.key", "3.1.3");
+        properties.setProperty("node3.level2.value1.key", "3.2.1");
+        properties.setProperty("node3.level2.value2.key", "3.2.2");
+        properties.setProperty("node3.level2.value3.key", "3.2.3");
+        properties.setProperty("node3.level3.value1.key", "3.3.1");
+        properties.setProperty("node3.level3.value2.key", "3.3.2");
+        properties.setProperty("node3.level3.value3.key", "3.3.3");
+
+        properties.setProperty("other.property", "bogus");
+        properties.setProperty("yet.another.property", "bogus");
+        properties.setProperty("simpleProperty", "bogus");
+
+    }
+
+    /**
+     * Test that a simple namespace works
+     */
+    @SuppressWarnings("nls")
+    @Test
+    public void testSimpleNamespace() {
+        nodes = StructuredPropertyHelper.getStructuredProperties(properties, "provider");
+
+        assertNotNull(nodes);
+        assertFalse(nodes.isEmpty());
+
+        assertEquals(3, nodes.size());
+
+        List<Node> children;
+        for (Node node : nodes) {
+            switch (node.getName()) {
+                case "provider1":
+                    assertNull(node.getValue());
+                    children = node.getChildren();
+                    assertNotNull(children);
+                    assertEquals(3, children.size());
+                    for (Node child : children) {
+                        switch (child.getName()) {
+                            case "URL":
+                                assertEquals("provider1URL", child.getValue());
+                                break;
+                            case "type":
+                                assertEquals("provider1type", child.getValue());
+                                break;
+                            case "name":
+                                assertEquals("provider1Name", child.getValue());
+                                break;
+                            default:
+                                fail("Unknown child of " + node.getName() + " with value " + child.toString());
+                        }
+                    }
+                    break;
+                case "provider2":
+                    assertNull(node.getValue());
+                    children = node.getChildren();
+                    assertNotNull(children);
+                    assertEquals(3, children.size());
+                    for (Node child : children) {
+                        switch (child.getName()) {
+                            case "URL":
+                                assertEquals("provider2URL", child.getValue());
+                                break;
+                            case "type":
+                                assertEquals("provider2type", child.getValue());
+                                break;
+                            case "name":
+                                assertEquals("provider2Name", child.getValue());
+                                break;
+                            default:
+                                fail("Unknown child of " + node.getName() + " with value " + child.toString());
+                        }
+                    }
+                    break;
+                case "provider3":
+                    /*
+                     * Note that the helper normalizes any ordinal suffixes (003 became 3)
+                     */
+                    assertNull(node.getValue());
+                    children = node.getChildren();
+                    assertNotNull(children);
+                    assertEquals(3, children.size());
+                    for (Node child : children) {
+                        switch (child.getName()) {
+                            case "URL":
+                                assertEquals("provider3URL", child.getValue());
+                                break;
+                            case "type":
+                                assertEquals("provider3type", child.getValue());
+                                break;
+                            case "name":
+                                assertEquals("provider3Name", child.getValue());
+                                break;
+                            default:
+                                fail("Unknown child of " + node.getName() + " with value " + child.toString());
+                        }
+                    }
+                    break;
+                default:
+                    fail("Unknown provider " + node.toString());
+            }
+        }
+        // System.out.println(nodes);
+    }
+
+    /**
+     * Test a multi-dimensional namespace (3X3X3)
+     */
+    @SuppressWarnings("nls")
+    @Test
+    public void testMultiLevelNamespace() {
+        nodes = StructuredPropertyHelper.getStructuredProperties(properties, "node");
+
+        assertNotNull(nodes);
+        assertFalse(nodes.isEmpty());
+
+        assertEquals(3, nodes.size());
+        for (Node node : nodes) {
+            assertNull(node.getValue());
+            List<Node> children = node.getChildren();
+            assertNotNull(children);
+            assertEquals(3, children.size());
+            for (Node child : children) {
+                assertNull(child.getValue());
+                List<Node> grandChildren = child.getChildren();
+                assertNotNull(grandChildren);
+                assertEquals(3, grandChildren.size());
+                for (Node greatGrandChild : grandChildren) {
+                    assertNull(greatGrandChild.getValue());
+                    List<Node> greatGrandChildren = greatGrandChild.getChildren();
+                    assertNotNull(greatGrandChildren);
+                    assertEquals(1, greatGrandChildren.size());
+                }
+            }
+        }
+        // System.out.println(nodes);
+    }
+    
+    @Test
+    public void testToStringWithValue()
+    {
+        nodes = StructuredPropertyHelper.getStructuredProperties(properties, "node");
+        Node node = nodes.get(0);
+        node.setName("testName");
+        node.setValue("testValue");
+        String str= node.toString();
+        assertEquals("testName = testValue",str);
+    }
+    
+    @Test
+    public void testEquals()
+    {
+        Node node0 = new Node();
+        node0.setName("testName");
+        node0.setValue("testValue");
+        Node node1 = new Node();
+        node1.setName("testName");
+        node1.setValue("testValue");
+        assertTrue(node0.equals(node1));    
+    }
+    
+   @Test
+    public void testEqualsWithSameNameAndDifferentValue()
+    {
+        Node node0 = new Node();
+        node0.setName("testName");
+        node0.setValue("testValue1");
+        Node node1 = new Node();
+        node1.setName("testName");
+        node1.setValue("testValue2");
+        assertFalse(node0.equals(node1));    
+    }
+    
+    @Test
+    public void testEqualsWithSameValueAndDifferentName()
+    {
+        Node node0 = new Node();
+        node0.setName("testName1");
+        node0.setValue("testValue");
+        Node node1 = new Node();
+        node1.setName("testName2");
+        node1.setValue("testValue");
+        assertFalse(node0.equals(node1));    
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TimeTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/TimeTest.java
new file mode 100644 (file)
index 0000000..961a62c
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : APPC
+ * ================================================================================
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Modifications Copyright (C) 2018 IBM
+ * =============================================================================
+ * 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.appc.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.text.ParseException;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.junit.Test;
+
+
+public class TimeTest {
+
+    @Test
+    public void testAddTime() {
+
+        final Date dateNow = new Date();
+        long dateNowMSec = dateNow.getTime();
+        Date dateSecLater = Time.addTime(dateNow, 0, 0, 0, 0, 1);
+        long dateSecLaterMSec = dateSecLater.getTime();
+        assertEquals(dateNowMSec + 1000, dateSecLaterMSec);
+
+    }
+
+    @Test
+    public void testDateOnly() {
+
+        final Date dateNow = new Date();
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(dateNow);
+
+        Time.dateOnly(cal);
+
+        long msecFromBegin = cal.get(Calendar.HOUR_OF_DAY)*60*60*1000 +
+            cal.get(Calendar.MINUTE)*60*1000 +
+            cal.get(Calendar.SECOND)*1000 +
+            cal.get(Calendar.MILLISECOND);
+
+        assertEquals( msecFromBegin, 0);
+
+    }
+
+    @Test
+    public void testGetCurrentUTCDate() {
+
+        Date utcDate  = Time.getCurrentUTCDate();
+
+        ZonedDateTime utc = ZonedDateTime.now(ZoneOffset.UTC);
+
+        long epochSecs = utc.toEpochSecond();
+
+        long utcSecs = utcDate.getTime() / 1000;
+
+        assertEquals(epochSecs, utcSecs);
+    }
+
+    @Test
+    public void testEndOfDayLocal() {
+        final Date dateNow = new Date();
+        assertTrue(Time.endOfDayLocal(dateNow) instanceof Date);
+    }
+    
+    @Test
+    public void testGetDateByLocaleAndTimeZone() {
+       final Date dateNow = new Date("19-Jul-2018");
+       Locale locale = new Locale("fr"); 
+       TimeZone timeZone = TimeZone.getTimeZone("Europe/France");
+       assertNotNull(Time.getDateByLocaleAndTimeZone(dateNow,locale,timeZone));
+       assertTrue(Time.getDateByLocaleAndTimeZone(dateNow,locale,timeZone) instanceof String);
+    }
+    
+    @Test
+    public void testUtcFormat() {
+       final Date date = new Date("19-Jul-2018");
+       assertNotNull(Time.utcFormat(date));
+       assertTrue(Time.utcFormat(date) instanceof String);
+    }
+    
+    //this test succeeds if localTime() does not throw an exception  
+    @Test
+    public void testLocalTime() {
+       Time.localTime(1532083631);
+    }
+    
+    @Test
+    public void testSetDate() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.YEAR, 2018);
+        cal.set(Calendar.MONTH, 07);
+        cal.set(Calendar.DAY_OF_MONTH, 03);
+        Calendar cal1= Time.setDate(cal, 2018, 07, 03);
+        assertEquals(cal, cal1);
+    }
+    
+    @Test
+    public void testStartOfDayLocal() {
+        assertTrue(Time.startOfDayLocal() instanceof Date);
+    }
+    
+    @Test
+    public void testTimeStamp() {
+        assertTrue(Time.timestamp() instanceof XMLGregorianCalendar);
+    }
+    
+    @Test
+    public void testDateToStringConverterMillis() {
+        String dateString=Time.dateToStringConverterMillis(new Date("02/09/2004"));
+        String expected="2004-02-09 00:00:00:000";
+        assertEquals(expected, dateString);
+    }
+    
+    @Test
+    public void testStringToDateConverterMillis() throws ParseException{
+        Date date=Time.stringToDateConverterMillis("2004-02-09 00:00:00:000");
+        Date expected=new Date("02/09/2004");
+        assertEquals(expected, date);
+    }
+}
diff --git a/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/UnmodifiablePropertiesTest.java b/appc-core/appc-common-bundle/src/test/java/org/onap/appc/util/UnmodifiablePropertiesTest.java
new file mode 100644 (file)
index 0000000..87646d9
--- /dev/null
@@ -0,0 +1,342 @@
+/*-\r
+ * ============LICENSE_START=======================================================\r
+ * ONAP : APPC\r
+ * ================================================================================\r
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+ * =============================================================================\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ * ============LICENSE_END=========================================================\r
+ */\r
+\r
+package org.onap.appc.util;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Before;\r
+import org.junit.Test;\r
+import org.mockito.Mockito;\r
+import org.hamcrest.CoreMatchers;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.PrintWriter;\r
+import java.io.StringWriter;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.PrintStream;\r
+import java.io.StringReader;\r
+import java.util.Enumeration;\r
+import java.util.Properties;\r
+\r
+public class UnmodifiablePropertiesTest {\r
+\r
+    private static final String propKey1 = "testKey1";\r
+    private static final String propKey2 = "testKey2";\r
+    private static final String propValue1 = "testValue1";\r
+    private static final String propValue2 = "testValue2";\r
+    private static final String noKey = "unusedKey";\r
+    private static final String noValue = "unusedValue";\r
+    private static final String propHeader = "test header";\r
+    private Properties properties = new Properties();\r
+\r
+    private UnmodifiableProperties unmodifiableProperties = new UnmodifiableProperties(properties);\r
+    private String desiredMessage = "Property cannot be modified!";\r
+\r
+    @Before\r
+    public void setUp() throws Exception {\r
+        properties.setProperty(propKey1, propValue1);\r
+        properties.setProperty(propKey2, propValue2);\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public void testClear() {\r
+        try {\r
+            unmodifiableProperties.clear();\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public void testClone() {\r
+        try {\r
+            unmodifiableProperties.clone();\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public final void testContainsObject() {\r
+        Assert.assertTrue(unmodifiableProperties.contains(propValue2));\r
+        Assert.assertFalse(unmodifiableProperties.contains(noValue));\r
+    }\r
+\r
+    @Test\r
+    public final void testContainsKeyObject() {\r
+        Assert.assertTrue(unmodifiableProperties.containsKey(propKey1));\r
+        Assert.assertFalse(unmodifiableProperties.containsKey(noKey));\r
+    }\r
+\r
+    @Test\r
+    public final void testContainsValueObject() {\r
+        Assert.assertTrue(unmodifiableProperties.containsValue(propValue1));\r
+        Assert.assertFalse(unmodifiableProperties.containsValue(noValue));\r
+    }\r
+\r
+    @Test\r
+    public final void testElements() {\r
+        Enumeration<Object> propValues = unmodifiableProperties.elements();\r
+        Assert.assertEquals(propValue2, propValues.nextElement());\r
+        Assert.assertEquals(propValue1, propValues.nextElement());\r
+    }\r
+\r
+    @Test\r
+    public final void testEntrySet() {\r
+        // Expect entrySet=[testKey2=testValue2, testKey1=testValue1].\r
+        Assert.assertEquals("Should match my properties K/V entries in setUp", properties.entrySet(),\r
+                unmodifiableProperties.entrySet());\r
+    }\r
+\r
+    @Test\r
+    public final void testEqualsObject() {\r
+        Assert.assertTrue(unmodifiableProperties.equals(properties));\r
+    }\r
+\r
+    @Test\r
+    public final void testGetObject() {\r
+        Assert.assertEquals(propValue2, unmodifiableProperties.get(propKey2));\r
+    }\r
+\r
+    @Test\r
+    public final void testGetPropertyString() {\r
+        Assert.assertEquals(propValue1, unmodifiableProperties.getProperty("testKey1"));\r
+    }\r
+\r
+    @Test\r
+    public final void testGetPropertyStringString() {\r
+        Assert.assertEquals(propValue2, unmodifiableProperties.getProperty(propKey2, noValue));\r
+        Assert.assertEquals(propValue2, unmodifiableProperties.getProperty(noKey, propValue2));\r
+    }\r
+\r
+    @Test\r
+    public final void testHashCode() {\r
+        Assert.assertEquals("Should match my properties.hashcode() int.", properties.hashCode(),\r
+                unmodifiableProperties.hashCode());\r
+    }\r
+\r
+    @Test\r
+    public final void testIsEmpty() {\r
+        Assert.assertFalse(unmodifiableProperties.isEmpty());\r
+    }\r
+\r
+    @Test\r
+    public final void testKeys() {\r
+        Enumeration<Object> propKeys = unmodifiableProperties.keys();\r
+        Assert.assertEquals(propKey2, propKeys.nextElement());\r
+        Assert.assertEquals(propKey1, propKeys.nextElement());\r
+    }\r
+\r
+    @Test\r
+    public final void testKeySet() {\r
+        // Expect keySet=[testKey2, testKey1].\r
+        Assert.assertEquals("Should match my properties key entries in SetUp", properties.keySet(),\r
+                unmodifiableProperties.keySet());\r
+    }\r
+\r
+    @Test\r
+    public final void testListPrintStream() {\r
+        ByteArrayOutputStream propByteArray = new ByteArrayOutputStream();\r
+        PrintStream listOut = new PrintStream(propByteArray);\r
+        unmodifiableProperties.list(listOut);\r
+        String propList = new String(propByteArray.toByteArray());\r
+        Assert.assertThat(propList, CoreMatchers.containsString("testKey2=testValue2"));\r
+        Assert.assertThat(propList, CoreMatchers.containsString("testKey1=testValue1"));\r
+    }\r
+\r
+    @Test\r
+    public final void testListPrintWriter() {\r
+        StringWriter listOut = new StringWriter();\r
+        PrintWriter writer = new PrintWriter(listOut);\r
+        unmodifiableProperties.list(writer);\r
+        String propList = listOut.toString();\r
+        Assert.assertThat(propList, CoreMatchers.containsString("testKey2=testValue2"));\r
+        Assert.assertThat(propList, CoreMatchers.containsString("testKey1=testValue1"));\r
+    }\r
+\r
+    @Test\r
+    public final void testLoadInputStream() throws IOException {\r
+        InputStream mockInStream = Mockito.mock(InputStream.class);\r
+        try {\r
+            unmodifiableProperties.load(mockInStream);\r
+        } catch (IOException ex) {\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+        }\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testLoadReader() throws IOException {\r
+        String dummyPair = "key3=testKey3\nvalue3=testValue3";\r
+        StringReader reader = new StringReader(dummyPair);\r
+        try {\r
+            unmodifiableProperties.load(reader);\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public final void testLoadFromXMLInputStream() throws IOException {\r
+        InputStream mockInStream = Mockito.mock(InputStream.class);\r
+        try {\r
+            unmodifiableProperties.loadFromXML(mockInStream);\r
+        } catch (IOException ex) {\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public final void testPropertyNames() {\r
+        Enumeration<?> propNames = unmodifiableProperties.propertyNames();\r
+        Assert.assertEquals(propKey2, propNames.nextElement());\r
+        Assert.assertEquals(propKey1, propNames.nextElement());\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testPutObjectObject() {\r
+        try {\r
+            unmodifiableProperties.put(propKey2, propValue1);\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testPutAllMapOfQextendsObjectQextendsObject() {\r
+        try {\r
+            unmodifiableProperties.putAll(properties);\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testRehash() {\r
+        try {\r
+            unmodifiableProperties.rehash();\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testRemoveObject() {\r
+        try {\r
+            unmodifiableProperties.remove(propKey1);\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public final void testSaveOutputStreamString() {\r
+        // Appl method is deprecated, but I still added this test since it is reachable.\r
+        OutputStream propByteArray = new ByteArrayOutputStream();\r
+        unmodifiableProperties.save(propByteArray, propHeader);\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.startsWith("#test header"));\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("testKey2=testValue2"));\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("testKey1=testValue1"));\r
+    }\r
+\r
+    @Test(expected = UnsupportedOperationException.class)\r
+    public final void testSetPropertyStringString() {\r
+        try {\r
+            unmodifiableProperties.setProperty(propKey1, propValue2);\r
+        } catch (UnsupportedOperationException exceptionMessage) {\r
+            Assert.assertEquals(desiredMessage, exceptionMessage.getMessage());\r
+            throw exceptionMessage;\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public final void testSize() {\r
+        Assert.assertEquals(2, unmodifiableProperties.size());\r
+    }\r
+\r
+    @Test\r
+    public final void testStoreOutputStreamString() throws IOException {\r
+        OutputStream propByteArray = new ByteArrayOutputStream();\r
+        unmodifiableProperties.store(propByteArray, propHeader);\r
+        // adds comment header and streams/appends properties file into propByteArray\r
+        // expected = "#test header\n#<Date>\ntestKey2=testValue2\ntestKey1=testValue1"\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.startsWith("#test header"));\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("testKey2=testValue2"));\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("testKey1=testValue1"));\r
+    }\r
+\r
+    @Test\r
+    public final void testStoreWriterString() throws IOException {\r
+        StringWriter writer = new StringWriter();\r
+        unmodifiableProperties.store(writer, propHeader);\r
+        Assert.assertThat(writer.toString(), CoreMatchers.startsWith("#test header"));\r
+        Assert.assertThat(writer.toString(), CoreMatchers.containsString("testKey2=testValue2"));\r
+        Assert.assertThat(writer.toString(), CoreMatchers.containsString("testKey1=testValue1"));\r
+    }\r
+\r
+    @Test\r
+    public final void testStoreToXMLOutputStreamString() throws IOException {\r
+        OutputStream propByteArray = new ByteArrayOutputStream();\r
+        unmodifiableProperties.storeToXML(propByteArray, propHeader);\r
+        // adds XML comment header and streams/appends XML properties file into propByteArray\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("<comment>test header</comment>"));\r
+        Assert.assertThat(propByteArray.toString(),\r
+                CoreMatchers.containsString("<entry key=\"testKey2\">testValue2</entry>"));\r
+        Assert.assertThat(propByteArray.toString(),\r
+                CoreMatchers.containsString("<entry key=\"testKey1\">testValue1</entry>"));\r
+    }\r
+\r
+    @Test\r
+    public final void testStoreToXMLOutputStreamStringString() throws IOException {\r
+        OutputStream propByteArray = new ByteArrayOutputStream();\r
+        unmodifiableProperties.storeToXML(propByteArray, propHeader, "UTF-8");\r
+        // adds XML comment header and streams/appends XML properties file into propByteArray\r
+        Assert.assertThat(propByteArray.toString(), CoreMatchers.containsString("<comment>test header</comment>"));\r
+        Assert.assertThat(propByteArray.toString(),\r
+                CoreMatchers.containsString("<entry key=\"testKey2\">testValue2</entry>"));\r
+        Assert.assertThat(propByteArray.toString(),\r
+                CoreMatchers.containsString("<entry key=\"testKey1\">testValue1</entry>"));\r
+    }\r
+\r
+    @Test\r
+    public final void testStringPropertyNames() {\r
+        Assert.assertEquals(properties.stringPropertyNames(), unmodifiableProperties.stringPropertyNames());\r
+    }\r
+\r
+    @Test\r
+    public final void testToString() {\r
+        // toString=[{testKey2=testValue2, testKey1=testValue1}]\r
+        Assert.assertEquals(properties.toString(), unmodifiableProperties.toString());\r
+    }\r
+\r
+    @Test\r
+    public final void testValues() {\r
+        Assert.assertEquals(properties.values().toString(), unmodifiableProperties.values().toString());\r
+    }\r
+}\r
diff --git a/appc-core/appc-common-bundle/src/test/resources/invalid.json b/appc-core/appc-common-bundle/src/test/resources/invalid.json
new file mode 100644 (file)
index 0000000..cd152e0
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  name: value
+}
\ No newline at end of file
diff --git a/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestAdditionalResources.properties b/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestAdditionalResources.properties
new file mode 100644 (file)
index 0000000..f70db83
--- /dev/null
@@ -0,0 +1,24 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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=========================================================
+###
+
+ADDITIONAL_RESOURCE=This is a message loaded from an additional resource bundle
diff --git a/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_de.properties b/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_de.properties
new file mode 100644 (file)
index 0000000..3bdecb1
--- /dev/null
@@ -0,0 +1,29 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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=========================================================
+###
+
+#
+# Message bundle for German (language de, no specific country) 
+# 
+#
+MESSAGE_TEST=Eine Nachricht f\u00FCr Unit-Tests den Ressource-Manager, arg0 = {0}, arg1 = {1}, arg2 = {2}
+TEST_001=Dies ist eine Testnachricht ohne Eins\u00FCtze bearbeitet werden!
diff --git a/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_en_US.properties b/appc-core/appc-common-bundle/src/test/resources/org/onap/appc/i18n/TestResources_en_US.properties
new file mode 100644 (file)
index 0000000..4bff012
--- /dev/null
@@ -0,0 +1,28 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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=========================================================
+###
+
+#
+# Message bundle for English - United States (en_US).  This is also the default bundle if no other bundles are found. 
+#
+MESSAGE_TEST=A message for unit testing the resource manager, arg0={0}, arg1={1}, arg2={2}
+TEST_001=This is a test message with no inserts to be edited!
diff --git a/appc-core/appc-common-bundle/src/test/resources/valid.json b/appc-core/appc-common-bundle/src/test/resources/valid.json
new file mode 100644 (file)
index 0000000..6ce80f3
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "name": "dummy name",
+  "value": 99
+}
\ No newline at end of file
diff --git a/appc-core/appc-core-features/onap-appc-common/pom.xml b/appc-core/appc-core-features/onap-appc-common/pom.xml
new file mode 100644 (file)
index 0000000..64e6e8f
--- /dev/null
@@ -0,0 +1,48 @@
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  -->\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+  <parent>\r
+    <groupId>org.onap.appc.parent</groupId>\r
+    <artifactId>single-feature-parent</artifactId>\r
+    <version>1.4.0-SNAPSHOT</version>\r
+    <relativePath/>\r
+  </parent>\r
+  \r
+  <groupId>org.onap.appc</groupId>\r
+  <artifactId>onap-appc-common</artifactId>\r
+  <packaging>feature</packaging>\r
+  \r
+  <dependencies>\r
+    <dependency>\r
+        <groupId>org.onap.appc</groupId>\r
+        <artifactId>appc-common-bundle</artifactId>\r
+        <version>${project.version}</version>\r
+    </dependency>\r
+    \r
+    <dependency>\r
+        <groupId>org.onap.ccsdk.sli.core</groupId>\r
+        <artifactId>ccsdk-dblib</artifactId>\r
+        <version>${ccsdk.sli.core.version}</version>\r
+        <type>xml</type>\r
+        <classifier>features</classifier>\r
+    </dependency>\r
+  </dependencies>\r
+</project>
\ No newline at end of file
diff --git a/appc-core/appc-core-features/onap-appc-core/pom.xml b/appc-core/appc-core-features/onap-appc-core/pom.xml
new file mode 100644 (file)
index 0000000..467cb1b
--- /dev/null
@@ -0,0 +1,42 @@
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  -->\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+  <parent>\r
+    <groupId>org.onap.appc.parent</groupId>\r
+    <artifactId>single-feature-parent</artifactId>\r
+    <version>1.4.0-SNAPSHOT</version>\r
+    <relativePath/>\r
+  </parent>\r
+  \r
+  <groupId>org.onap.appc</groupId>\r
+  <artifactId>onap-appc-core</artifactId>\r
+  <packaging>feature</packaging>\r
+  \r
+  <dependencies>\r
+    <dependency>\r
+        <groupId>org.onap.appc</groupId>\r
+        <artifactId>onap-appc-common</artifactId>\r
+        <version>${project.version}</version>\r
+        <type>xml</type>\r
+        <classifier>features</classifier>\r
+    </dependency>\r
+  </dependencies>\r
+</project>
\ No newline at end of file
diff --git a/appc-core/appc-core-features/pom.xml b/appc-core/appc-core-features/pom.xml
new file mode 100644 (file)
index 0000000..2382429
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  -->\r
+  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+  <parent>\r
+    <groupId>org.onap.appc.parent</groupId>\r
+    <artifactId>odlparent-lite</artifactId>    \r
+    <version>1.4.0-SNAPSHOT</version>\r
+  </parent>\r
+  \r
+  <groupId>org.onap.appc</groupId>\r
+  <artifactId>appc-core-features</artifactId>\r
+  <packaging>pom</packaging>\r
+  <modules>\r
+       <module>onap-appc-common</module>\r
+       <module>onap-appc-core</module>\r
+  </modules>\r
+</project>
\ No newline at end of file
diff --git a/appc-core/appc-core-installer/pom.xml b/appc-core/appc-core-installer/pom.xml
new file mode 100644 (file)
index 0000000..fa8b290
--- /dev/null
@@ -0,0 +1,143 @@
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  -->\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+  <parent>\r
+    <groupId>org.onap.appc</groupId>\r
+    <artifactId>appc-core</artifactId>\r
+    <version>1.4.0-SNAPSHOT</version>\r
+  </parent>\r
+  <artifactId>appc-core-installer</artifactId>\r
+  <packaging>pom</packaging>\r
+  \r
+  <properties>\r
+    <application.name>appc-core</application.name>\r
+    <features.boot>appc-core</features.boot>\r
+    \r
+    <!-- SEPARATED FEATURE INSTALLS -->\r
+    <features.repo.core>mvn:org.onap.appc/onap-appc-core/${project.version}/xml/features</features.repo.core>\r
+    <features.repo.common>mvn:org.onap.appc/onap-appc-common/${project.version}/xml/features</features.repo.common>\r
+  </properties>\r
+  <dependencies>\r
+    <dependency>\r
+        <groupId>org.onap.appc</groupId>\r
+        <artifactId>onap-appc-common</artifactId>\r
+        <version>${project.version}</version>\r
+        <type>xml</type>\r
+        <classifier>features</classifier>\r
+    </dependency>\r
+    <dependency>\r
+        <groupId>org.onap.appc</groupId>\r
+        <artifactId>onap-appc-core</artifactId>\r
+        <version>${project.version}</version>\r
+        <type>xml</type>\r
+        <classifier>features</classifier>\r
+    </dependency>\r
+  </dependencies>\r
+    <build>\r
+    <plugins>\r
+      <plugin>\r
+        <artifactId>maven-assembly-plugin</artifactId>\r
+        <executions>\r
+          <execution>\r
+            <id>maven-repo-zip</id>\r
+            <goals>\r
+              <goal>single</goal>\r
+            </goals>\r
+            <phase>package</phase>\r
+            <configuration>\r
+              <appendAssemblyId>false</appendAssemblyId>\r
+              <attach>false</attach>\r
+              <finalName>stage/${application.name}-${project.version}</finalName>\r
+              <descriptors>\r
+                <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor>\r
+              </descriptors>\r
+            </configuration>\r
+          </execution>\r
+          <execution>\r
+            <id>installer-zip</id>\r
+            <goals>\r
+              <goal>single</goal>\r
+            </goals>\r
+            <phase>package</phase>\r
+            <configuration>\r
+              <appendAssemblyId>false</appendAssemblyId>\r
+              <attach>true</attach>\r
+              <finalName>${application.name}-${project.version}</finalName>\r
+              <descriptors>\r
+                <descriptor>src/assembly/assemble_installer_zip.xml</descriptor>\r
+              </descriptors>\r
+            </configuration>\r
+          </execution>\r
+        </executions>\r
+      </plugin>\r
+      <plugin>\r
+        <groupId>org.apache.maven.plugins</groupId>\r
+        <artifactId>maven-dependency-plugin</artifactId>\r
+        <executions>\r
+          <execution>\r
+            <id>copy-dependencies</id>\r
+            <goals>\r
+              <goal>copy-dependencies</goal>\r
+            </goals>\r
+            <phase>prepare-package</phase>\r
+            <configuration>\r
+              <transitive>false</transitive>\r
+              <outputDirectory>${project.build.directory}/assembly/system</outputDirectory>\r
+              <overWriteReleases>false</overWriteReleases>\r
+              <overWriteSnapshots>true</overWriteSnapshots>\r
+              <overWriteIfNewer>true</overWriteIfNewer>\r
+              <useRepositoryLayout>true</useRepositoryLayout>\r
+              <addParentPoms>false</addParentPoms>\r
+              <copyPom>false</copyPom>\r
+              <excludeGroupIds>org.opendaylight</excludeGroupIds>\r
+              <scope>provided</scope>\r
+            </configuration>\r
+          </execution>\r
+        </executions>\r
+      </plugin>\r
+      <plugin>\r
+        <artifactId>maven-resources-plugin</artifactId>\r
+        <executions>\r
+          <execution>\r
+            <id>copy-version</id>\r
+            <goals>\r
+              <goal>copy-resources</goal>\r
+            </goals>\r
+            <!-- here the phase you need -->\r
+            <phase>validate</phase>\r
+            <configuration>\r
+              <outputDirectory>${basedir}/target/stage</outputDirectory>\r
+              <resources>\r
+                <resource>\r
+                  <directory>src/main/resources/scripts</directory>\r
+                  <includes>\r
+                    <include>install-feature.sh</include>\r
+                  </includes>\r
+                  <filtering>true</filtering>\r
+                </resource>\r
+              </resources>\r
+            </configuration>\r
+          </execution>\r
+        </executions>\r
+      </plugin>\r
+    </plugins>\r
+  </build>\r
+</project>
\ No newline at end of file
diff --git a/appc-core/appc-core-installer/src/assembly/assemble_installer_zip.xml b/appc-core/appc-core-installer/src/assembly/assemble_installer_zip.xml
new file mode 100644 (file)
index 0000000..1d8bead
--- /dev/null
@@ -0,0 +1,60 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP : APPC
+  ================================================================================
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Copyright (C) 2017 Amdocs
+  =============================================================================
+  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=========================================================
+  -->
+
+<!-- Defines how we build the .zip file which is our distribution. -->
+
+<assembly
+       xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+       <id>appc-core</id>
+       <formats>
+               <format>zip</format>
+       </formats>
+
+       <!--  we want "system" and related files right at the root level
+                 as this file is suppose to be unzip on top of a karaf
+                 distro. -->
+       <includeBaseDirectory>false</includeBaseDirectory>
+
+       <fileSets>
+               <fileSet>
+                       <directory>target/stage/</directory>
+                       <outputDirectory>${application.name}</outputDirectory>
+                       <fileMode>755</fileMode>
+                       <includes>
+                               <include>*.sh</include>
+                       </includes>
+               </fileSet>
+               <fileSet>
+                       <directory>target/stage/</directory>
+                       <outputDirectory>${application.name}</outputDirectory>
+                       <fileMode>644</fileMode>
+                       <excludes>
+                               <exclude>*.sh</exclude>
+                       </excludes>
+               </fileSet>
+       </fileSets>
+
+
+
+</assembly>
diff --git a/appc-core/appc-core-installer/src/assembly/assemble_mvnrepo_zip.xml b/appc-core/appc-core-installer/src/assembly/assemble_mvnrepo_zip.xml
new file mode 100644 (file)
index 0000000..54b49f3
--- /dev/null
@@ -0,0 +1,48 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP : APPC
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Copyright (C) 2017 Amdocs
+  =============================================================================
+  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=========================================================
+  -->
+
+<!-- Defines how we build the .zip file which is our distribution. -->
+
+<assembly
+       xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+       <id>appc-core</id>
+       <formats>
+               <format>zip</format>
+       </formats>
+
+       <!--  we want "system" and related files right at the root level
+                 as this file is suppose to be unzip on top of a karaf
+                 distro. -->
+       <includeBaseDirectory>false</includeBaseDirectory>
+
+       <fileSets>
+               <fileSet>
+                       <directory>target/assembly/</directory>
+                       <outputDirectory>.</outputDirectory>
+                       <excludes>
+                       </excludes>
+               </fileSet>
+       </fileSets>
+
+</assembly>
diff --git a/appc-core/appc-core-installer/src/main/resources/scripts/install-feature.sh b/appc-core/appc-core-installer/src/main/resources/scripts/install-feature.sh
new file mode 100644 (file)
index 0000000..5d2f6fa
--- /dev/null
@@ -0,0 +1,56 @@
+###
+# ============LICENSE_START=======================================================
+# ONAP : APPC
+# ================================================================================
+# Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Copyright (C) 2017 Amdocs
+# =============================================================================
+# 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=========================================================
+###
+
+#!/bin/bash
+
+ODL_HOME=${ODL_HOME:-/opt/opendaylight/current}
+ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client}
+ODL_KARAF_CLIENT_OPTS=${ODL_KARAF_CLIENT_OPTS:-""}
+INSTALLERDIR=$(dirname $0)
+
+REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}.zip
+
+if [ -f ${REPOZIP} ]
+then
+       unzip -n -d ${ODL_HOME} ${REPOZIP}
+else
+       echo "ERROR : repo zip ($REPOZIP) not found"
+       exit 1
+fi
+
+${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:repo-add ${features.repo.common}
+${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:repo-add ${features.repo.core}
+
+
+#COUNT=0
+#while [ $COUNT -lt 10 ]; do
+#      ${ODL_KARAF_CLIENT} ${ODL_KARAF_CLIENT_OPTS} feature:repo-add ${features.repositories} 2> /tmp/installErr
+
+#      cat /tmp/installErr
+#      if grep -q 'Failed to get the session' /tmp/installErr; then
+#              sleep 10
+#      else
+#              let COUNT=10
+#      fi
+#      let COUNT=COUNT+1
+#done
diff --git a/appc-core/pom.xml b/appc-core/pom.xml
new file mode 100644 (file)
index 0000000..71a2292
--- /dev/null
@@ -0,0 +1,36 @@
+<!--\r
+  ============LICENSE_START=======================================================\r
+  ONAP : APPC\r
+  ================================================================================\r
+  Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.\r
+  ================================================================================\r
+  Licensed under the Apache License, Version 2.0 (the "License");\r
+  you may not use this file except in compliance with the License.\r
+  You may obtain a copy of the License at\r
+  \r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+  \r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+  ============LICENSE_END=========================================================\r
+  -->\r
+  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+    <parent>\r
+        <groupId>org.onap.appc.parent</groupId>\r
+        <artifactId>odlparent-lite</artifactId>\r
+        <version>1.4.0-SNAPSHOT</version>\r
+        <relativePath/>\r
+    </parent>\r
+  <groupId>org.onap.appc</groupId>\r
+  <artifactId>appc-core</artifactId>\r
+  <packaging>pom</packaging>\r
+  <modules>\r
+       <module>appc-common-bundle</module>\r
+       <module>appc-core-features</module>\r
+       <module>appc-core-installer</module>\r
+  </modules>\r
+</project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 340a430..3300e1f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -640,6 +640,7 @@ limitations under the License.
     <modules>
         <module>appc-parent</module>
         <module>appc-common</module>
+        <module>appc-core</module>
     </modules>
     <!-- Adding profiles for testing -->
     <profiles>