diff options
Diffstat (limited to 'core/utils/provider')
21 files changed, 2505 insertions, 3 deletions
diff --git a/core/utils/provider/pom.xml b/core/utils/provider/pom.xml index 476448775..bd85ff3a1 100644 --- a/core/utils/provider/pom.xml +++ b/core/utils/provider/pom.xml @@ -59,6 +59,26 @@ <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-reflect</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito2</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/StructuredPropertyHelper.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/StructuredPropertyHelper.java new file mode 100644 index 000000000..c9fc56c34 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/StructuredPropertyHelper.java @@ -0,0 +1,257 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils; + +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; + } + + StringBuilder builder = new StringBuilder(token.trim()); + Pattern pattern = Pattern.compile("([^0-9]+)([0-9]*)"); + Matcher matcher = pattern.matcher(builder); + if (matcher.matches()) { + String nameRoot = matcher.group(1); + String ordinal = matcher.group(2); + if (ordinal != null && ordinal.length() > 0) { + int i = Integer.parseInt(ordinal); + builder.setLength(0); + builder.append(nameRoot); + builder.append(Integer.toString(i)); + } + } + return builder.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 Object#hashCode() + */ + @Override + public int hashCode() { + return name.hashCode() + (value != null ? value.hashCode() : children.hashCode()); + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object obj) { + if (obj == null) + return false; + if (this.getClass() != obj.getClass()) + return false; + + Node other = (Node) obj; + boolean result = name.equals(other.name); + + if (value == null) { + result &= other.value == null; + } else { + result &= value.equals(other.value); + } + if (children == null) { + result &= other.children == null; + } else { + result &= children.equals(other.children); + } + return result; + } + + /** + * @see 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(Node o) { + return name.compareTo(o.name); + } + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java index 05c132d0f..9f0289458 100644 --- a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/configuration/ConfigurationFactory.java @@ -124,7 +124,7 @@ public final class ConfigurationFactory { /** * The default properties resource to be loaded */ - private static final String DEFAULT_PROPERTIES = "org/onap/appc/default.properties"; + private static final String DEFAULT_PROPERTIES = "default.properties"; /** * This collection allows for special configurations to be created and maintained, organized by @@ -301,8 +301,7 @@ public final class ConfigurationFactory { /* * Load the defaults (if any are present) */ - InputStream in = Thread.currentThread().getContextClassLoader() - .getResourceAsStream(DEFAULT_PROPERTIES); + InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(DEFAULT_PROPERTIES); if (in != null) { logger.info(Msg.LOADING_DEFAULTS, DEFAULT_PROPERTIES); try { diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Allocator.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Allocator.java new file mode 100644 index 000000000..a9c781f65 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Allocator.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.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(org.onap.ccsdk.sli.core.utils.pool.Pool<T> pool); +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CacheManagement.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CacheManagement.java new file mode 100644 index 000000000..d3d47e759 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CacheManagement.java @@ -0,0 +1,33 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +public interface CacheManagement { + + /** + * @return The object that is actually being wrapped and cached + */ + Object getWrappedObject(); + +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CachedElement.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CachedElement.java new file mode 100644 index 000000000..2816edd20 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/CachedElement.java @@ -0,0 +1,217 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Modifications Copyright (C) 2019 IBM + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +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 Closeable} interface by + * using a dynamic proxy. + */ + +public class CachedElement<T extends Closeable> + implements Closeable, InvocationHandler, CacheManagement { + private static final EELFLogger LOG = EELFManager.getInstance().getLogger(CachedElement.class); + + /** + * 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.isAssignableFrom(CacheManagement.class)) { + 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) { + LOG.error("Pool is empty", e); + } + } + + /** + * 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 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 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 InvocationHandler#invoke(Object, Method, + * Object[]) + */ + @SuppressWarnings({"unchecked", "nls"}) + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Exception { + Object result = null; + + switch (method.getName()) { + case "close": + if (released.compareAndSet(false, true) && !pool.isDrained()) { + pool.release((T) proxy); + } + break; + case "equals": + CacheManagement cm = (CacheManagement) proxy; + T other = (T) cm.getWrappedObject(); + result = element.equals(other); + break; + case "getWrappedObject": + return element; + default: + result = method.invoke(element, args); + break; + } + + return result; + } + + /** + * This method is used to be able to access the wrapped object underneath the dynamic proxy + * + * @see org.onap.ccsdk.sli.core.utils.pool.CacheManagement#getWrappedObject() + */ + @Override + public T getWrappedObject() { + return element; + } + + @SuppressWarnings("nls") + @Override + public String toString() { + return element == null ? "null" : element.toString(); + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Destructor.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Destructor.java new file mode 100644 index 000000000..10d94e13d --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Destructor.java @@ -0,0 +1,44 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.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/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Pool.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Pool.java new file mode 100644 index 000000000..8ebdc8575 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/Pool.java @@ -0,0 +1,368 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +import java.io.Closeable; +import java.util.ArrayDeque; +import java.util.ArrayList; +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 org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.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(org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.PoolExtensionException + * If the pool cannot be extended + * @throws org.onap.ccsdk.sli.core.utils.pool.PoolDrainedException + * If the caller is trying to reserve an element from a drained pool + */ + @SuppressWarnings("unchecked") + public T reserve() throws org.onap.ccsdk.sli.core.utils.pool.PoolExtensionException, org.onap.ccsdk.sli.core.utils.pool.PoolDrainedException { + if (isDrained()) { + throw new org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.PoolExtensionException(String.format("Unable to add " + + "more elements, pool is at maximum size of %d", maxPool)); + } else { + extend(1); + } + } + + obj = free.removeFirst(); + allocated.add(obj); + } finally { + writeLock.unlock(); + } + + /* + * Now that we have the real object, lets wrap it in a dynamic proxy so that we can intercept the close call and + * just return the context to the free pool. obj.getClass().getInterfaces(). We need to find ALL interfaces that + * the object (and all superclasses) implement and have the proxy implement them too + */ + Class<?> cls = obj.getClass(); + Class<?>[] array; + List<Class<?>> interfaces = new ArrayList<Class<?>>(); + while (!cls.equals(Object.class)) { + array = cls.getInterfaces(); + for (Class<?> item : array) { + if (!interfaces.contains(item)) { + interfaces.add(item); + } + } + cls = cls.getSuperclass(); + } + array = new Class<?>[interfaces.size()]; + array = interfaces.toArray(array); + return org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.PoolDrainedException + * If the caller is trying to release an element to a drained pool + */ + public void release(T obj) throws org.onap.ccsdk.sli.core.utils.pool.PoolDrainedException { + if (isDrained()) { + throw new org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.PoolExtensionException + * if the pool cannot be extended because no allocator has been specified. + */ + private void extend(int count) throws org.onap.ccsdk.sli.core.utils.pool.PoolExtensionException { + if (allocator == null) { + throw new org.onap.ccsdk.sli.core.utils.pool.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 org.onap.ccsdk.sli.core.utils.pool.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/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedException.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedException.java new file mode 100644 index 000000000..163298e49 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedException.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.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/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolException.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolException.java new file mode 100644 index 000000000..110d08bba --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolException.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.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/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionException.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionException.java new file mode 100644 index 000000000..c326197fb --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionException.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +/** + * An error occurred trying to extend the pool + * + */ +public class PoolExtensionException extends org.onap.ccsdk.sli.core.utils.pool.PoolException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * PoolExtensionException constructor + * + * @param msg + * The error message + */ + public PoolExtensionException(String msg) { + super(msg); + } +} diff --git a/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolSpecificationException.java b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolSpecificationException.java new file mode 100644 index 000000000..3bc5f51e6 --- /dev/null +++ b/core/utils/provider/src/main/java/org/onap/ccsdk/sli/core/utils/pool/PoolSpecificationException.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +/** + * This exception is thrown whenever the pool is not specified correctly + * + */ +public class PoolSpecificationException extends org.onap.ccsdk.sli.core.utils.pool.PoolException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * PoolSpecificationException constructor + * + * @param msg + * The error message + */ + public PoolSpecificationException(String msg) { + super(msg); + } + +} diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstantsTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstantsTest.java new file mode 100644 index 000000000..e8767a550 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingConstantsTest.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.logging; + +import org.junit.Test; +import org.powermock.reflect.Whitebox; + +public class LoggingConstantsTest { + @Test (expected = IllegalAccessError.class) + public void testConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.class); + } + + @Test (expected = IllegalAccessError.class) + public void testMdcKeysConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.MDCKeys.class); + } + + @Test (expected = IllegalAccessError.class) + public void testStatusCodesConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.StatusCodes.class); + } + + @Test (expected = IllegalAccessError.class) + public void testTargetNamesConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.TargetNames.class); + } + + @Test (expected = IllegalAccessError.class) + public void testTargetServiceNamesConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.TargetServiceNames.class); + } + + @Test (expected = IllegalAccessError.class) + public void testAAIServiceNamesConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingConstants.TargetServiceNames.AAIServiceNames.class); + } +} diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtilsTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtilsTest.java new file mode 100644 index 000000000..3c1708b42 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/logging/LoggingUtilsTest.java @@ -0,0 +1,357 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.logging; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.lang.reflect.Method; +import java.time.Instant; +import org.junit.Test; +import org.powermock.reflect.Whitebox; +import org.slf4j.MDC; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +public class LoggingUtilsTest { + @Test(expected = IllegalAccessError.class) + public void testConstructor() throws Exception { + Whitebox.invokeConstructor(LoggingUtils.class); + } + + @Test + public void testLogErrorMessageStringStringStringStringStringString() { + try { + LoggingUtils.logErrorMessage("ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking logErrorMessage: " + e.toString()); + } + } + + @Test + public void testLogErrorMessageStringStringStringString() { + try { + LoggingUtils.logErrorMessage("TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking logErrorMessage: " + e.toString()); + } + } + + @Test + public void testLogErrorMessageStringStringString() { + try { + LoggingUtils.logErrorMessage("TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking logErrorMessage: " + e.toString()); + } + } + + @Test + public void testLogError() { + try { + Class<?>[] paramString = { String.class, String.class, String.class, String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("logError", paramString); + m.setAccessible(true); + m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICE_NAME", "ADDITIONAL_MESSAGE", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking logError: " + e.toString()); + } + } + + @Test + public void testLogAuditMessage() { + try { + Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("logAuditMessage", paramString); + m.setAccessible(true); + java.util.Date timestamp = new java.util.Date(); + m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking logAuditMessage: " + e.toString()); + } + } + + @Test + public void testAuditInfo() { + try { + EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + auditLogger.info("Audit logging test info"); + } catch (Exception e) { + fail("Exception invoking testAuditInfo: " + e.toString()); + } + } + + @Test + public void testAuditWarn() { + try { + EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + auditLogger.warn("Audit logging test warning"); + } catch (Exception e) { + fail("Exception invoking testAuditWarn: " + e.toString()); + } + } + + @Test + public void testLogMetricsMessage() { + try { + java.util.Date timestamp = new java.util.Date(); + LoggingUtils.logMetricsMessage(timestamp.toInstant(), timestamp.toInstant(), "TARGET_ENTITY", "TARGET_SERVICE_NAME", "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME"); + assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + + } catch (Exception e) { + fail("Exception invoking logMetricsMessage: " + e.toString()); + } + } + + @Test + public void testPopulateAuditLogContext() { + try { + Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateAuditLogContext", paramString); + m.setAccessible(true); + java.util.Date timestamp = new java.util.Date(); + m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "100", "RESPONSE_DESCRIPTION", "CLASS_NAME"); + assertEquals("COMPLETE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + assertEquals("100", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)); + assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking populateAuditLogContext: " + e.toString()); + } + } + + @Test + public void testCleanAuditErrorContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanAuditErrorContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, "STATUS_CODE"); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, "RESPONSE_CODE"); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION, "RESPONSE_DESCRIPTION"); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)); + assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION)); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking cleanAuditErrorLogContext: " + e.toString()); + } + } + + @Test + public void testPopulateErrorLogContext() { + try { + Class<?>[] paramString = { String.class, String.class, String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateErrorLogContext", paramString); + m.setAccessible(true); + m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION", "TARGET_ENTITY", "TARGET_SERVICENAME", "CLASS_NAME"); + assertEquals("CLASS_NAME", MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking populateErrorLogContext: " + e.toString()); + } + } + + @Test + public void testCleanErrorLogContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanErrorLogContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking cleanErrorLogContext: " + e.toString()); + } + } + + @Test + public void testPopulateMetricLogContext() { + try { + Class<?>[] paramString = { Instant.class, Instant.class, String.class, String.class, String.class, + String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateMetricLogContext", paramString); + m.setAccessible(true); + java.util.Date timestamp = new java.util.Date(); + m.invoke(null, timestamp.toInstant(), timestamp.toInstant(), "TARGET_ENTITY", "TARGET_SERVICE_NAME", "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION", "CLASS_NAME"); + assertEquals("STATUS_CODE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + assertEquals("RESPONSE_CODE", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)); + assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking populateMetricLogContext: " + e.toString()); + } + } + + @Test + public void testCleanMetricContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanMetricContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.CLASS_NAME, "CLASS_NAME"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.CLASS_NAME)); + } catch (Exception e) { + fail("Exception invoking cleanMetricContext: " + e.toString()); + } + } + + @Test + public void testPopulateTargetContext() { + try { + Class<?>[] paramString = { String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateTargetContext", paramString); + m.setAccessible(true); + m.invoke(null, "TARGET_ENTITY", "TARGET_SERVICE_NAME"); + assertEquals("TARGET_ENTITY", MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY)); + assertEquals("TARGET_SERVICE_NAME", MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME)); + } catch (Exception e) { + fail("Exception invoking populateTargetContext: " + e.toString()); + } + } + + @Test + public void testCleanTargetContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanTargetContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.TARGET_ENTITY, "TARGET_ENTITY"); + MDC.put(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME, "TARGET_SERVICE_NAME"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.TARGET_ENTITY)); + assertNull(MDC.get(LoggingConstants.MDCKeys.TARGET_SERVICE_NAME)); + } catch (Exception e) { + fail("Exception invoking cleanTargetContext: " + e.toString()); + } + } + + @Test + public void testPopulateTimeContext() { + try { + Class<?>[] paramString = { Instant.class, Instant.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateTimeContext", paramString); + m.setAccessible(true); + java.util.Date timestamp = new java.util.Date(); + m.invoke(null, timestamp.toInstant(), timestamp.toInstant()); + } catch (Exception e) { + fail("Exception invoking populateTimeContext: " + e.toString()); + } + } + + @Test + public void testGenerateTimestampStr() { + try { + Class<?>[] paramString = { Instant.class }; + Method m = LoggingUtils.class.getDeclaredMethod("generateTimestampStr", paramString); + m.setAccessible(true); + java.util.Date timestamp = new java.util.Date(); + assertNotNull((String) m.invoke(null, timestamp.toInstant())); + } catch (Exception e) { + fail("Exception invoking testGenerateTimestampStr: " + e.toString()); + } + + } + + @Test + public void testCleanTimeContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanTimeContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP, "BEGIN_TIMESTAMP"); + MDC.put(LoggingConstants.MDCKeys.END_TIMESTAMP, "END_TIMESTAMP"); + MDC.put(LoggingConstants.MDCKeys.ELAPSED_TIME, "ELAPSED_TIME"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.BEGIN_TIMESTAMP)); + assertNull(MDC.get(LoggingConstants.MDCKeys.END_TIMESTAMP)); + assertNull(MDC.get(LoggingConstants.MDCKeys.ELAPSED_TIME)); + } catch (Exception e) { + fail("Exception invoking cleanErrorContext: " + e.toString()); + } + } + + @Test + public void testPopulateResponseContext() { + try { + Class<?>[] paramString = { String.class, String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateResponseContext", paramString); + m.setAccessible(true); + m.invoke(null, "STATUS_CODE", "RESPONSE_CODE", "RESPONSE_DESCRIPTION"); + assertEquals("STATUS_CODE", MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + assertEquals("RESPONSE_CODE", MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)); + assertEquals("RESPONSE_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking populateResponseContext: " + e.toString()); + } + } + + @Test + public void testCleanResponseContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanResponseContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.STATUS_CODE, "STATUS_CODE"); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_CODE, "RESPONSE_CODE"); + MDC.put(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION, "RESPONSE_DESCRIPTION"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.STATUS_CODE)); + assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_CODE)); + assertNull(MDC.get(LoggingConstants.MDCKeys.RESPONSE_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking cleanErrorContext: " + e.toString()); + } + } + + @Test + public void testPopulateErrorContext() { + try { + Class<?>[] paramString = { String.class, String.class }; + Method m = LoggingUtils.class.getDeclaredMethod("populateErrorContext", paramString); + m.setAccessible(true); + m.invoke(null, "ERROR_CODE", "ERROR_DESCRIPTION"); + //assertEquals("900", MDC.get(LoggingConstants.MDCKeys.ERROR_CODE)); + assertEquals("ERROR_DESCRIPTION", MDC.get(LoggingConstants.MDCKeys.ERROR_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking populateErrorContext: " + e.toString()); + } + } + + @Test + public void testCleanErrorContext() { + try { + Method m = LoggingUtils.class.getDeclaredMethod("cleanErrorContext"); + m.setAccessible(true); + MDC.put(LoggingConstants.MDCKeys.ERROR_CODE, "ERROR_CODE"); + MDC.put(LoggingConstants.MDCKeys.ERROR_DESCRIPTION, "ERROR_DESCRIPTION"); + m.invoke(null); + assertNull(MDC.get(LoggingConstants.MDCKeys.ERROR_CODE)); + assertNull(MDC.get(LoggingConstants.MDCKeys.ERROR_DESCRIPTION)); + } catch (Exception e) { + fail("Exception invoking cleanErrorContext: " + e.toString()); + } + } + +} diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/CachedElementTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/CachedElementTest.java new file mode 100644 index 000000000..60fd6f570 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/CachedElementTest.java @@ -0,0 +1,285 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Modifications Copyright (C) 2019 IBM + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + + + +package org.onap.ccsdk.sli.core.utils.pool; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import org.junit.Before; +import org.junit.Test; + +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.assertSame; +import static org.junit.Assert.assertTrue; + +public class CachedElementTest implements Allocator<Testable>, Destructor<Testable> { + private static final int MIN = 10; + private static final int MAX = 100; + private Pool<Testable> pool; + private int index = 0; + private int destroyCount = 0; + + /** + * setup + * + * @throws PoolSpecificationException + * If the minimum size is less than 0, or if the max size is non-zero and less than the min size. + */ + @Before + public void setup() throws PoolSpecificationException { + pool = new Pool<>(MIN, MAX); + } + + /** + * Test state + */ + @Test + public void testAllocator() { + assertNull(pool.getAllocator()); + pool.setAllocator(this); + assertNotNull(pool.getAllocator()); + } + + /** + * Test state + */ + @Test + public void testDestructor() { + assertNull(pool.getDestructor()); + pool.setDestructor(this); + assertNotNull(pool.getDestructor()); + } + + /** + * Test that we can allocate and release elements and that the pool maintains them in MRU order + * + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws PoolDrainedException + * If the caller is trying to reserve an element from a drained pool + */ + @Test + public void testAllocateAndRelease() throws PoolExtensionException, PoolDrainedException { + pool.setAllocator(this); + + assertFalse(pool.isDrained()); + + /* + * Allocate three elements + */ + Testable value1 = pool.reserve(); + assertNotNull(value1); + assertEquals(Integer.valueOf(MIN - 1), Integer.valueOf(value1.getId())); + assertEquals(1, pool.getAllocatedSize()); + assertEquals(MIN - 1, pool.getFreeSize()); + assertEquals(1, pool.getAllocatedSize()); + + Testable value2 = pool.reserve(); + assertNotNull(value2); + assertEquals(Integer.valueOf(MIN - 2), Integer.valueOf(value2.getId())); + assertEquals(2, pool.getAllocatedSize()); + assertEquals(MIN - 2, pool.getFreeSize()); + assertEquals(2, pool.getAllocatedSize()); + + Testable value3 = pool.reserve(); + assertNotNull(value3); + assertEquals(Integer.valueOf(MIN - 3), Integer.valueOf(value3.getId())); + assertEquals(3, pool.getAllocatedSize()); + assertEquals(MIN - 3, pool.getFreeSize()); + assertEquals(3, pool.getAllocatedSize()); + + /* + * Now, release them in the order obtained + */ + pool.release(value1); + pool.release(value2); + pool.release(value3); + + assertEquals(0, pool.getAllocatedSize()); + assertEquals(MIN, pool.getFreeSize()); + + /* + * Now, allocate them again, but their values should be reversed (3, 2, 1) representing the most recently used + * to the least recently used. + */ + value1 = pool.reserve(); + assertNotNull(value1); + assertEquals(Integer.valueOf(MIN - 3), Integer.valueOf(value1.getId())); + + value2 = pool.reserve(); + assertNotNull(value2); + assertEquals(Integer.valueOf(MIN - 2), Integer.valueOf(value2.getId())); + + value3 = pool.reserve(); + assertNotNull(value3); + assertEquals(Integer.valueOf(MIN - 1), Integer.valueOf(value3.getId())); + } + + /** + * Test that we can trim the pool to a desired size + * + * @throws PoolDrainedException + * If the caller is trying to release or reserve an element from a drained pool + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws IllegalAccessException + * if this Method object is enforcing Java language access control and the underlying method is + * inaccessible. + * @throws IllegalArgumentException + * if the method is an instance method and the specified object argument is not an instance of the class + * or interface declaring the underlying method (or of a subclass or implementor thereof); if the number + * of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or + * if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal + * parameter type by a method invocation conversion. + * @throws InvocationTargetException + * if the underlying method throws an exception. + * @throws SecurityException + * If a security manager, s, is present and any of the following conditions is met: + * <ul> + * <li>invocation of s.checkMemberAccess(this, Member.DECLARED) denies access to the declared method</li> + * <li>the caller's class loader is not the same as or an ancestor of the class loader for the current + * class and invocation of s.checkPackageAccess() denies access to the package of this class</li> + * </ul> + * @throws NoSuchMethodException + * if a matching method is not found. + */ + @SuppressWarnings("nls") + @Test + public void testTrim() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, + PoolDrainedException, PoolExtensionException, NoSuchMethodException, SecurityException { + + pool.setAllocator(this); + int SIZE = 50; + Testable[] array = new Testable[SIZE]; + + assertEquals(0, pool.getAllocatedSize()); + for (int i = 0; i < SIZE; i++) { + array[i] = pool.reserve(); + } + assertEquals(SIZE, pool.getAllocatedSize()); + + for (int i = 0; i < SIZE; i++) { + pool.release(array[i]); + } + assertEquals(0, pool.getAllocatedSize()); + + assertEquals(SIZE, pool.getFreeSize()); + + Method trimMethod = Pool.class.getDeclaredMethod("trim", new Class[] { + Integer.TYPE + }); + trimMethod.setAccessible(true); + trimMethod.invoke(pool, new Object[] { + SIZE - MIN + }); + + assertEquals(MIN, pool.getFreeSize()); + } + + /** + * Test that we can drain a pool containing a mix of free and allocated elements + * + * @throws PoolDrainedException + * If the caller is trying to release or reserve an element from a drained pool + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws IOException + * if an I/O error occurs + */ + @Test + public void testDrain() throws PoolExtensionException, PoolDrainedException, IOException { + int SIZE = 50; + int FREE = 20; + int ALLOC = SIZE - FREE; + + Testable[] array = new Testable[SIZE]; + pool.setAllocator(this); + pool.setDestructor(this); + + assertFalse(pool.isDrained()); + + assertEquals(0, pool.getAllocatedSize()); + for (int i = 0; i < SIZE; i++) { + array[i] = pool.reserve(); + } + assertEquals(SIZE, pool.getAllocatedSize()); + + for (int i = 0; i < FREE; i++) { + array[i].close(); + } + assertEquals(ALLOC, pool.getAllocatedSize()); + assertEquals(FREE, pool.getFreeSize()); + + pool.drain(); + assertEquals(0, pool.getFreeSize()); + assertEquals(0, pool.getAllocatedSize()); + assertTrue(pool.isDrained()); + + assertEquals(SIZE, destroyCount); + } + + /** + * @see org.onap.ccsdk.sli.core.utils.pool.Allocator#allocate(org.onap.ccsdk.sli.core.utils.pool.Pool) + */ + @Override + public Testable allocate(Pool<Testable> pool) { + Testable element = new org.onap.ccsdk.sli.core.utils.pool.Element(index++); + Testable ce = CachedElement.newInstance(pool, element, new Class[] { + Testable.class + }); + return ce; + } + + /** + * @see org.onap.ccsdk.sli.core.utils.pool.Destructor#destroy(java.io.Closeable, org.onap.ccsdk.sli.core.utils.pool.Pool) + */ + @Override + public void destroy(Testable obj, Pool<Testable> pool) { + destroyCount++; + } + + @Test + public void testGetWrappedObject() + { + Testable element = new org.onap.ccsdk.sli.core.utils.pool.Element(index++); + CachedElement cachedElement = new CachedElement(pool, element); + assertNotNull(cachedElement.getWrappedObject()); + assertSame(element, cachedElement.getWrappedObject()); + } + + @Test + public void testToString() + { + Testable element = new org.onap.ccsdk.sli.core.utils.pool.Element(index++); + CachedElement cachedElement = new CachedElement(pool, element); + assertTrue(cachedElement.toString() instanceof String); + } +} diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Element.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Element.java new file mode 100644 index 000000000..288a5ffbd --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Element.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + + + +package org.onap.ccsdk.sli.core.utils.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/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedExceptionTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedExceptionTest.java new file mode 100644 index 000000000..30907f995 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolDrainedExceptionTest.java @@ -0,0 +1,35 @@ +/*-
+* ============LICENSE_START=======================================================
+* ONAP : APPC
+* ================================================================================
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+* =============================================================================
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END=========================================================
+*/
+package org.onap.ccsdk.sli.core.utils.pool;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PoolDrainedExceptionTest {
+
+ @Test
+ public void testPoolDrainedException() {
+ String message = "test message";
+ PoolDrainedException poolDrainedExp = new PoolDrainedException(message);
+ Assert.assertEquals(message, poolDrainedExp.getMessage());
+ Assert.assertEquals(message, poolDrainedExp.getLocalizedMessage());
+ }
+
+}
diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExceptionTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExceptionTest.java new file mode 100644 index 000000000..9716d5813 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExceptionTest.java @@ -0,0 +1,72 @@ +/*-
+* ============LICENSE_START=======================================================
+* ONAP : APPC
+* ================================================================================
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+* =============================================================================
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END=========================================================
+*/
+package org.onap.ccsdk.sli.core.utils.pool;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PoolExceptionTest {
+
+ @Test
+ public void testPoolException() {
+ PoolException poolException = new PoolException();
+ Assert.assertTrue(poolException.getCause() == null);
+ Assert.assertTrue(poolException.getMessage() == null);
+ }
+
+ @Test
+ public void testPoolExceptionString() {
+ String message = "test message";
+ PoolException poolException = new PoolException(message);
+ Assert.assertEquals(message, poolException.getMessage());
+ Assert.assertEquals(message, poolException.getLocalizedMessage());
+ }
+
+ @Test
+ public void testPoolExceptionThrowable() {
+ String tMessage = "throwable message";
+ Throwable throwable = new Throwable(tMessage);
+ PoolException poolException = new PoolException(throwable);
+ Assert.assertEquals(throwable, poolException.getCause());
+ }
+
+ @Test
+ public void testPoolExceptionStringThrowable() {
+ String message = "my test message";
+ String tMessage = "throwable message";
+ Throwable throwable = new Throwable(tMessage);
+ PoolException poolException = new PoolException(message, throwable);
+ Assert.assertEquals(throwable, poolException.getCause());
+ Assert.assertTrue(poolException.getMessage().contains(message));
+ Assert.assertEquals(message, poolException.getLocalizedMessage());
+ }
+
+ @Test
+ public void testPoolExceptionStringThrowableBooleanBoolean() {
+ String message = "my test message";
+ String tMessage = "throwable message";
+ Throwable throwable = new Throwable(tMessage);
+ PoolException poolException = new PoolException(message, throwable, true, true);
+ Assert.assertEquals(throwable, poolException.getCause());
+ Assert.assertTrue(poolException.getMessage().contains(message));
+ Assert.assertEquals(message, poolException.getLocalizedMessage());
+ }
+
+}
diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionExceptionTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionExceptionTest.java new file mode 100644 index 000000000..f972a7d4b --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolExtensionExceptionTest.java @@ -0,0 +1,35 @@ +/*-
+* ============LICENSE_START=======================================================
+* ONAP : APPC
+* ================================================================================
+* Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+* =============================================================================
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+* ============LICENSE_END=========================================================
+*/
+package org.onap.ccsdk.sli.core.utils.pool;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PoolExtensionExceptionTest {
+
+ @Test
+ public void testPoolExtensionException() {
+ String message = "test message";
+ PoolExtensionException poolExtExcpt = new PoolExtensionException(message);
+ Assert.assertEquals(message, poolExtExcpt.getMessage());
+ Assert.assertEquals(message, poolExtExcpt.getLocalizedMessage());
+ }
+
+}
diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolTest.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolTest.java new file mode 100644 index 000000000..c1c7aa199 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/PoolTest.java @@ -0,0 +1,335 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Modifications Copyright (C) 2018 IBM. + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + + + +package org.onap.ccsdk.sli.core.utils.pool; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Properties; +import org.junit.Before; +import org.junit.Test; +import org.onap.ccsdk.sli.core.utils.pool.*; +import org.onap.ccsdk.sli.core.utils.pool.Allocator; +import org.onap.ccsdk.sli.core.utils.pool.Destructor; +import org.onap.ccsdk.sli.core.utils.pool.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; + +public class PoolTest implements Allocator<Testable>, Destructor<Testable> { + + private Pool<Testable> pool; + private static final int MIN = 10; + private static final int MAX = 100; + private int index = 0; + private int destroyCount = 0; + + /** + * Set up the test by allocating a pool with MIN-MAX size (bounded pool) + * + * @throws PoolSpecificationException + * If the minimum size is less than 0, or if the max size is non-zero and less than the min size. + */ + @Before + public void setup() throws PoolSpecificationException { + pool = new Pool<>(MIN, MAX); + index = 0; + destroyCount = 0; + } + + /** + * Test that trying to construct a pool with a bad minimum throws an exception + * + * @throws PoolSpecificationException + * If the minimum size is less than 0, or if the max size is non-zero and less than the min size. + */ + @Test(expected = PoolSpecificationException.class) + public void testInvalidMinSize() throws PoolSpecificationException { + pool = new Pool<>(-1, MAX); + } + + /** + * Test that trying to construct a pool with a bad maximum throws an exception + * + * @throws PoolSpecificationException + * If the minimum size is less than 0, or if the max size is non-zero and less than the min size. + */ + @Test(expected = PoolSpecificationException.class) + public void testInvalidMaxSize() throws PoolSpecificationException { + pool = new Pool<>(MIN, -1); + } + + /** + * Test creation of a pool where max is less than min fails + * + * @throws PoolSpecificationException + * If the minimum size is less than 0, or if the max size is non-zero and less than the min size. + */ + @Test(expected = PoolSpecificationException.class) + public void testInvalidSizeRange() throws PoolSpecificationException { + pool = new Pool<>(MAX, MIN); + } + + /** + * Test state + */ + @Test + public void testMinPool() { + assertEquals(MIN, pool.getMinPool()); + } + + /** + * Test state + */ + @Test + public void testMaxPool() { + assertEquals(MAX, pool.getMaxPool()); + } + + /** + * Test state + */ + @Test + public void testAllocator() { + assertNull(pool.getAllocator()); + pool.setAllocator(this); + assertNotNull(pool.getAllocator()); + } + + /** + * Test state + */ + @Test + public void testDestructor() { + assertNull(pool.getDestructor()); + pool.setDestructor(this); + assertNotNull(pool.getDestructor()); + } + + /** + * Test that we can allocate and release elements and that the pool maintains them in MRU order + * + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws PoolDrainedException + * If the caller is trying to reserve an element from a drained pool + */ + @Test + public void testAllocateAndRelease() throws PoolExtensionException, PoolDrainedException { + pool.setAllocator(this); + + assertFalse(pool.isDrained()); + + /* + * Allocate three elements + */ + Testable value1 = pool.reserve(); + assertNotNull(value1); + assertEquals(Integer.valueOf(MIN - 1), value1.getId()); + assertEquals(1, pool.getAllocatedSize()); + assertEquals(MIN - 1, pool.getFreeSize()); + assertEquals(1, pool.getAllocatedSize()); + + Testable value2 = pool.reserve(); + assertNotNull(value2); + assertEquals(Integer.valueOf(MIN - 2), value2.getId()); + assertEquals(2, pool.getAllocatedSize()); + assertEquals(MIN - 2, pool.getFreeSize()); + assertEquals(2, pool.getAllocatedSize()); + + Testable value3 = pool.reserve(); + assertNotNull(value3); + assertEquals(Integer.valueOf(MIN - 3), value3.getId()); + assertEquals(3, pool.getAllocatedSize()); + assertEquals(MIN - 3, pool.getFreeSize()); + assertEquals(3, pool.getAllocatedSize()); + + /* + * Now, release them in the order obtained + */ + pool.release(value1); + pool.release(value2); + pool.release(value3); + + assertEquals(0, pool.getAllocatedSize()); + assertEquals(MIN, pool.getFreeSize()); + + /* + * Now, allocate them again, but their values should be reversed (3, 2, 1) representing the most recently used + * to the least recently used. + */ + value1 = pool.reserve(); + assertNotNull(value1); + assertEquals(Integer.valueOf(MIN - 3), value1.getId()); + + value2 = pool.reserve(); + assertNotNull(value2); + assertEquals(Integer.valueOf(MIN - 2), value2.getId()); + + value3 = pool.reserve(); + assertNotNull(value3); + assertEquals(Integer.valueOf(MIN - 1), value3.getId()); + } + + /** + * Test that we can trim the pool to a desired size + * + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws NoSuchMethodException + * if a matching method is not found. + * @throws SecurityException + * if the request is denied. + * @throws IllegalAccessException + * if this Method object is enforcing Java language access control and the underlying method is + * inaccessible. + * @throws IllegalArgumentException + * if the method is an instance method and the specified object argument is not an instance of the class + * or interface declaring the underlying method (or of a subclass or implementor thereof); if the number + * of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or + * if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal + * parameter type by a method invocation conversion. + * @throws InvocationTargetException + * if the underlying method throws an exception. + * @throws PoolDrainedException + * If the caller is trying to reserve an element from a drained pool + */ + @SuppressWarnings("nls") + @Test + public void testTrim() throws PoolExtensionException, NoSuchMethodException, SecurityException, + IllegalAccessException, IllegalArgumentException, InvocationTargetException, PoolDrainedException { + pool.setAllocator(this); + int SIZE = 50; + Proxy[] array = new Proxy[SIZE]; + + assertEquals(0, pool.getAllocatedSize()); + for (int i = 0; i < SIZE; i++) { + array[i] = (Proxy) pool.reserve(); + } + assertEquals(SIZE, pool.getAllocatedSize()); + + for (int i = 0; i < SIZE; i++) { + pool.release((Testable) array[i]); + } + assertEquals(0, pool.getAllocatedSize()); + + assertEquals(SIZE, pool.getFreeSize()); + + Method trimMethod = Pool.class.getDeclaredMethod("trim", new Class[] { + Integer.TYPE + }); + trimMethod.setAccessible(true); + trimMethod.invoke(pool, new Object[] { + SIZE - MIN + }); + + assertEquals(MIN, pool.getFreeSize()); + } + + /** + * Test that we can drain a pool containing a mix of free and allocated elements + * + * @throws PoolExtensionException + * If the pool cannot be extended + * @throws PoolDrainedException + * If the caller is trying to reserve an element from a drained pool + */ + @Test + public void testDrain() throws PoolExtensionException, PoolDrainedException { + int SIZE = 50; + int FREE = 20; + int ALLOC = SIZE - FREE; + + Proxy[] array = new Proxy[SIZE]; + pool.setAllocator(this); + pool.setDestructor(this); + + assertFalse(pool.isDrained()); + + assertEquals(0, pool.getAllocatedSize()); + for (int i = 0; i < SIZE; i++) { + array[i] = (Proxy) pool.reserve(); + } + assertEquals(SIZE, pool.getAllocatedSize()); + + for (int i = 0; i < FREE; i++) { + pool.release((Testable) array[i]); + } + assertEquals(ALLOC, pool.getAllocatedSize()); + assertEquals(FREE, pool.getFreeSize()); + + pool.drain(); + assertEquals(0, pool.getFreeSize()); + assertEquals(0, pool.getAllocatedSize()); + assertTrue(pool.isDrained()); + + assertEquals(SIZE, destroyCount); + } + + /** + * @see org.onap.ccsdk.sli.core.utils.pool.Destructor#destroy(java.io.Closeable, org.onap.ccsdk.sli.core.utils.pool.Pool) + */ + @Override + public void destroy(Testable obj, Pool<Testable> pool) { + destroyCount++; + try { + obj.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * @see org.onap.ccsdk.sli.core.utils.pool.Allocator#allocate(org.onap.ccsdk.sli.core.utils.pool.Pool) + */ + @Override + public Testable allocate(Pool<Testable> pool) { + Testable e = new org.onap.ccsdk.sli.core.utils.pool.Element(index++); + + return e; + } + + @Test + public void testGetAndSetProperties() throws PoolSpecificationException + { + pool= new Pool<Testable>(3, 5); + pool.setProperty("key1", "value1"); + assertEquals("value1", pool.getProperty("key1")); + } + + @Test + public void testGetProperties() throws PoolSpecificationException + { + pool= new Pool<Testable>(3, 5); + assertTrue(pool.getProperties() instanceof Properties); + } +} diff --git a/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Testable.java b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Testable.java new file mode 100644 index 000000000..95da40409 --- /dev/null +++ b/core/utils/provider/src/test/java/org/onap/ccsdk/sli/core/utils/pool/Testable.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.core.utils.pool; + +import java.io.Closeable; + +public interface Testable extends Closeable { + + Integer getId(); + + Boolean isClosed(); +} + |