http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/IdGenerator.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/IdGenerator.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/IdGenerator.java new file mode 100644 index 0000000..c662b59 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/IdGenerator.java @@ -0,0 +1,274 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.UnknownHostException; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Generator for Globally unique Strings. + */ +public class IdGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(IdGenerator.class); + private static final String UNIQUE_STUB; + private static int instanceCount; + private static String hostName; + private String seed; + private final AtomicLong sequence = new AtomicLong(1); + private int length; + public static final String PROPERTY_IDGENERATOR_PORT = "activemq.idgenerator.port"; + + static { + String stub = ""; + boolean canAccessSystemProps = true; + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertiesAccess(); + } + } + catch (SecurityException se) { + canAccessSystemProps = false; + } + + if (canAccessSystemProps) { + int idGeneratorPort = 0; + ServerSocket ss = null; + try { + idGeneratorPort = Integer.parseInt(System.getProperty(PROPERTY_IDGENERATOR_PORT, "0")); + LOG.trace("Using port {}", idGeneratorPort); + hostName = getLocalHostName(); + ss = new ServerSocket(idGeneratorPort); + stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-"; + Thread.sleep(100); + } + catch (Exception e) { + if (LOG.isTraceEnabled()) { + LOG.trace("could not generate unique stub by using DNS and binding to local port", e); + } + else { + LOG.warn("could not generate unique stub by using DNS and binding to local port: {} {}", e.getClass().getCanonicalName(), e.getMessage()); + } + + // Restore interrupted state so higher level code can deal with it. + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + } + finally { + if (ss != null) { + try { + ss.close(); + } + catch (IOException ioe) { + if (LOG.isTraceEnabled()) { + LOG.trace("Closing the server socket failed", ioe); + } + else { + LOG.warn("Closing the server socket failed" + " due " + ioe.getMessage()); + } + } + } + } + } + + if (hostName == null) { + hostName = "localhost"; + } + hostName = sanitizeHostName(hostName); + + if (stub.length() == 0) { + stub = "-1-" + System.currentTimeMillis() + "-"; + } + UNIQUE_STUB = stub; + } + + /** + * Construct an IdGenerator + * + * @param prefix The prefix value that is applied to all generated IDs. + */ + public IdGenerator(String prefix) { + synchronized (UNIQUE_STUB) { + this.seed = prefix + UNIQUE_STUB + (instanceCount++) + ":"; + this.length = this.seed.length() + ("" + Long.MAX_VALUE).length(); + } + } + + public IdGenerator() { + this("ID:" + hostName); + } + + /** + * As we have to find the host name as a side-affect of generating a unique stub, we allow + * it's easy retrieval here + * + * @return the local host name + */ + public static String getHostName() { + return hostName; + } + + /** + * Generate a unique id + * + * @return a unique id + */ + public synchronized String generateId() { + StringBuilder sb = new StringBuilder(length); + sb.append(seed); + sb.append(sequence.getAndIncrement()); + return sb.toString(); + } + + public static String sanitizeHostName(String hostName) { + boolean changed = false; + + StringBuilder sb = new StringBuilder(); + for (char ch : hostName.toCharArray()) { + // only include ASCII chars + if (ch < 127) { + sb.append(ch); + } + else { + changed = true; + } + } + + if (changed) { + String newHost = sb.toString(); + LOG.info("Sanitized hostname from: {} to: {}", hostName, newHost); + return newHost; + } + else { + return hostName; + } + } + + /** + * Generate a unique ID - that is friendly for a URL or file system + * + * @return a unique id + */ + public String generateSanitizedId() { + String result = generateId(); + result = result.replace(':', '-'); + result = result.replace('_', '-'); + result = result.replace('.', '-'); + return result; + } + + /** + * From a generated id - return the seed (i.e. minus the count) + * + * @param id the generated identifier + * @return the seed + */ + public static String getSeedFromId(String id) { + String result = id; + if (id != null) { + int index = id.lastIndexOf(':'); + if (index > 0 && (index + 1) < id.length()) { + result = id.substring(0, index); + } + } + return result; + } + + /** + * From a generated id - return the generator count + * + * @param id The ID that will be parsed for a sequence number. + * @return the sequence value parsed from the given ID. + */ + public static long getSequenceFromId(String id) { + long result = -1; + if (id != null) { + int index = id.lastIndexOf(':'); + + if (index > 0 && (index + 1) < id.length()) { + String numStr = id.substring(index + 1, id.length()); + result = Long.parseLong(numStr); + } + } + return result; + } + + /** + * Does a proper compare on the Id's + * + * @param id1 the lhs of the comparison. + * @param id2 the rhs of the comparison. + * @return 0 if equal else a positive if {@literal id1 > id2} ... + */ + public static int compare(String id1, String id2) { + int result = -1; + String seed1 = IdGenerator.getSeedFromId(id1); + String seed2 = IdGenerator.getSeedFromId(id2); + if (seed1 != null && seed2 != null) { + result = seed1.compareTo(seed2); + if (result == 0) { + long count1 = IdGenerator.getSequenceFromId(id1); + long count2 = IdGenerator.getSequenceFromId(id2); + result = (int) (count1 - count2); + } + } + return result; + } + + /** + * When using the {@link java.net.InetAddress#getHostName()} method in an + * environment where neither a proper DNS lookup nor an <tt>/etc/hosts</tt> + * entry exists for a given host, the following exception will be thrown: + * <code> + * java.net.UnknownHostException: <hostname>: <hostname> + * at java.net.InetAddress.getLocalHost(InetAddress.java:1425) + * ... + * </code> + * Instead of just throwing an UnknownHostException and giving up, this + * method grabs a suitable hostname from the exception and prevents the + * exception from being thrown. If a suitable hostname cannot be acquired + * from the exception, only then is the <tt>UnknownHostException</tt> thrown. + * + * @return The hostname + * @throws UnknownHostException if the given host cannot be looked up. + * @see java.net.InetAddress#getLocalHost() + * @see java.net.InetAddress#getHostName() + */ + protected static String getLocalHostName() throws UnknownHostException { + try { + return (InetAddress.getLocalHost()).getHostName(); + } + catch (UnknownHostException uhe) { + String host = uhe.getMessage(); // host = "hostname: hostname" + if (host != null) { + int colon = host.indexOf(':'); + if (colon > 0) { + return host.substring(0, colon); + } + } + throw uhe; + } + } +}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/NoOpAsyncResult.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/NoOpAsyncResult.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/NoOpAsyncResult.java new file mode 100644 index 0000000..5dd4d12 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/NoOpAsyncResult.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +/** + * Simple NoOp implementation used when the result of the operation does not matter. + */ +public class NoOpAsyncResult implements AsyncResult { + + public static final NoOpAsyncResult INSTANCE = new NoOpAsyncResult(); + + @Override + public void onFailure(Throwable result) { + + } + + @Override + public void onSuccess() { + + } + + @Override + public boolean isComplete() { + return true; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/PropertyUtil.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/PropertyUtil.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/PropertyUtil.java new file mode 100644 index 0000000..1285a0f --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/PropertyUtil.java @@ -0,0 +1,533 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import javax.net.ssl.SSLContext; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +/** + * Utilities for properties + */ +public class PropertyUtil { + + /** + * Creates a URI from the original URI and the given parameters. + * + * @param originalURI The URI whose current parameters are removed and replaced with the given remainder value. + * @param params The URI params that should be used to replace the current ones in the target. + * @return a new URI that matches the original one but has its query options replaced with + * the given ones. + * @throws URISyntaxException if the given URI is invalid. + */ + public static URI replaceQuery(URI originalURI, Map<String, String> params) throws URISyntaxException { + String s = createQueryString(params); + if (s.length() == 0) { + s = null; + } + return replaceQuery(originalURI, s); + } + + /** + * Creates a URI with the given query, removing an previous query value from the given URI. + * + * @param uri The source URI whose existing query is replaced with the newly supplied one. + * @param query The new URI query string that should be appended to the given URI. + * @return a new URI that is a combination of the original URI and the given query string. + * @throws URISyntaxException if the given URI is invalid. + */ + public static URI replaceQuery(URI uri, String query) throws URISyntaxException { + String schemeSpecificPart = uri.getRawSchemeSpecificPart(); + // strip existing query if any + int questionMark = schemeSpecificPart.lastIndexOf("?"); + // make sure question mark is not within parentheses + if (questionMark < schemeSpecificPart.lastIndexOf(")")) { + questionMark = -1; + } + if (questionMark > 0) { + schemeSpecificPart = schemeSpecificPart.substring(0, questionMark); + } + if (query != null && query.length() > 0) { + schemeSpecificPart += "?" + query; + } + return new URI(uri.getScheme(), schemeSpecificPart, uri.getFragment()); + } + + /** + * Creates a URI with the given query, removing an previous query value from the given URI. + * + * @param uri The source URI whose existing query is replaced with the newly supplied one. + * @return a new URI that is a combination of the original URI and the given query string. + * @throws URISyntaxException if the given URI is invalid. + */ + public static URI eraseQuery(URI uri) throws URISyntaxException { + return replaceQuery(uri, (String) null); + } + + /** + * Given a key / value mapping, create and return a URI formatted query string that is valid + * and can be appended to a URI. + * + * @param options The Mapping that will create the new Query string. + * @return a URI formatted query string. + * @throws URISyntaxException if the given URI is invalid. + */ + public static String createQueryString(Map<String, ?> options) throws URISyntaxException { + try { + if (options.size() > 0) { + StringBuffer rc = new StringBuffer(); + boolean first = true; + for (Entry<String, ?> entry : options.entrySet()) { + if (first) { + first = false; + } + else { + rc.append("&"); + } + rc.append(URLEncoder.encode(entry.getKey(), "UTF-8")); + rc.append("="); + rc.append(URLEncoder.encode((String) entry.getValue(), "UTF-8")); + } + return rc.toString(); + } + else { + return ""; + } + } + catch (UnsupportedEncodingException e) { + throw (URISyntaxException) new URISyntaxException(e.toString(), "Invalid encoding").initCause(e); + } + } + + /** + * Get properties from a URI and return them in a new {@code Map<String, String>} instance. + * + * If the URI is null or the query string of the URI is null an empty Map is returned. + * + * @param uri the URI whose parameters are to be parsed. + * @return <Code>Map</Code> of properties + * @throws Exception if an error occurs while parsing the query options. + */ + public static Map<String, String> parseParameters(URI uri) throws Exception { + if (uri == null || uri.getQuery() == null) { + return Collections.emptyMap(); + } + + return parseQuery(stripPrefix(uri.getQuery(), "?")); + } + + /** + * Parse properties from a named resource -eg. a URI or a simple name e.g. + * {@literal foo?name="fred"&size=2} + * + * @param uri the URI whose parameters are to be parsed. + * @return <Code>Map</Code> of properties + * @throws Exception if an error occurs while parsing the query options. + */ + public static Map<String, String> parseParameters(String uri) throws Exception { + if (uri == null) { + return Collections.emptyMap(); + } + + return parseQuery(stripUpto(uri, '?')); + } + + /** + * Get properties from a URI query string. + * + * @param queryString the string value returned from a call to the URI class getQuery method. + * @return <Code>Map</Code> of properties from the parsed string. + * @throws Exception if an error occurs while parsing the query options. + */ + public static Map<String, String> parseQuery(String queryString) throws Exception { + if (queryString != null && !queryString.isEmpty()) { + Map<String, String> rc = new HashMap<>(); + String[] parameters = queryString.split("&"); + for (int i = 0; i < parameters.length; i++) { + int p = parameters[i].indexOf("="); + if (p >= 0) { + String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8"); + String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8"); + rc.put(name, value); + } + else { + rc.put(parameters[i], null); + } + } + return rc; + } + + return Collections.emptyMap(); + } + + /** + * Given a map of properties, filter out only those prefixed with the given value, the + * values filtered are returned in a new Map instance. + * + * @param properties The map of properties to filter. + * @param optionPrefix The prefix value to use when filtering. + * @return a filter map with only values that match the given prefix. + */ + public static Map<String, String> filterProperties(Map<String, String> properties, String optionPrefix) { + if (properties == null) { + throw new IllegalArgumentException("The given properties object was null."); + } + + HashMap<String, String> rc = new HashMap<>(properties.size()); + + for (Iterator<Entry<String, String>> iter = properties.entrySet().iterator(); iter.hasNext(); ) { + Entry<String, String> entry = iter.next(); + if (entry.getKey().startsWith(optionPrefix)) { + String name = entry.getKey().substring(optionPrefix.length()); + rc.put(name, entry.getValue()); + iter.remove(); + } + } + + return rc; + } + + /** + * Enumerate the properties of the target object and add them as additional entries + * to the query string of the given string URI. + * + * @param uri The string URI value to append the object properties to. + * @param bean The Object whose properties will be added to the target URI. + * @return a new String value that is the original URI with the added bean properties. + * @throws Exception if an error occurs while enumerating the bean properties. + */ + public static String addPropertiesToURIFromBean(String uri, Object bean) throws Exception { + Map<String, String> properties = PropertyUtil.getProperties(bean); + return PropertyUtil.addPropertiesToURI(uri, properties); + } + + /** + * Enumerate the properties of the target object and add them as additional entries + * to the query string of the given URI. + * + * @param uri The URI value to append the object properties to. + * @param properties The Object whose properties will be added to the target URI. + * @return a new String value that is the original URI with the added bean properties. + * @throws Exception if an error occurs while enumerating the bean properties. + */ + public static String addPropertiesToURI(URI uri, Map<String, String> properties) throws Exception { + return addPropertiesToURI(uri.toString(), properties); + } + + /** + * Append the given properties to the query portion of the given URI. + * + * @param uri The string URI value to append the object properties to. + * @param properties The properties that will be added to the target URI. + * @return a new String value that is the original URI with the added properties. + * @throws Exception if an error occurs while building the new URI string. + */ + public static String addPropertiesToURI(String uri, Map<String, String> properties) throws Exception { + String result = uri; + if (uri != null && properties != null) { + StringBuilder base = new StringBuilder(stripBefore(uri, '?')); + Map<String, String> map = parseParameters(uri); + if (!map.isEmpty()) { + map.putAll(properties); + } + else { + map = properties; + } + if (!map.isEmpty()) { + base.append('?'); + boolean first = true; + for (Map.Entry<String, String> entry : map.entrySet()) { + if (!first) { + base.append('&'); + } + first = false; + base.append(entry.getKey()).append("=").append(entry.getValue()); + } + result = base.toString(); + } + } + return result; + } + + /** + * Set properties on an object using the provided map. The return value + * indicates if all properties from the given map were set on the target object. + * + * @param target the object whose properties are to be set from the map options. + * @param properties the properties that should be applied to the given object. + * @return true if all values in the properties map were applied to the target object. + */ + public static Map<String, String> setProperties(Object target, Map<String, String> properties) { + if (target == null) { + throw new IllegalArgumentException("target object cannot be null"); + } + if (properties == null) { + throw new IllegalArgumentException("Given Properties object cannot be null"); + } + + Map<String, String> unmatched = new HashMap<>(); + + for (Map.Entry<String, String> entry : properties.entrySet()) { + if (!setProperty(target, entry.getKey(), entry.getValue())) { + unmatched.put(entry.getKey(), entry.getValue()); + } + } + + return Collections.unmodifiableMap(unmatched); + } + + //TODO: common impl for above and below methods. + + /** + * Set properties on an object using the provided Properties object. The return value + * indicates if all properties from the given map were set on the target object. + * + * @param target the object whose properties are to be set from the map options. + * @param properties the properties that should be applied to the given object. + * @return an unmodifiable map with any values that could not be applied to the target. + */ + public static Map<String, Object> setProperties(Object target, Properties properties) { + if (target == null) { + throw new IllegalArgumentException("target object cannot be null"); + } + if (properties == null) { + throw new IllegalArgumentException("Given Properties object cannot be null"); + } + + Map<String, Object> unmatched = new HashMap<>(); + + for (Map.Entry<Object, Object> entry : properties.entrySet()) { + if (!setProperty(target, (String) entry.getKey(), entry.getValue())) { + unmatched.put((String) entry.getKey(), entry.getValue()); + } + } + + return Collections.<String, Object>unmodifiableMap(unmatched); + } + + /** + * Get properties from an object using reflection. If the passed object is null an + * empty <code>Map</code> is returned. + * + * @param object the Object whose properties are to be extracted. + * @return <Code>Map</Code> of properties extracted from the given object. + * @throws Exception if an error occurs while examining the object's properties. + */ + public static Map<String, String> getProperties(Object object) throws Exception { + if (object == null) { + return Collections.emptyMap(); + } + + Map<String, String> properties = new LinkedHashMap<>(); + BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass()); + Object[] NULL_ARG = {}; + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + if (propertyDescriptors != null) { + for (int i = 0; i < propertyDescriptors.length; i++) { + PropertyDescriptor pd = propertyDescriptors[i]; + if (pd.getReadMethod() != null && !pd.getName().equals("class") && !pd.getName().equals("properties") && !pd.getName().equals("reference")) { + Object value = pd.getReadMethod().invoke(object, NULL_ARG); + if (value != null) { + if (value instanceof Boolean || value instanceof Number || value instanceof String || value instanceof URI || value instanceof URL) { + properties.put(pd.getName(), ("" + value)); + } + else if (value instanceof SSLContext) { + // ignore this one.. + } + else { + Map<String, String> inner = getProperties(value); + for (Map.Entry<String, String> entry : inner.entrySet()) { + properties.put(pd.getName() + "." + entry.getKey(), entry.getValue()); + } + } + } + } + } + } + + return properties; + } + + /** + * Find a specific property getter in a given object based on a property name. + * + * @param object the object to search. + * @param name the property name to search for. + * @return the result of invoking the specific property get method. + * @throws Exception if an error occurs while searching the object's bean info. + */ + public static Object getProperty(Object object, String name) throws Exception { + BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass()); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + if (propertyDescriptors != null) { + for (int i = 0; i < propertyDescriptors.length; i++) { + PropertyDescriptor pd = propertyDescriptors[i]; + if (pd.getReadMethod() != null && pd.getName().equals(name)) { + return pd.getReadMethod().invoke(object); + } + } + } + return null; + } + + /** + * Set a property named property on a given Object. + * <p> + * The object is searched for an set method that would match the given named + * property and if one is found. If necessary an attempt will be made to convert + * the new value to an acceptable type. + * + * @param target The object whose property is to be set. + * @param name The name of the property to set. + * @param value The new value to set for the named property. + * @return true if the property was able to be set on the target object. + */ + public static boolean setProperty(Object target, String name, Object value) { + try { + int dotPos = name.indexOf("."); + while (dotPos >= 0) { + String getterName = name.substring(0, dotPos); + target = getProperty(target, getterName); + name = name.substring(dotPos + 1); + dotPos = name.indexOf("."); + } + + Class<?> clazz = target.getClass(); + Method setter = findSetterMethod(clazz, name); + if (setter == null) { + return false; + } + // If the type is null or it matches the needed type, just use the + // value directly + if (value == null || value.getClass() == setter.getParameterTypes()[0]) { + setter.invoke(target, new Object[]{value}); + } + else { + setter.invoke(target, new Object[]{convert(value, setter.getParameterTypes()[0])}); + } + return true; + } + catch (Throwable ignore) { + return false; + } + } + + /** + * Return a String minus the given prefix. If the string does not start + * with the given prefix the original string value is returned. + * + * @param value The String whose prefix is to be removed. + * @param prefix The prefix string to remove from the target string. + * @return stripped version of the original input string. + */ + public static String stripPrefix(String value, String prefix) { + if (value != null && prefix != null && value.startsWith(prefix)) { + return value.substring(prefix.length()); + } + return value; + } + + /** + * Return a portion of a String value by looking beyond the given + * character. + * + * @param value The string value to split + * @param c The character that marks the split point. + * @return the sub-string value starting beyond the given character. + */ + public static String stripUpto(String value, char c) { + String result = null; + if (value != null) { + int index = value.indexOf(c); + if (index > 0) { + result = value.substring(index + 1); + } + } + return result; + } + + /** + * Return a String up to and including character + * + * @param value The string value to split + * @param c The character that marks the start of split point. + * @return the sub-string value starting from the given character. + */ + public static String stripBefore(String value, char c) { + String result = value; + if (value != null) { + int index = value.indexOf(c); + if (index > 0) { + result = value.substring(0, index); + } + } + return result; + } + + private static Method findSetterMethod(Class<?> clazz, String name) { + // Build the method name. + name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + Class<?>[] params = method.getParameterTypes(); + if (method.getName().equals(name) && params.length == 1) { + return method; + } + } + return null; + } + + private static Object convert(Object value, Class<?> type) throws Exception { + if (value == null) { + if (boolean.class.isAssignableFrom(type)) { + return Boolean.FALSE; + } + return null; + } + + if (type.isAssignableFrom(value.getClass())) { + return type.cast(value); + } + + // special for String[] as we do not want to use a PropertyEditor for that + if (type.isAssignableFrom(String[].class)) { + return StringArrayConverter.convertToStringArray(value); + } + + if (type == URI.class) { + return new URI(value.toString()); + } + + return TypeConversionSupport.convert(value, type); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/StringArrayConverter.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/StringArrayConverter.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/StringArrayConverter.java new file mode 100644 index 0000000..3fc9eb4 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/StringArrayConverter.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Class for converting to/from String[] to be used instead of a + * {@link java.beans.PropertyEditor} which otherwise causes memory leaks as the + * JDK {@link java.beans.PropertyEditorManager} is a static class and has strong + * references to classes, causing problems in hot-deployment environments. + */ +public class StringArrayConverter { + + public static String[] convertToStringArray(Object value) { + if (value == null) { + return null; + } + + String text = value.toString(); + if (text == null || text.isEmpty()) { + return null; + } + + StringTokenizer stok = new StringTokenizer(text, ","); + final List<String> list = new ArrayList<>(); + + while (stok.hasMoreTokens()) { + list.add(stok.nextToken()); + } + + String[] array = list.toArray(new String[list.size()]); + return array; + } + + public static String convertToString(String[] value) { + if (value == null || value.length == 0) { + return null; + } + + StringBuffer result = new StringBuffer(String.valueOf(value[0])); + for (int i = 1; i < value.length; i++) { + result.append(",").append(value[i]); + } + + return result.toString(); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/TypeConversionSupport.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/TypeConversionSupport.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/TypeConversionSupport.java new file mode 100644 index 0000000..7d07551 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/TypeConversionSupport.java @@ -0,0 +1,218 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.util.Date; +import java.util.HashMap; + +public final class TypeConversionSupport { + + static class ConversionKey { + + final Class<?> from; + final Class<?> to; + final int hashCode; + + ConversionKey(Class<?> from, Class<?> to) { + this.from = from; + this.to = to; + this.hashCode = from.hashCode() ^ (to.hashCode() << 1); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || o.getClass() != this.getClass()) { + return false; + } + + ConversionKey x = (ConversionKey) o; + return x.from == from && x.to == to; + } + + @Override + public int hashCode() { + return hashCode; + } + } + + interface Converter { + + Object convert(Object value); + } + + private static final HashMap<ConversionKey, Converter> CONVERSION_MAP = new HashMap<>(); + + static { + Converter toStringConverter = new Converter() { + @Override + public Object convert(Object value) { + return value.toString(); + } + }; + CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter); + CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter); + + CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() { + @Override + public Object convert(Object value) { + return Boolean.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() { + @Override + public Object convert(Object value) { + return Byte.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() { + @Override + public Object convert(Object value) { + return Short.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() { + @Override + public Object convert(Object value) { + return Integer.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() { + @Override + public Object convert(Object value) { + return Long.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() { + @Override + public Object convert(Object value) { + return Float.valueOf((String) value); + } + }); + CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() { + @Override + public Object convert(Object value) { + return Double.valueOf((String) value); + } + }); + + Converter longConverter = new Converter() { + @Override + public Object convert(Object value) { + return Long.valueOf(((Number) value).longValue()); + } + }; + CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter); + CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter); + CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter); + CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() { + @Override + public Object convert(Object value) { + return Long.valueOf(((Date) value).getTime()); + } + }); + + Converter intConverter = new Converter() { + @Override + public Object convert(Object value) { + return Integer.valueOf(((Number) value).intValue()); + } + }; + CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter); + CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter); + + CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() { + @Override + public Object convert(Object value) { + return Short.valueOf(((Number) value).shortValue()); + } + }); + + CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() { + @Override + public Object convert(Object value) { + return new Double(((Number) value).doubleValue()); + } + }); + } + + public static Object convert(Object value, Class<?> toClass) { + + assert value != null && toClass != null; + + if (value.getClass() == toClass) { + return value; + } + + Class<?> fromClass = value.getClass(); + + if (fromClass.isPrimitive()) { + fromClass = convertPrimitiveTypeToWrapperType(fromClass); + } + + if (toClass.isPrimitive()) { + toClass = convertPrimitiveTypeToWrapperType(toClass); + } + + Converter c = CONVERSION_MAP.get(new ConversionKey(fromClass, toClass)); + if (c == null) { + return null; + } + + return c.convert(value); + } + + private static Class<?> convertPrimitiveTypeToWrapperType(Class<?> type) { + Class<?> rc = type; + if (type.isPrimitive()) { + if (type == int.class) { + rc = Integer.class; + } + else if (type == long.class) { + rc = Long.class; + } + else if (type == double.class) { + rc = Double.class; + } + else if (type == float.class) { + rc = Float.class; + } + else if (type == short.class) { + rc = Short.class; + } + else if (type == byte.class) { + rc = Byte.class; + } + else if (type == boolean.class) { + rc = Boolean.class; + } + } + + return rc; + } + + private TypeConversionSupport() { + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableConnection.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableConnection.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableConnection.java new file mode 100644 index 0000000..32003a4 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableConnection.java @@ -0,0 +1,202 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.util.EnumSet; +import java.util.Map; + +import org.apache.qpid.proton.amqp.Symbol; +import org.apache.qpid.proton.amqp.transport.ErrorCondition; +import org.apache.qpid.proton.engine.Collector; +import org.apache.qpid.proton.engine.Connection; +import org.apache.qpid.proton.engine.Delivery; +import org.apache.qpid.proton.engine.EndpointState; +import org.apache.qpid.proton.engine.Link; +import org.apache.qpid.proton.engine.Record; +import org.apache.qpid.proton.engine.Session; +import org.apache.qpid.proton.engine.Transport; +import org.apache.qpid.proton.reactor.Reactor; + +/** + * Unmodifiable Connection wrapper used to prevent test code from accidentally + * modifying Connection state. + */ +public class UnmodifiableConnection implements Connection { + + private final Connection connection; + + public UnmodifiableConnection(Connection connection) { + this.connection = connection; + } + + @Override + public EndpointState getLocalState() { + return connection.getLocalState(); + } + + @Override + public EndpointState getRemoteState() { + return connection.getRemoteState(); + } + + @Override + public ErrorCondition getCondition() { + return connection.getCondition(); + } + + @Override + public void setCondition(ErrorCondition condition) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public ErrorCondition getRemoteCondition() { + return connection.getRemoteCondition(); + } + + @Override + public void free() { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public void open() { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public void close() { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public Session session() { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public Session sessionHead(EnumSet<EndpointState> local, EnumSet<EndpointState> remote) { + Session head = connection.sessionHead(local, remote); + if (head != null) { + head = new UnmodifiableSession(head); + } + + return head; + } + + @Override + public Link linkHead(EnumSet<EndpointState> local, EnumSet<EndpointState> remote) { + // TODO - If implemented this method should return an unmodifiable link isntance. + return null; + } + + @Override + public Delivery getWorkHead() { + // TODO - If implemented this method should return an unmodifiable delivery isntance. + return null; + } + + @Override + public void setContainer(String container) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public void setHostname(String hostname) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public String getHostname() { + return connection.getHostname(); + } + + @Override + public String getRemoteContainer() { + return connection.getRemoteContainer(); + } + + @Override + public String getRemoteHostname() { + return connection.getRemoteHostname(); + } + + @Override + public void setOfferedCapabilities(Symbol[] capabilities) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public void setDesiredCapabilities(Symbol[] capabilities) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public Symbol[] getRemoteOfferedCapabilities() { + return connection.getRemoteOfferedCapabilities(); + } + + @Override + public Symbol[] getRemoteDesiredCapabilities() { + return connection.getRemoteDesiredCapabilities(); + } + + @Override + public Map<Symbol, Object> getRemoteProperties() { + return connection.getRemoteProperties(); + } + + @Override + public void setProperties(Map<Symbol, Object> properties) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public Object getContext() { + return connection.getContext(); + } + + @Override + public void setContext(Object context) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public void collect(Collector collector) { + throw new UnsupportedOperationException("Cannot alter the Connection"); + } + + @Override + public String getContainer() { + return connection.getContainer(); + } + + @Override + public Transport getTransport() { + return new UnmodifiableTransport(connection.getTransport()); + } + + @Override + public Record attachments() { + return connection.attachments(); + } + + @Override + public Reactor getReactor() { + return connection.getReactor(); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableDelivery.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableDelivery.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableDelivery.java new file mode 100644 index 0000000..9f48b41 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableDelivery.java @@ -0,0 +1,170 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import org.apache.qpid.proton.amqp.transport.DeliveryState; +import org.apache.qpid.proton.engine.Delivery; +import org.apache.qpid.proton.engine.Link; +import org.apache.qpid.proton.engine.Receiver; +import org.apache.qpid.proton.engine.Record; +import org.apache.qpid.proton.engine.Sender; + +/** + * Unmodifiable Delivery wrapper used to prevent test code from accidentally + * modifying Delivery state. + */ +public class UnmodifiableDelivery implements Delivery { + + private final Delivery delivery; + + public UnmodifiableDelivery(Delivery delivery) { + this.delivery = delivery; + } + + @Override + public byte[] getTag() { + return delivery.getTag(); + } + + @Override + public Link getLink() { + if (delivery.getLink() instanceof Sender) { + return new UnmodifiableSender((Sender) delivery.getLink()); + } + else if (delivery.getLink() instanceof Receiver) { + return new UnmodifiableReceiver((Receiver) delivery.getLink()); + } + else { + throw new IllegalStateException("Delivery has unknown link type"); + } + } + + @Override + public DeliveryState getLocalState() { + return delivery.getLocalState(); + } + + @Override + public DeliveryState getRemoteState() { + return delivery.getRemoteState(); + } + + @Override + public int getMessageFormat() { + return delivery.getMessageFormat(); + } + + @Override + public void disposition(DeliveryState state) { + throw new UnsupportedOperationException("Cannot alter the Delivery state"); + } + + @Override + public void settle() { + throw new UnsupportedOperationException("Cannot alter the Delivery state"); + } + + @Override + public boolean isSettled() { + return delivery.isSettled(); + } + + @Override + public boolean remotelySettled() { + return delivery.remotelySettled(); + } + + @Override + public void free() { + throw new UnsupportedOperationException("Cannot alter the Delivery state"); + } + + @Override + public Delivery getWorkNext() { + return new UnmodifiableDelivery(delivery.getWorkNext()); + } + + @Override + public Delivery next() { + return new UnmodifiableDelivery(delivery.next()); + } + + @Override + public boolean isWritable() { + return delivery.isWritable(); + } + + @Override + public boolean isReadable() { + return delivery.isReadable(); + } + + @Override + public void setContext(Object o) { + throw new UnsupportedOperationException("Cannot alter the Delivery state"); + } + + @Override + public Object getContext() { + return delivery.getContext(); + } + + @Override + public boolean isUpdated() { + return delivery.isUpdated(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("Cannot alter the Delivery state"); + } + + @Override + public boolean isPartial() { + return delivery.isPartial(); + } + + @Override + public int pending() { + return delivery.pending(); + } + + @Override + public boolean isBuffered() { + return delivery.isBuffered(); + } + + @Override + public Record attachments() { + return delivery.attachments(); + } + + @Override + public DeliveryState getDefaultDeliveryState() { + return delivery.getDefaultDeliveryState(); + } + + @Override + public void setDefaultDeliveryState(DeliveryState state) { + throw new UnsupportedOperationException("Cannot alter the Delivery"); + } + + @Override + public void setMessageFormat(int messageFormat) { + throw new UnsupportedOperationException("Cannot alter the Delivery"); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableLink.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableLink.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableLink.java new file mode 100644 index 0000000..a58bfe7 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableLink.java @@ -0,0 +1,276 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.util.EnumSet; +import java.util.Map; + +import org.apache.qpid.proton.amqp.Symbol; +import org.apache.qpid.proton.amqp.transport.ErrorCondition; +import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode; +import org.apache.qpid.proton.amqp.transport.SenderSettleMode; +import org.apache.qpid.proton.amqp.transport.Source; +import org.apache.qpid.proton.amqp.transport.Target; +import org.apache.qpid.proton.engine.Delivery; +import org.apache.qpid.proton.engine.EndpointState; +import org.apache.qpid.proton.engine.Link; +import org.apache.qpid.proton.engine.Receiver; +import org.apache.qpid.proton.engine.Record; +import org.apache.qpid.proton.engine.Sender; +import org.apache.qpid.proton.engine.Session; + +/** + * Unmodifiable Session wrapper used to prevent test code from accidentally + * modifying Session state. + */ +public class UnmodifiableLink implements Link { + + private final Link link; + + public UnmodifiableLink(Link link) { + this.link = link; + } + + @Override + public EndpointState getLocalState() { + return link.getLocalState(); + } + + @Override + public EndpointState getRemoteState() { + return link.getRemoteState(); + } + + @Override + public ErrorCondition getCondition() { + return link.getCondition(); + } + + @Override + public void setCondition(ErrorCondition condition) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public ErrorCondition getRemoteCondition() { + return link.getRemoteCondition(); + } + + @Override + public void free() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void open() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void close() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void setContext(Object o) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Object getContext() { + return link.getContext(); + } + + @Override + public String getName() { + return link.getName(); + } + + @Override + public Delivery delivery(byte[] tag) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Delivery delivery(byte[] tag, int offset, int length) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Delivery head() { + return new UnmodifiableDelivery(link.head()); + } + + @Override + public Delivery current() { + return new UnmodifiableDelivery(link.current()); + } + + @Override + public boolean advance() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Source getSource() { + // TODO Figure out a simple way to wrap the odd Source types in Proton-J + return link.getSource(); + } + + @Override + public Target getTarget() { + // TODO Figure out a simple way to wrap the odd Source types in Proton-J + return link.getTarget(); + } + + @Override + public void setSource(Source address) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void setTarget(Target address) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Source getRemoteSource() { + // TODO Figure out a simple way to wrap the odd Source types in Proton-J + return link.getRemoteSource(); + } + + @Override + public Target getRemoteTarget() { + // TODO Figure out a simple way to wrap the odd Target types in Proton-J + return link.getRemoteTarget(); + } + + @Override + public Link next(EnumSet<EndpointState> local, EnumSet<EndpointState> remote) { + Link next = link.next(local, remote); + + if (next != null) { + if (next instanceof Sender) { + next = new UnmodifiableSender((Sender) next); + } + else { + next = new UnmodifiableReceiver((Receiver) next); + } + } + + return next; + } + + @Override + public int getCredit() { + return link.getCredit(); + } + + @Override + public int getQueued() { + return link.getQueued(); + } + + @Override + public int getUnsettled() { + return link.getUnsettled(); + } + + @Override + public Session getSession() { + return new UnmodifiableSession(link.getSession()); + } + + @Override + public SenderSettleMode getSenderSettleMode() { + return link.getSenderSettleMode(); + } + + @Override + public void setSenderSettleMode(SenderSettleMode senderSettleMode) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public SenderSettleMode getRemoteSenderSettleMode() { + return link.getRemoteSenderSettleMode(); + } + + @Override + public ReceiverSettleMode getReceiverSettleMode() { + return link.getReceiverSettleMode(); + } + + @Override + public void setReceiverSettleMode(ReceiverSettleMode receiverSettleMode) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public ReceiverSettleMode getRemoteReceiverSettleMode() { + return link.getRemoteReceiverSettleMode(); + } + + @Override + public void setRemoteSenderSettleMode(SenderSettleMode remoteSenderSettleMode) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public int drained() { + return link.drained(); // TODO - Is this a mutating call? + } + + @Override + public int getRemoteCredit() { + return link.getRemoteCredit(); + } + + @Override + public boolean getDrain() { + return link.getDrain(); + } + + @Override + public void detach() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public boolean detached() { + return link.detached(); + } + + public Record attachments() { + return link.attachments(); + } + + @Override + public Map<Symbol, Object> getProperties() { + return link.getProperties(); + } + + @Override + public void setProperties(Map<Symbol, Object> properties) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public Map<Symbol, Object> getRemoteProperties() { + return link.getRemoteProperties(); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableReceiver.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableReceiver.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableReceiver.java new file mode 100644 index 0000000..92760db --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableReceiver.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import org.apache.qpid.proton.engine.Receiver; + +/** + * Unmodifiable Receiver wrapper used to prevent test code from accidentally + * modifying Receiver state. + */ +public class UnmodifiableReceiver extends UnmodifiableLink implements Receiver { + + private final Receiver receiver; + + public UnmodifiableReceiver(Receiver receiver) { + super(receiver); + + this.receiver = receiver; + } + + @Override + public void flow(int credits) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public int recv(byte[] bytes, int offset, int size) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void drain(int credit) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public boolean draining() { + return receiver.draining(); + } + + @Override + public void setDrain(boolean drain) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSender.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSender.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSender.java new file mode 100644 index 0000000..89742cb --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSender.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import org.apache.qpid.proton.engine.Sender; + +/** + * Unmodifiable Sender wrapper used to prevent test code from accidentally + * modifying Sender state. + */ +public class UnmodifiableSender extends UnmodifiableLink implements Sender { + + public UnmodifiableSender(Sender sender) { + super(sender); + } + + @Override + public void offer(int credits) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public int send(byte[] bytes, int offset, int length) { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } + + @Override + public void abort() { + throw new UnsupportedOperationException("Cannot alter the Link state"); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSession.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSession.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSession.java new file mode 100644 index 0000000..a44028e --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableSession.java @@ -0,0 +1,150 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.util.EnumSet; + +import org.apache.qpid.proton.amqp.transport.ErrorCondition; +import org.apache.qpid.proton.engine.Connection; +import org.apache.qpid.proton.engine.EndpointState; +import org.apache.qpid.proton.engine.Receiver; +import org.apache.qpid.proton.engine.Record; +import org.apache.qpid.proton.engine.Sender; +import org.apache.qpid.proton.engine.Session; + +/** + * Unmodifiable Session wrapper used to prevent test code from accidentally + * modifying Session state. + */ +public class UnmodifiableSession implements Session { + + private final Session session; + + public UnmodifiableSession(Session session) { + this.session = session; + } + + @Override + public EndpointState getLocalState() { + return session.getLocalState(); + } + + @Override + public EndpointState getRemoteState() { + return session.getRemoteState(); + } + + @Override + public ErrorCondition getCondition() { + return session.getCondition(); + } + + @Override + public void setCondition(ErrorCondition condition) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public ErrorCondition getRemoteCondition() { + return session.getRemoteCondition(); + } + + @Override + public void free() { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public void open() { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public void close() { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public void setContext(Object o) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public Object getContext() { + return session.getContext(); + } + + @Override + public Sender sender(String name) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public Receiver receiver(String name) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public Session next(EnumSet<EndpointState> local, EnumSet<EndpointState> remote) { + Session next = session.next(local, remote); + if (next != null) { + next = new UnmodifiableSession(next); + } + + return next; + } + + @Override + public Connection getConnection() { + return new UnmodifiableConnection(session.getConnection()); + } + + @Override + public int getIncomingCapacity() { + return session.getIncomingCapacity(); + } + + @Override + public void setIncomingCapacity(int bytes) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } + + @Override + public int getIncomingBytes() { + return session.getIncomingBytes(); + } + + @Override + public int getOutgoingBytes() { + return session.getOutgoingBytes(); + } + + @Override + public Record attachments() { + return session.attachments(); + } + + @Override + public long getOutgoingWindow() { + return session.getOutgoingWindow(); + } + + @Override + public void setOutgoingWindow(long outgoingWindowSize) { + throw new UnsupportedOperationException("Cannot alter the Session"); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableTransport.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableTransport.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableTransport.java new file mode 100644 index 0000000..5e305f4 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/UnmodifiableTransport.java @@ -0,0 +1,274 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +import java.nio.ByteBuffer; + +import org.apache.qpid.proton.amqp.transport.ErrorCondition; +import org.apache.qpid.proton.engine.Connection; +import org.apache.qpid.proton.engine.EndpointState; +import org.apache.qpid.proton.engine.Record; +import org.apache.qpid.proton.engine.Sasl; +import org.apache.qpid.proton.engine.Ssl; +import org.apache.qpid.proton.engine.SslDomain; +import org.apache.qpid.proton.engine.SslPeerDetails; +import org.apache.qpid.proton.engine.Transport; +import org.apache.qpid.proton.engine.TransportException; +import org.apache.qpid.proton.engine.TransportResult; + +/** + * Unmodifiable Transport wrapper used to prevent test code from accidentally + * modifying Transport state. + */ +public class UnmodifiableTransport implements Transport { + + private final Transport transport; + + public UnmodifiableTransport(Transport transport) { + this.transport = transport; + } + + @Override + public void close() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void free() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public Object getContext() { + return null; + } + + @Override + public EndpointState getLocalState() { + return transport.getLocalState(); + } + + @Override + public ErrorCondition getRemoteCondition() { + return transport.getRemoteCondition(); + } + + @Override + public EndpointState getRemoteState() { + return transport.getRemoteState(); + } + + @Override + public void open() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void setCondition(ErrorCondition arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void setContext(Object arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void bind(Connection arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public int capacity() { + return transport.capacity(); + } + + @Override + public void close_head() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void close_tail() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public int getChannelMax() { + return transport.getChannelMax(); + } + + @Override + public ErrorCondition getCondition() { + return transport.getCondition(); + } + + @Override + public int getIdleTimeout() { + return transport.getIdleTimeout(); + } + + @Override + public ByteBuffer getInputBuffer() { + return null; + } + + @Override + public int getMaxFrameSize() { + return transport.getMaxFrameSize(); + } + + @Override + public ByteBuffer getOutputBuffer() { + return null; + } + + @Override + public int getRemoteChannelMax() { + return transport.getRemoteChannelMax(); + } + + @Override + public int getRemoteIdleTimeout() { + return transport.getRemoteIdleTimeout(); + } + + @Override + public int getRemoteMaxFrameSize() { + return transport.getRemoteMaxFrameSize(); + } + + @Override + public ByteBuffer head() { + return null; + } + + @Override + public int input(byte[] arg0, int arg1, int arg2) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public boolean isClosed() { + return transport.isClosed(); + } + + @Override + public int output(byte[] arg0, int arg1, int arg2) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void outputConsumed() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public int pending() { + return transport.pending(); + } + + @Override + public void pop(int arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void process() throws TransportException { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public TransportResult processInput() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public Sasl sasl() throws IllegalStateException { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void setChannelMax(int arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void setIdleTimeout(int arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void setMaxFrameSize(int arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public Ssl ssl(SslDomain arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public Ssl ssl(SslDomain arg0, SslPeerDetails arg1) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public ByteBuffer tail() { + return null; + } + + @Override + public long tick(long arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void trace(int arg0) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public void unbind() { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public Record attachments() { + return transport.attachments(); + } + + @Override + public long getFramesInput() { + return transport.getFramesInput(); + } + + @Override + public long getFramesOutput() { + return transport.getFramesOutput(); + } + + @Override + public void setEmitFlowEventOnSend(boolean emitFlowEventOnSend) { + throw new UnsupportedOperationException("Cannot alter the Transport"); + } + + @Override + public boolean isEmitFlowEventOnSend() { + return transport.isEmitFlowEventOnSend(); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/WrappedAsyncResult.java ---------------------------------------------------------------------- diff --git a/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/WrappedAsyncResult.java b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/WrappedAsyncResult.java new file mode 100644 index 0000000..bfe9a80 --- /dev/null +++ b/tests/artemis-test-support/src/main/java/org/apache/activemq/transport/amqp/client/util/WrappedAsyncResult.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.transport.amqp.client.util; + +/** + * Base class used to wrap one AsyncResult with another. + */ +public abstract class WrappedAsyncResult implements AsyncResult { + + protected final AsyncResult wrapped; + + /** + * Create a new WrappedAsyncResult for the target AsyncResult + */ + public WrappedAsyncResult(AsyncResult wrapped) { + this.wrapped = wrapped; + } + + @Override + public void onFailure(Throwable result) { + if (wrapped != null) { + wrapped.onFailure(result); + } + } + + @Override + public void onSuccess() { + if (wrapped != null) { + wrapped.onSuccess(); + } + } + + @Override + public boolean isComplete() { + if (wrapped != null) { + return wrapped.isComplete(); + } + + return false; + } + + public AsyncResult getWrappedRequest() { + return wrapped; + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/integration-tests/pom.xml ---------------------------------------------------------------------- diff --git a/tests/integration-tests/pom.xml b/tests/integration-tests/pom.xml index 752e288..5d7617c 100644 --- a/tests/integration-tests/pom.xml +++ b/tests/integration-tests/pom.xml @@ -340,6 +340,11 @@ <artifactId>org.apache.karaf.shell.console</artifactId> <version>${karaf.version}</version> </dependency> + <dependency> + <groupId>org.apache.activemq.tests</groupId> + <artifactId>artemis-test-support</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> <build> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/df41a60e/tests/pom.xml ---------------------------------------------------------------------- diff --git a/tests/pom.xml b/tests/pom.xml index 6a9c000..a2efeac 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -46,6 +46,13 @@ <version>1.2</version> <!-- License: Apache: 2.0 --> </dependency> + <dependency> + <groupId>org.apache.qpid</groupId> + <artifactId>qpid-jms-client</artifactId> + <version>0.10.0</version> + <!-- License: Apache: 2.0 --> + </dependency> + <!-- End JMS Dependencies --> </dependencies> </dependencyManagement> @@ -122,5 +129,6 @@ <module>soak-tests</module> <module>stress-tests</module> <module>performance-tests</module> + <module>artemis-test-support</module> </modules> </project>
