summaryrefslogtreecommitdiffstats
path: root/appc-common
diff options
context:
space:
mode:
Diffstat (limited to 'appc-common')
-rw-r--r--appc-common/.gitignore4
-rw-r--r--appc-common/pom.xml210
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/Constants.java188
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/concurrent/Signal.java228
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/configuration/Configuration.java240
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/configuration/ConfigurationFactory.java416
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/configuration/DefaultConfiguration.java578
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/configuration/package.html170
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionException.java35
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionTool.java215
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/encryption/HexHelper.java149
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/exceptions/APPCException.java105
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/exceptions/UnknownProviderException.java104
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/i18n/Msg.java612
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/logging/LoggingConstants.java70
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/logging/LoggingUtils.java196
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/Allocator.java45
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/CacheManagement.java32
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/CachedElement.java208
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/Destructor.java44
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/Pool.java371
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/PoolDrainedException.java48
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/PoolException.java89
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/PoolExtensionException.java46
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/pool/PoolSpecificationException.java47
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/JsonUtil.java44
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/MessageFormatter.java83
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/ObjectMapper.java98
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/PathContext.java100
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/StreamHelper.java60
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/StringHelper.java592
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/StructuredPropertyHelper.java252
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/Time.java608
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/UnmodifiableProperties.java353
-rw-r--r--appc-common/src/main/java/org/openecomp/appc/util/httpClient.java207
-rw-r--r--appc-common/src/main/resources/org/openecomp/appc/i18n/MessageResources.properties792
-rw-r--r--appc-common/src/main/resources/org/openecomp/appc/i18n/auth.properties23
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/concurrent/TestSignal.java132
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/encryption/TestEncryption.java43
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/pool/CachedElementTest.java273
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/pool/Element.java75
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/pool/PoolTest.java320
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/pool/Testable.java32
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/util/TestJsonUtil.java71
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/util/TestStreamHelper.java78
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/util/TestStringHelper.java104
-rw-r--r--appc-common/src/test/java/org/openecomp/appc/util/TestStructuredPropertyHelper.java233
-rw-r--r--appc-common/src/test/resources/org/openecomp/appc/i18n/TestAdditionalResources.properties22
-rw-r--r--appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_de.properties26
-rw-r--r--appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_en_US.properties26
50 files changed, 9097 insertions, 0 deletions
diff --git a/appc-common/.gitignore b/appc-common/.gitignore
new file mode 100644
index 000000000..637be2b0f
--- /dev/null
+++ b/appc-common/.gitignore
@@ -0,0 +1,4 @@
+/target/
+.classpath
+/bin/
+/.settings/
diff --git a/appc-common/pom.xml b/appc-common/pom.xml
new file mode 100644
index 000000000..e234e89d2
--- /dev/null
+++ b/appc-common/pom.xml
@@ -0,0 +1,210 @@
+<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">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.openecomp.appc</groupId>
+ <artifactId>appc</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <artifactId>appc-common</artifactId>
+ <name>APP-C Common</name>
+ <description>Common library shared across all modules</description>
+
+<!-- <packaging>bundle</packaging> -->
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <!-- Needed for EELF (Event and Error Logging Framework) support -->
+ <dependency>
+ <groupId>com.att.eelf</groupId>
+ <artifactId>eelf-core</artifactId>
+ </dependency>
+
+ <!-- Needed for encryption -->
+ <dependency>
+ <groupId>org.jasypt</groupId>
+ <artifactId>jasypt</artifactId>
+ <version>1.9.2</version>
+<!-- <classifier>lite</classifier> -->
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax</groupId>
+ <artifactId>javaee-api</artifactId>
+ <version>7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ <version>${apache.httpcomponents.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ <resource>
+ <directory>src/main/java</directory>
+ <includes>
+ <include>**/*.java</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>appc-common</Bundle-SymbolicName>
+ <!-- <Export-Package>org.openecomp.appc.provider</Export-Package> -->
+ <Import-Package>!com.att,!javax.crypto.*, *</Import-Package>
+ <Embed-Dependency>eelf-core, jasypt</Embed-Dependency>
+ <Embed-Transitive>true</Embed-Transitive>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>com.att.eelf</groupId>
+ <artifactId>eelf-maven-plugin</artifactId>
+ <version>${eelf.maven.plugin.version}</version>
+ <executions>
+ <execution>
+ <id>validation</id>
+ <phase>install</phase>
+ <goals>
+ <goal>ValidateApplicationMsgs</goal>
+ </goals>
+ <configuration>
+ <resources>
+ <resource>
+ <messageClass>org.openecomp.appc.i18n.Msg</messageClass>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate</id>
+ <phase>install</phase>
+ <goals>
+ <goal>WikiMsgGenerator</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>target/messages</outputDirectory>
+ <outputFile>messages.html</outputFile>
+ <resources>
+ <resource>
+ <messageClass>org.openecomp.appc.i18n.Msg</messageClass>
+ <header><![CDATA[<p> <ac:macro ac:name="toc" /> </p>]]></header>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.openecomp.appc</groupId>
+ <artifactId>appc-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <!-- For embedding dependencies -->
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>install</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <finalName>${project.artifactId}-${project.version}-jar-with-dependencies</finalName>
+ <artifactSet>
+ <excludes>
+ <exclude>junit:junit</exclude>
+ <exclude>ch.qos.logback:*</exclude>
+ <exclude>org.slf4j:slf4j-api</exclude>
+ </excludes>
+ </artifactSet>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/appc-common/src/main/java/org/openecomp/appc/Constants.java b/appc-common/src/main/java/org/openecomp/appc/Constants.java
new file mode 100644
index 000000000..134f7ecc2
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/Constants.java
@@ -0,0 +1,188 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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";
+
+ public static final String DG_OUTPUT_STATUS_MESSAGE = "output.status.message";
+
+ public static final String DG_ATTRIBUTE_STATUS = "SvcLogic.status";
+
+ /**
+ * 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 name of the service logic method in the DG to be executed
+ */
+ // public static final String CONFIGURATION_METHOD_NAME = "configuration-operation";
+
+ /**
+ * 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.openecomp.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.openecomp.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.openecomp.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.openecomp.appc.reqid";
+
+ /**
+ * The name of the property that indicates which method of the IaaS adapter to call
+ */
+ public static final String CONTEXT_ACTION = "org.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.appc.stack.state.change.timeout" ;
+
+ /**
+ * Private default constructor prevents instantiation
+ */
+
+ @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";
+
+ private Constants() {
+
+ }
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/concurrent/Signal.java b/appc-common/src/main/java/org/openecomp/appc/concurrent/Signal.java
new file mode 100644
index 000000000..153dd0bdc
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/concurrent/Signal.java
@@ -0,0 +1,228 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.concurrent;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.openecomp.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-common/src/main/java/org/openecomp/appc/configuration/Configuration.java b/appc-common/src/main/java/org/openecomp/appc/configuration/Configuration.java
new file mode 100644
index 000000000..f64129011
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/configuration/Configuration.java
@@ -0,0 +1,240 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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.openecomp.appc.bootstrap.file";
+ String DEFAULT_BOOTSTRAP_FILE_NAME = "appc.properties";
+ String PROPERTY_BOOTSTRAP_FILE_PATH = "org.openecomp.appc.bootstrap.path";
+ String DEFAULT_BOOTSTRAP_FILE_PATH = "${user.home},etc,../etc";
+ String PROPERTY_RESOURCE_BUNDLES = "org.openecomp.appc.resources";
+ String DEFAULT_RESOURCE_BUNDLES = "org/openecomp/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-common/src/main/java/org/openecomp/appc/configuration/ConfigurationFactory.java b/appc-common/src/main/java/org/openecomp/appc/configuration/ConfigurationFactory.java
new file mode 100644
index 000000000..bbfd90de1
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/configuration/ConfigurationFactory.java
@@ -0,0 +1,416 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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.Properties;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+import org.openecomp.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.openecomp.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.openecomp.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/openecomp/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().getApplicationLogger();
+
+ /**
+ * 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/openecomp/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<Object, Configuration>();
+
+ /**
+ * 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 t) {
+ logger.error("getConfiguration", t);
+ } finally {
+ writeLock.unlock();
+ }
+ readLock.lock();
+ }
+ return config;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * 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) {
+ ReadLock readLock = lock.readLock();
+ readLock.lock();
+ try {
+ DefaultConfiguration local = (DefaultConfiguration) localConfigs.get(owner);
+ if (local == null) {
+ readLock.unlock();
+ WriteLock writeLock = lock.writeLock();
+ writeLock.lock();
+ try {
+ local = (DefaultConfiguration) localConfigs.get(owner);
+ if (local == null) {
+ DefaultConfiguration global = (DefaultConfiguration) getConfiguration();
+ try {
+ local = (DefaultConfiguration) global.clone();
+ } catch (CloneNotSupportedException e) {
+ logger.error("getConfiguration", e);
+ }
+ localConfigs.put(owner, local);
+ }
+ } finally {
+ writeLock.unlock();
+ }
+ readLock.lock();
+ }
+ return local;
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * 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();
+ }
+ }
+
+ /**
+ * 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) {
+ // not much we can do since logger may not be configured yet
+ e.printStackTrace(System.out);
+ }
+ }
+ 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 {
+ stream.close();
+ } catch (IOException e) {
+ // not much we can do since logger may not be configured
+ // yet
+ e.printStackTrace(System.out);
+ }
+ }
+ }
+ }
+
+ 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-common/src/main/java/org/openecomp/appc/configuration/DefaultConfiguration.java b/appc-common/src/main/java/org/openecomp/appc/configuration/DefaultConfiguration.java
new file mode 100644
index 000000000..7af491724
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/configuration/DefaultConfiguration.java
@@ -0,0 +1,578 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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.openecomp.appc.encryption.EncryptionTool;
+import org.openecomp.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
+ * @version $Id$
+ */
+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.
+ */
+ public 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) {
+ if (value.startsWith(EncryptionTool.ENCRYPTED_VALUE_PREFIX)) {
+ try {
+ return EncryptionTool.getInstance().decrypt(value);
+ } catch (Throwable e) {
+ String out = "";
+ for (Provider p : Security.getProviders()) {
+ for (Service s : p.getServices()) {
+ String algo = s.getAlgorithm();
+ out +=
+ String.format("\n==Found Algorithm [ %s ] in provider [ %s ] and service [ %s ]", algo,
+ p.getName(), s.getClassName());
+ }
+ }
+ logger.debug(out);
+ 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) {
+ DefaultConfiguration other = (DefaultConfiguration) obj;
+
+ if ((this.properties.size() == other.properties.size())
+ && (this.properties.entrySet().containsAll(other.properties.entrySet()))
+ && (other.properties.entrySet().containsAll(this.properties.entrySet()))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 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 template;
+ }
+
+ // Decrypt the template if needed
+ // template = decrypt(template); DH: Do not assign values to parameters, bad form! Also, Sonar complains
+ // bitterly
+
+ StringBuffer buffer = new StringBuffer(decrypt(template));
+ Pattern pattern = Pattern.compile("\\$\\{([^\\}]+)\\}");
+ Matcher matcher = pattern.matcher(buffer);
+ while (matcher.find()) {
+ String variable = matcher.group(1);
+ String value = properties.getProperty(variable);
+ if (value == null) {
+ value = System.getProperty(variable);
+ }
+ if (value == null) {
+ value = "";
+ }
+ buffer.replace(matcher.start(), matcher.end(), value);
+
+ matcher.reset();
+ }
+ return buffer.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")).booleanValue();
+ }
+
+ /**
+ * 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.openecomp.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.openecomp.appc.configuration.Configuration#getDoubleProperty(java.lang.String)
+ */
+ @SuppressWarnings("nls")
+ @Override
+ public double getDoubleProperty(String key) {
+ try {
+ return Double.valueOf(getProperty(key, "0.0")).doubleValue();
+ } 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.openecomp.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.
+ * @returns The value of the property, or 0 if it does not exist or is invalid.
+ * @see org.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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.openecomp.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
+ * @returns True if the value is a boolean constant, or false if it does not exist or is not a correct string
+ * @see org.openecomp.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
+ * @returns True if the property is a valid representation of a double, or false if it does not exist or contains
+ * illegal characters.
+ * @see org.openecomp.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
+ * @returns True if the value is a valid integer string, or false if it does not exist or contains illegal
+ * characters.
+ * @see org.openecomp.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.openecomp.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) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 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.openecomp.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.openecomp.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-common/src/main/java/org/openecomp/appc/configuration/package.html b/appc-common/src/main/java/org/openecomp/appc/configuration/package.html
new file mode 100644
index 000000000..4460a9e5c
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/configuration/package.html
@@ -0,0 +1,170 @@
+<!--
+ ============LICENSE_START=======================================================
+ openECOMP : APP-C
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property. All rights
+ reserved.
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ============LICENSE_END=========================================================
+ -->
+
+<html>
+<head>
+<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>
diff --git a/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionException.java b/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionException.java
new file mode 100644
index 000000000..c21abc2b9
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionException.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.encryption;
+
+public class EncryptionException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8259594446628138378L;
+
+ public EncryptionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionTool.java b/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionTool.java
new file mode 100644
index 000000000..088fc8570
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/encryption/EncryptionTool.java
@@ -0,0 +1,215 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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() {
+ // encryptor = new BasicTextEncryptor();
+ // encryptor.setPassword(secret.toString());
+ 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());
+ // return encryptor.decrypt(encValue);
+ 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-common/src/main/java/org/openecomp/appc/encryption/HexHelper.java b/appc-common/src/main/java/org/openecomp/appc/encryption/HexHelper.java
new file mode 100644
index 000000000..01a602cf4
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/encryption/HexHelper.java
@@ -0,0 +1,149 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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(Character.valueOf('0'), Integer.valueOf(0));
+ TextToHex.put(Character.valueOf('1'), Integer.valueOf(1));
+ TextToHex.put(Character.valueOf('2'), Integer.valueOf(2));
+ TextToHex.put(Character.valueOf('3'), Integer.valueOf(3));
+ TextToHex.put(Character.valueOf('4'), Integer.valueOf(4));
+ TextToHex.put(Character.valueOf('5'), Integer.valueOf(5));
+ TextToHex.put(Character.valueOf('6'), Integer.valueOf(6));
+ TextToHex.put(Character.valueOf('7'), Integer.valueOf(7));
+ TextToHex.put(Character.valueOf('8'), Integer.valueOf(8));
+ TextToHex.put(Character.valueOf('9'), Integer.valueOf(9));
+ TextToHex.put(Character.valueOf('A'), Integer.valueOf(10));
+ TextToHex.put(Character.valueOf('B'), Integer.valueOf(11));
+ TextToHex.put(Character.valueOf('C'), Integer.valueOf(12));
+ TextToHex.put(Character.valueOf('D'), Integer.valueOf(13));
+ TextToHex.put(Character.valueOf('E'), Integer.valueOf(14));
+ TextToHex.put(Character.valueOf('F'), Integer.valueOf(15));
+ }
+
+ /**
+ * Default private constructor prevents instantiation
+ */
+ private HexHelper() {
+ // no-op
+ }
+
+ /**
+ * Converts an array of bytes to the equivalent string representation using hexadecimal notation and returning that
+ * representation in a StringBuffer.
+ *
+ * @param bytes
+ * The bytes to be converted to a hexadecimal string
+ * @return The string representation
+ */
+ public static StringBuffer convertBytesToHexSB(byte[] bytes) {
+ StringBuffer sb = new StringBuffer(bytes.length * 2);
+ int byteLen = bytes.length;
+ for (int index = 0; index < byteLen; index++) {
+ 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[((bytes[index] & 0xf0) >>> 4)];
+ sb.append(tempChar);
+
+ // Get the last 4 bits (low) Do bitwise logical AND to get rid of
+ // high nibble. Get char representation
+ tempChar = HEX_TABLE[(bytes[index] & 0x0f)];
+ sb.append(tempChar);
+ }
+ return sb;
+ }
+
+ /**
+ * 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) {
+ byte[] bytes = null;
+ byte high;
+ byte low;
+ char hexChar;
+
+ StringBuffer buffer = new StringBuffer(hexValue.toUpperCase());
+ if (buffer.length() % 2 != 0) {
+ LOG.warn("Invalid HEX value length. "
+ + "The length of the value has to be a multiple of 2. Prepending '0' value.");
+ buffer.insert(0, '0');
+ }
+ int hexLength = buffer.length();
+ int byteLength = hexLength / 2;
+
+ bytes = new byte[byteLength];
+ for (int index = 0; index < hexLength; index += 2) {
+ hexChar = buffer.charAt(index);
+ high = (TextToHex.get(Character.valueOf(hexChar))).byteValue();
+ high = (byte) (high << 4);
+ hexChar = buffer.charAt(index + 1);
+ low = (TextToHex.get(Character.valueOf(hexChar))).byteValue();
+ high = (byte) (high | low);
+ bytes[index / 2] = high;
+ }
+ return bytes;
+ }
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/exceptions/APPCException.java b/appc-common/src/main/java/org/openecomp/appc/exceptions/APPCException.java
new file mode 100644
index 000000000..bf3115f38
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/exceptions/APPCException.java
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/exceptions/UnknownProviderException.java b/appc-common/src/main/java/org/openecomp/appc/exceptions/UnknownProviderException.java
new file mode 100644
index 000000000..e73f9e5f7
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/exceptions/UnknownProviderException.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/i18n/Msg.java b/appc-common/src/main/java/org/openecomp/appc/i18n/Msg.java
new file mode 100644
index 000000000..3e4237258
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/i18n/Msg.java
@@ -0,0 +1,612 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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 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,
+
+ /**
+ * 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,
+
+ /**
+ * 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,
+
+ /**
+ * 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,
+
+ /**
+ * 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,
+
+ /**
+ * 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,
+
+ /**
+ * Stack {0} is being snapshoted...
+ */
+ SNAPSHOTING_STACK,
+
+ /**
+ * Stack {0} snapshoted, snapshot ID = [{1}].
+ */
+ STACK_SNAPSHOTED,
+
+ /**
+ * Stack {0} is being restored to snapshot {1}...
+ */
+ RESTORING_STACK,
+
+ /**
+ * Stack {0} is restored to snapshot {1}.
+ */
+ STACK_RESTORED,
+
+ /**
+ * 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;
+
+ /**
+ * Static initializer to ensure the resource bundles for this class are loaded...
+ */
+ static {
+ EELFResourceManager.loadMessageBundle("org/openecomp/appc/i18n/MessageResources");
+ }
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/logging/LoggingConstants.java b/appc-common/src/main/java/org/openecomp/appc/logging/LoggingConstants.java
new file mode 100644
index 000000000..dcc797138
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/logging/LoggingConstants.java
@@ -0,0 +1,70 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.logging;
+
+public class LoggingConstants {
+
+ public static class 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";
+ }
+
+ public static class StatusCodes {
+ public static final String COMPLETE = "COMPLETE";
+ public static final String ERROR = "ERROR";
+ }
+
+ public static class 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 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";
+ }
+
+ public static class TargetServiceNames{
+
+ public static class AAIServiceNames{
+ public static final String QUERY = "query";
+ public static final String GET_VNF_DATA = "getVnfData";
+ }
+
+ }
+
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/logging/LoggingUtils.java b/appc-common/src/main/java/org/openecomp/appc/logging/LoggingUtils.java
new file mode 100644
index 000000000..901ff3272
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/logging/LoggingUtils.java
@@ -0,0 +1,196 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.logging;
+
+import org.openecomp.appc.i18n.Msg;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+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.util.Date;
+import java.util.TimeZone;
+
+
+
+public class LoggingUtils {
+
+ private final static EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+ private final static EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ private final static EELFLogger metricLogger = EELFManager.getInstance().getMetricsLogger();
+
+ 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(Date beginTimeStamp, Date 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 logMetricsMessage(Date beginTimeStamp, Date 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(Date beginTimeStamp, Date endTimeStamp, String code, String responseDescription, String className) {
+ populateTimeContext(beginTimeStamp, endTimeStamp);
+ MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, code);
+ MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, code.equals("100") || code.equals("400") ?
+ 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(Date beginTimeStamp, Date 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(Date beginTimeStamp, Date endTimeStamp) {
+ String beginTime = "";
+ String endTime = "";
+ String elapsedTime = "";
+
+ if (beginTimeStamp != null && endTimeStamp != null) {
+ elapsedTime = String.valueOf(endTimeStamp.getTime() - beginTimeStamp.getTime());
+ 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(Date timeStamp) {
+ DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
+ TimeZone tz = TimeZone.getTimeZone("UTC");
+ df.setTimeZone(tz);
+ return df.format(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-common/src/main/java/org/openecomp/appc/pool/Allocator.java b/appc-common/src/main/java/org/openecomp/appc/pool/Allocator.java
new file mode 100644
index 000000000..8301cb7a5
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/Allocator.java
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/CacheManagement.java b/appc-common/src/main/java/org/openecomp/appc/pool/CacheManagement.java
new file mode 100644
index 000000000..10c007548
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/CacheManagement.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+package org.openecomp.appc.pool;
+
+public interface CacheManagement {
+
+ /**
+ * @return The object that is actually being wrapped and cached
+ */
+ Object getWrappedObject();
+
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/pool/CachedElement.java b/appc-common/src/main/java/org/openecomp/appc/pool/CachedElement.java
new file mode 100644
index 000000000..558b2a33a
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/CachedElement.java
@@ -0,0 +1,208 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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 Throwable {
+ Object result = null;
+
+ if (method.getName().equals("close")) {
+ if (released.compareAndSet(false, true)) {
+ if (!pool.isDrained()) {
+ pool.release((T) proxy);
+ }
+ }
+ } else if (method.getName().equals("equals")) {
+ CacheManagement cm = (CacheManagement) proxy;
+ T other = (T) cm.getWrappedObject();
+ result = element.equals(other);
+ } else if (method.getName().equals("getWrappedObject")) {
+ return element;
+ } else {
+ result = method.invoke(element, args);
+ }
+
+ return result;
+ }
+
+ /**
+ * This method is used to be able to access the wrapped object underneath the dynamic proxy
+ *
+ * @see org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/Destructor.java b/appc-common/src/main/java/org/openecomp/appc/pool/Destructor.java
new file mode 100644
index 000000000..40d2f1170
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/Destructor.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/Pool.java b/appc-common/src/main/java/org/openecomp/appc/pool/Pool.java
new file mode 100644
index 000000000..4c5b92474
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/Pool.java
@@ -0,0 +1,371 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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();
+ }
+
+ // return obj;
+
+ /*
+ * 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-common/src/main/java/org/openecomp/appc/pool/PoolDrainedException.java b/appc-common/src/main/java/org/openecomp/appc/pool/PoolDrainedException.java
new file mode 100644
index 000000000..71edb493c
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/PoolDrainedException.java
@@ -0,0 +1,48 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/PoolException.java b/appc-common/src/main/java/org/openecomp/appc/pool/PoolException.java
new file mode 100644
index 000000000..0ba88b68e
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/PoolException.java
@@ -0,0 +1,89 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/PoolExtensionException.java b/appc-common/src/main/java/org/openecomp/appc/pool/PoolExtensionException.java
new file mode 100644
index 000000000..64f338105
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/PoolExtensionException.java
@@ -0,0 +1,46 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/pool/PoolSpecificationException.java b/appc-common/src/main/java/org/openecomp/appc/pool/PoolSpecificationException.java
new file mode 100644
index 000000000..f46ca374a
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/pool/PoolSpecificationException.java
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/util/JsonUtil.java b/appc-common/src/main/java/org/openecomp/appc/util/JsonUtil.java
new file mode 100644
index 000000000..6c5623da1
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/JsonUtil.java
@@ -0,0 +1,44 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.util;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+public class JsonUtil {
+ /**
+ * @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 {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Map readValueMap = objectMapper.readValue(valueAsString,Map.class);
+ return org.openecomp.appc.util.ObjectMapper.map(readValueMap);
+ }
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/util/MessageFormatter.java b/appc-common/src/main/java/org/openecomp/appc/util/MessageFormatter.java
new file mode 100644
index 000000000..39c9a67e3
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/MessageFormatter.java
@@ -0,0 +1,83 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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";
+ private final static String paramRegex = "\\$\\{(?<paramName>[^}$]+)\\}"; //start with ${ and after there is one or more characters that are not $ and not } and ended with }
+
+
+ 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() + "\\}", String.valueOf(entry.getValue()));
+ }
+/* } else {
+ StringBuilder builder = new StringBuilder(formattedMessage);
+ builder.append("; output params: [");
+ for (Map.Entry<String, Object> entry : params.entrySet()) {
+ builder.append(entry.getKey()).append(":").append(String.valueOf(entry.getValue())).append("; ");
+ }
+ builder.append("]");
+ formattedMessage = builder.toString();*/
+ }
+
+ return formattedMessage;
+ }
+
+ public static List<String> getParamsNamesList(String messageTemplate) {
+ List<String> paramsNames = null;
+ if(!StringUtils.isEmpty(messageTemplate)){
+ paramsNames = new ArrayList<String>();
+ 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-common/src/main/java/org/openecomp/appc/util/ObjectMapper.java b/appc-common/src/main/java/org/openecomp/appc/util/ObjectMapper.java
new file mode 100644
index 000000000..4d55d4e11
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/ObjectMapper.java
@@ -0,0 +1,98 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/util/PathContext.java b/appc-common/src/main/java/org/openecomp/appc/util/PathContext.java
new file mode 100644
index 000000000..5565afd2f
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/PathContext.java
@@ -0,0 +1,100 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/util/StreamHelper.java b/appc-common/src/main/java/org/openecomp/appc/util/StreamHelper.java
new file mode 100644
index 000000000..8f80b8117
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/StreamHelper.java
@@ -0,0 +1,60 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/util/StringHelper.java b/appc-common/src/main/java/org/openecomp/appc/util/StringHelper.java
new file mode 100644
index 000000000..0f9188694
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/StringHelper.java
@@ -0,0 +1,592 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.appc.util;
+
+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 {
+
+ 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 ".*";
+ }
+ boolean appendEOL = false;
+ StringBuffer buffer = new StringBuffer(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(buffer);
+ int position = 0;
+ while (matcher.find(position)) {
+ buffer.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(buffer);
+ position = 0;
+ while (matcher.find(position)) {
+ String metachar = buffer.substring(matcher.start(), matcher.end());
+ if (metachar.equals("*")) {
+ buffer.replace(matcher.start(), matcher.end(), ".*");
+ position = matcher.end() + 1;
+ if (matcher.end() < buffer.length() - 1) {
+ appendEOL = true;
+ }
+ } else if (metachar.equals("+")) {
+ buffer.replace(matcher.start(), matcher.end(), ".");
+ position = matcher.end();
+ if (matcher.end() == buffer.length()) {
+ appendEOL = true;
+ }
+ }
+ }
+
+ /*
+ * 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 (appendEOL) {
+ buffer.append("$");
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * 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 equals(String a, String b) {
+ return equals(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 equals(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 equals(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) {
+ StringBuffer buffer = new StringBuffer(name == null ? "" : name);
+ Pattern pattern = Pattern.compile("[^a-z0-9]+", Pattern.CASE_INSENSITIVE);
+ Matcher matcher = pattern.matcher(buffer);
+ int position = 0;
+ while (matcher.find(position)) {
+ buffer.delete(matcher.start(), matcher.end());
+ position = matcher.start();
+ }
+
+ if (buffer.length() < minLen) {
+ for (int i = buffer.length(); i <= minLen; i++) {
+ buffer.append("A");
+ }
+ }
+
+ /*
+ * Remove out of the center of the name to preserve start and end and result in a string of max len
+ */
+ if (buffer.length() > maxLen) {
+ int excess = buffer.length() - maxLen;
+ int left = maxLen / 2;
+
+ buffer.delete(left, excess + left);
+ }
+
+ return buffer.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");
+ StringBuffer buffer = new StringBuffer();
+ for (String token : tokens) {
+ buffer.append(token.trim());
+ }
+ return buffer.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;
+ }
+
+ StringBuffer buffer = new StringBuffer(content);
+ Pattern pattern = Pattern.compile("^(\n)[^\r]|[^\r](\n)[^\r]|[^\r](\n)$");
+ Matcher matcher = pattern.matcher(buffer);
+ 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);
+ }
+
+ buffer.replace(index, index + 1, "\r\n");
+ position = index + 1;
+ }
+
+ return buffer.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;
+ }
+
+ StringBuffer buffer = new StringBuffer(content);
+ Pattern pattern = Pattern.compile("\r\n|\n\r");
+ Matcher matcher = pattern.matcher(buffer);
+ int position = 0;
+ while (matcher.find(position)) {
+ buffer.replace(matcher.start(), matcher.end(), "\n");
+ position = matcher.start();
+ }
+
+ return buffer.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 sequence;
+ }
+
+ StringBuffer buffer = new StringBuffer(sequence);
+
+ for (int index = 0; index < buffer.length(); index++) {
+ char ch = buffer.charAt(index);
+
+ int position = match.indexOf(ch);
+ if (position == -1) {
+ continue;
+ }
+
+ if (position >= replacement.length()) {
+ position %= replacement.length();
+ }
+ buffer.setCharAt(index, replacement.charAt(position));
+ }
+
+ return buffer.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;
+ }
+
+ StringBuffer buffer = new StringBuffer(name);
+ for (int index = 0; index < buffer.length(); index++) {
+ char ch = buffer.charAt(index);
+
+ if ((index == 0 && !Character.isJavaIdentifierStart(ch)) || (!Character.isJavaIdentifierPart(ch))) {
+ buffer.setCharAt(index, '_');
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * 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 sequence;
+ }
+
+ StringBuffer buffer = new StringBuffer(sequence);
+ for (int index = 0; index < buffer.length(); index++) {
+ char ch = buffer.charAt(index);
+ if (legal.indexOf(ch) == -1) {
+ buffer.setCharAt(index, replacement);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Private constructor to prevent instantiation of this class - All methods are static!
+ */
+ private StringHelper() {
+
+ }
+
+ /**
+ * @param list
+ * The list of elements
+ * @return The list of elements formatted as a comma-delimited list
+ */
+ public static String asList(List<String> list) {
+ StringBuffer buffer = new StringBuffer();
+ if (list != null) {
+ if (list.size() == 1) {
+ buffer.append(list.get(0));
+ } else {
+ for (String element : list) {
+ buffer.append(element);
+ buffer.append(", ");
+ }
+
+ if (buffer.length() > 2) {
+ buffer.delete(buffer.length() - 2, buffer.length());
+ }
+ }
+ }
+ return buffer.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) {
+ StringBuffer buffer = new StringBuffer();
+ if (map != null) {
+ Set<String> keys = map.keySet();
+ for (String key : keys) {
+ buffer.append(String.format("%s=%s, ", key, map.get(key)));
+ }
+
+ if (buffer.length() > 2) {
+ buffer.delete(buffer.length() - 2, buffer.length());
+ }
+ }
+ return buffer.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
+ nfe.printStackTrace();
+ }
+ }
+
+ // 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
+ }
+ }
+
+ // 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-common/src/main/java/org/openecomp/appc/util/StructuredPropertyHelper.java b/appc-common/src/main/java/org/openecomp/appc/util/StructuredPropertyHelper.java
new file mode 100644
index 000000000..1705547c1
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/StructuredPropertyHelper.java
@@ -0,0 +1,252 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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) {
+ 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-common/src/main/java/org/openecomp/appc/util/Time.java b/appc-common/src/main/java/org/openecomp/appc/util/Time.java
new file mode 100644
index 000000000..147ae2ca7
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/Time.java
@@ -0,0 +1,608 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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));
+ }
+}
diff --git a/appc-common/src/main/java/org/openecomp/appc/util/UnmodifiableProperties.java b/appc-common/src/main/java/org/openecomp/appc/util/UnmodifiableProperties.java
new file mode 100644
index 000000000..50bc96ff5
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/UnmodifiableProperties.java
@@ -0,0 +1,353 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/main/java/org/openecomp/appc/util/httpClient.java b/appc-common/src/main/java/org/openecomp/appc/util/httpClient.java
new file mode 100644
index 000000000..0847c4091
--- /dev/null
+++ b/appc-common/src/main/java/org/openecomp/appc/util/httpClient.java
@@ -0,0 +1,207 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.util;
+
+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.HttpClient;
+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.DefaultHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.openecomp.appc.configuration.Configuration;
+import org.openecomp.appc.configuration.ConfigurationFactory;
+import org.openecomp.appc.exceptions.APPCException;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+
+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;
+ String result;
+
+ try {
+ HttpResponse response = client.execute(delete);
+ httpCode = response.getStatusLine().getStatusCode();
+ } catch (IOException e) {
+ throw new APPCException(e);
+ }
+
+ return httpCode;
+ }
+}
diff --git a/appc-common/src/main/resources/org/openecomp/appc/i18n/MessageResources.properties b/appc-common/src/main/resources/org/openecomp/appc/i18n/MessageResources.properties
new file mode 100644
index 000000000..0c571cbae
--- /dev/null
+++ b/appc-common/src/main/resources/org/openecomp/appc/i18n/MessageResources.properties
@@ -0,0 +1,792 @@
+###
+# ============LICENSE_START=======================================================
+# openECOMP : APP-C
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# This 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.openecomp.appc.bootstrap.path</em>. The \
+ property file name defaults to <em>appc.properties</em> and can also be \
+ overridden by the <em>org.openecomp.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.openecomp.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.openecomp.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.
+
+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.
+
+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.|\
+ .
+
+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.|\
+ .
+
+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
diff --git a/appc-common/src/main/resources/org/openecomp/appc/i18n/auth.properties b/appc-common/src/main/resources/org/openecomp/appc/i18n/auth.properties
new file mode 100644
index 000000000..bdb5af244
--- /dev/null
+++ b/appc-common/src/main/resources/org/openecomp/appc/i18n/auth.properties
@@ -0,0 +1,23 @@
+###
+# ============LICENSE_START=======================================================
+# openECOMP : APP-C
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+username=admin
+password=admin
diff --git a/appc-common/src/test/java/org/openecomp/appc/concurrent/TestSignal.java b/appc-common/src/test/java/org/openecomp/appc/concurrent/TestSignal.java
new file mode 100644
index 000000000..1751b62d9
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/concurrent/TestSignal.java
@@ -0,0 +1,132 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.concurrent;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Test;
+import org.openecomp.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) {
+ e.printStackTrace();
+ }
+ }
+
+ public boolean isCompleted() {
+ return completed;
+ }
+
+ public Signal getSignal() {
+ return signal;
+ }
+ }
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/encryption/TestEncryption.java b/appc-common/src/test/java/org/openecomp/appc/encryption/TestEncryption.java
new file mode 100644
index 000000000..e82a44352
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/encryption/TestEncryption.java
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.encryption;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Test;
+import org.openecomp.appc.encryption.EncryptionTool;
+
+public class TestEncryption {
+
+ @Test
+ public void testEncryptionDecryption() {
+ String plain = "AppC";
+ String enc = EncryptionTool.getInstance().encrypt(plain);
+ assertNotEquals(plain, enc);
+ String dec = EncryptionTool.getInstance().decrypt(enc);
+ assertNotEquals(enc, dec);
+ assertEquals(plain, dec);
+ System.out.println(String.format("%s = [%s]", plain, enc));
+ }
+
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/pool/CachedElementTest.java b/appc-common/src/test/java/org/openecomp/appc/pool/CachedElementTest.java
new file mode 100644
index 000000000..423d33952
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/pool/CachedElementTest.java
@@ -0,0 +1,273 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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.openecomp.appc.pool.Allocator;
+import org.openecomp.appc.pool.CachedElement;
+import org.openecomp.appc.pool.Destructor;
+import org.openecomp.appc.pool.Pool;
+import org.openecomp.appc.pool.PoolDrainedException;
+import org.openecomp.appc.pool.PoolExtensionException;
+import org.openecomp.appc.pool.PoolSpecificationException;
+import org.openecomp.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.openecomp.appc.pool.Allocator#allocate(org.openecomp.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.openecomp.appc.pool.Destructor#destroy(java.io.Closeable, org.openecomp.appc.pool.Pool)
+ */
+ @Override
+ public void destroy(Testable obj, Pool<Testable> pool) {
+ destroyCount++;
+ }
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/pool/Element.java b/appc-common/src/test/java/org/openecomp/appc/pool/Element.java
new file mode 100644
index 000000000..61c302432
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/pool/Element.java
@@ -0,0 +1,75 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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-common/src/test/java/org/openecomp/appc/pool/PoolTest.java b/appc-common/src/test/java/org/openecomp/appc/pool/PoolTest.java
new file mode 100644
index 000000000..97414804c
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/pool/PoolTest.java
@@ -0,0 +1,320 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.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.openecomp.appc.pool.Allocator;
+import org.openecomp.appc.pool.Destructor;
+import org.openecomp.appc.pool.Pool;
+import org.openecomp.appc.pool.PoolDrainedException;
+import org.openecomp.appc.pool.PoolExtensionException;
+import org.openecomp.appc.pool.PoolSpecificationException;
+import org.openecomp.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.openecomp.appc.pool.Destructor#destroy(java.io.Closeable, org.openecomp.appc.pool.Pool)
+ */
+ @Override
+ public void destroy(Testable obj, Pool<Testable> pool) {
+ destroyCount++;
+ try {
+ obj.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @see org.openecomp.appc.pool.Allocator#allocate(org.openecomp.appc.pool.Pool)
+ */
+ @Override
+ public Testable allocate(Pool<Testable> pool) {
+ Testable e = new Element(index++);
+
+ return e;
+ }
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/pool/Testable.java b/appc-common/src/test/java/org/openecomp/appc/pool/Testable.java
new file mode 100644
index 000000000..61adf91d3
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/pool/Testable.java
@@ -0,0 +1,32 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.pool;
+
+import java.io.Closeable;
+
+public interface Testable extends Closeable {
+
+ Integer getId();
+
+ Boolean isClosed();
+}
+
diff --git a/appc-common/src/test/java/org/openecomp/appc/util/TestJsonUtil.java b/appc-common/src/test/java/org/openecomp/appc/util/TestJsonUtil.java
new file mode 100644
index 000000000..d78049e12
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/util/TestJsonUtil.java
@@ -0,0 +1,71 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openecomp.appc.util.JsonUtil;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+
+public class TestJsonUtil {
+
+ @Test
+ public void testConvertJsonStringToFlatMap() {
+ try {
+ String jsonString = "{\"A\":\"A-value\",\"B\":{\"C\":\"B.C-value\",\"D\":\"B.D-value\"}}";
+ Map<String, String> flatMap = JsonUtil.convertJsonStringToFlatMap(jsonString);
+ assertNotNull(flatMap);
+ 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);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Assert.fail(e.toString());
+ }
+ }
+
+ @Test
+ public void testConvertJsonStringToFlatMapWithInnerJson() {
+ try {
+ String jsonString = "{\"A\":\"A-value\",\"B\":\"{\\\"C\\\":\\\"C-value\\\",\\\"D\\\":\\\"D-value\\\"}\"}";
+ Map<String, String> flatMap = JsonUtil.convertJsonStringToFlatMap(jsonString);
+ assertNotNull(flatMap);
+ Map<String, String> expectedMap = new HashMap<>();
+ expectedMap.put("A","A-value");
+ expectedMap.put("B","{\"C\":\"C-value\",\"D\":\"D-value\"}");
+ assertEquals(expectedMap,flatMap);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Assert.fail(e.toString());
+ }
+ }
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/util/TestStreamHelper.java b/appc-common/src/test/java/org/openecomp/appc/util/TestStreamHelper.java
new file mode 100644
index 000000000..d0b93a3c1
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/util/TestStreamHelper.java
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.util;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+
+import org.junit.Test;
+import org.openecomp.appc.util.StreamHelper;
+
+public class TestStreamHelper {
+
+ 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 testStreamHelperNullStream() {
+ assertNotNull(StreamHelper.getStringFromInputStream(null));
+ assertEquals("", StreamHelper.getStringFromInputStream(null));
+ }
+
+ @Test
+ public void testStreamHelperByteArrayStream() {
+ ByteArrayInputStream in = new ByteArrayInputStream(text.getBytes());
+
+ assertEquals(text, StreamHelper.getStringFromInputStream(in));
+ }
+
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/util/TestStringHelper.java b/appc-common/src/test/java/org/openecomp/appc/util/TestStringHelper.java
new file mode 100644
index 000000000..0afd4cb43
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/util/TestStringHelper.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+
+
+package org.openecomp.appc.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Properties;
+
+import org.junit.Test;
+import org.openecomp.appc.util.StringHelper;
+
+
+public class TestStringHelper {
+
+ @Test
+ public void testAsListWithNullList() {
+ String value = StringHelper.asList((String[]) null);
+ assertNotNull(value);
+ assertEquals("[]", value);
+ }
+
+ @Test
+ public void testAsListWithEmptyList() {
+ String value = StringHelper.asList(new String[] {});
+ assertNotNull(value);
+ assertEquals("[]", value);
+ }
+
+ @Test
+ public void testAsListWithSingleValue() {
+ String value = StringHelper.asList("one");
+ assertNotNull(value);
+ assertEquals("[one]", value);
+ }
+
+ @Test
+ public void testAsListWithTwoValues() {
+ String value = StringHelper.asList("one", "two");
+ assertNotNull(value);
+ assertEquals("[one,two]", value);
+ }
+
+ @Test
+ public void testAsListWithFiveValues() {
+ String value = StringHelper.asList("one", "two", "three", "four", "five");
+ assertNotNull(value);
+ assertEquals("[one,two,three,four,five]", value);
+ }
+
+ @Test
+ public void testPropertiesToString() {
+ String key1 = "key1";
+ String val1 = "val1";
+ String key2 = "key2";
+ String val2 = "val2";
+
+ assertEquals(null, StringHelper.propertiesToString(null));
+
+ Properties props = new Properties();
+
+ String result = StringHelper.propertiesToString(props);
+ assertNotNull(result);
+ assertEquals("[ ]", result);
+
+ props.setProperty(key1, val1);
+ result = StringHelper.propertiesToString(props);
+ assertNotNull(result);
+ assertTrue(result.contains(key1));
+ assertTrue(result.contains(val1));
+ assertTrue(result.lastIndexOf(",") < result.length() - 3); // No trailing comma
+
+ props.setProperty(key2, val2);
+ result = StringHelper.propertiesToString(props);
+ assertNotNull(result);
+ assertTrue(result.contains(key1));
+ assertTrue(result.contains(val1));
+ assertTrue(result.contains(key2));
+ assertTrue(result.contains(val2));
+ assertTrue(result.lastIndexOf(",") < result.length() - 3); // No trailing comma
+ }
+}
diff --git a/appc-common/src/test/java/org/openecomp/appc/util/TestStructuredPropertyHelper.java b/appc-common/src/test/java/org/openecomp/appc/util/TestStructuredPropertyHelper.java
new file mode 100644
index 000000000..35541277f
--- /dev/null
+++ b/appc-common/src/test/java/org/openecomp/appc/util/TestStructuredPropertyHelper.java
@@ -0,0 +1,233 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.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.openecomp.appc.util.StructuredPropertyHelper;
+import org.openecomp.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);
+ }
+}
diff --git a/appc-common/src/test/resources/org/openecomp/appc/i18n/TestAdditionalResources.properties b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestAdditionalResources.properties
new file mode 100644
index 000000000..020ea7d28
--- /dev/null
+++ b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestAdditionalResources.properties
@@ -0,0 +1,22 @@
+###
+# ============LICENSE_START=======================================================
+# openECOMP : APP-C
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+ADDITIONAL_RESOURCE=This is a message loaded from an additional resource bundle
diff --git a/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_de.properties b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_de.properties
new file mode 100644
index 000000000..01bc87ac6
--- /dev/null
+++ b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_de.properties
@@ -0,0 +1,26 @@
+###
+# ============LICENSE_START=======================================================
+# openECOMP : APP-C
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+# Message bundle for German (language de, no specific country)
+#
+MESSAGE_TEST=Eine Nachricht f�r Unit-Tests den Ressource-Manager, arg0 = {0}, arg1 = {1}, arg2 = {2}
+TEST_001=Dies ist eine Testnachricht ohne Eins�tze bearbeitet werden!
diff --git a/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_en_US.properties b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_en_US.properties
new file mode 100644
index 000000000..db9be7b5e
--- /dev/null
+++ b/appc-common/src/test/resources/org/openecomp/appc/i18n/TestResources_en_US.properties
@@ -0,0 +1,26 @@
+###
+# ============LICENSE_START=======================================================
+# openECOMP : APP-C
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights
+# reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+#
+# 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!