diff options
author | 2021-05-13 15:09:28 -0400 | |
---|---|---|
committer | 2021-05-17 10:52:59 -0400 | |
commit | 7845d9b33a89a1c647dfa20bfefee3599783cae7 (patch) | |
tree | 3be5e37a9c916b858002458278a999ca9b8e3974 /core/utils/provider/src/main | |
parent | 557282a4274b7f2849e2433ff3373b43c6a920b3 (diff) |
Moving IAAS Adaptor from APPC to CCSDK SLI
Issue-ID: CCSDK-3198
Signed-off-by: Singal, Kapil (ks220y) <ks220y@att.com>
Change-Id: I24c21a9bebe87bb87eb14bd903ee558c20b45277
Diffstat (limited to 'core/utils/provider/src/main')
11 files changed, 1196 insertions, 3 deletions
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); + } + +} |