Repository: aries-rsa Updated Branches: refs/heads/master 58bb694dc -> 62d835dec
http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/ClassLoaderObjectInputStream.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/ClassLoaderObjectInputStream.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/ClassLoaderObjectInputStream.java new file mode 100644 index 0000000..63138c0 --- /dev/null +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/ClassLoaderObjectInputStream.java @@ -0,0 +1,86 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.lang.reflect.Proxy; +import java.util.HashMap; + +public class ClassLoaderObjectInputStream extends ObjectInputStream { + + /** <p>Maps primitive type names to corresponding class objects.</p> */ + private static final HashMap<String, Class> primClasses = new HashMap<String, Class>(8, 1.0F); + + private ClassLoader classLoader; + + public ClassLoaderObjectInputStream(InputStream in) throws IOException { + super(in); + } + + public ClassLoader getClassLoader() { + return classLoader; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + protected Class resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException { + return load(classDesc.getName()); + } + + protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { + Class[] cinterfaces = new Class[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) { + cinterfaces[i] = load(interfaces[i]); + } + + try { + return Proxy.getProxyClass(classLoader, cinterfaces); + } catch (IllegalArgumentException e) { + throw new ClassNotFoundException(null, e); + } + } + + private Class load(String className) + throws ClassNotFoundException { + try { + return Class.forName(className, false, classLoader); + } catch (ClassNotFoundException e) { + final Class clazz = primClasses.get(className); + if (clazz != null) { + return clazz; + } else { + throw e; + } + } + } + + static { + primClasses.put("boolean", boolean.class); + primClasses.put("byte", byte.class); + primClasses.put("char", char.class); + primClasses.put("short", short.class); + primClasses.put("int", int.class); + primClasses.put("long", long.class); + primClasses.put("float", float.class); + primClasses.put("double", double.class); + primClasses.put("void", void.class); + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/IntrospectionSupport.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/IntrospectionSupport.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/IntrospectionSupport.java new file mode 100755 index 0000000..1d31218 --- /dev/null +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/IntrospectionSupport.java @@ -0,0 +1,362 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin.util; + +import java.beans.PropertyEditor; +import java.beans.PropertyEditorManager; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + + + +public final class IntrospectionSupport { + + private IntrospectionSupport() { + } + + public static boolean getProperties(Object target, Map props, String optionPrefix) { + + boolean rc = false; + if (target == null) { + throw new IllegalArgumentException("target was null."); + } + if (props == null) { + throw new IllegalArgumentException("props was null."); + } + + if (optionPrefix == null) { + optionPrefix = ""; + } + + Class<?> clazz = target.getClass(); + Method[] methods = clazz.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + String name = method.getName(); + Class<?> type = method.getReturnType(); + Class<?> params[] = method.getParameterTypes(); + if ((name.startsWith("is") || name.startsWith("get")) && params.length == 0 && type != null && isSettableType(type)) { + + try { + + Object value = method.invoke(target, new Object[] {}); + if (value == null) { + continue; + } + + String strValue = convertToString(value, type); + if (strValue == null) { + continue; + } + if (name.startsWith("get")) { + name = name.substring(3, 4).toLowerCase() + + name.substring(4); + } else { + name = name.substring(2, 3).toLowerCase() + + name.substring(3); + } + props.put(optionPrefix + name, strValue); + rc = true; + + } catch (Throwable ignore) { + } + + } + } + + return rc; + } + + public static boolean setProperties(Object target, Map<String, ?> props, String optionPrefix) { + boolean rc = false; + if (target == null) { + throw new IllegalArgumentException("target was null."); + } + if (props == null) { + throw new IllegalArgumentException("props was null."); + } + + for (Iterator<String> iter = props.keySet().iterator(); iter.hasNext();) { + String name = iter.next(); + if (name.startsWith(optionPrefix)) { + Object value = props.get(name); + name = name.substring(optionPrefix.length()); + if (setProperty(target, name, value)) { + iter.remove(); + rc = true; + } + } + } + return rc; + } + + public static Map<String, Object> extractProperties(Map props, String optionPrefix) { + if (props == null) { + throw new IllegalArgumentException("props was null."); + } + + HashMap<String, Object> rc = new HashMap<String, Object>(props.size()); + + for (Iterator<Entry> iter = props.entrySet().iterator(); iter.hasNext();) { + Entry entry = iter.next(); + String name = (String)entry.getKey(); + if (name.startsWith(optionPrefix)) { + name = name.substring(optionPrefix.length()); + rc.put(name, entry.getValue()); + iter.remove(); + } + } + + return rc; + } + + public static boolean setProperties(Object target, Map props) { + boolean rc = false; + + if (target == null) { + throw new IllegalArgumentException("target was null."); + } + if (props == null) { + throw new IllegalArgumentException("props was null."); + } + + for (Iterator<Entry> iter = props.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = iter.next(); + if (setProperty(target, (String)entry.getKey(), entry.getValue())) { + iter.remove(); + rc = true; + } + } + + return rc; + } + + public static Class<?> getPropertyType(Object target, String name) { + Class<?> clazz = target.getClass(); + Method setter = findSetterMethod(clazz, name); + if (setter == null) { + return null; + } + return setter.getParameterTypes()[0]; + } + + public static boolean setProperty(Object target, String name, Object value) { + try { + 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 { + // We need to convert it + setter.invoke(target, new Object[] {convert(value, setter.getParameterTypes()[0])}); + } + return true; + } catch (Throwable ignore) { + return false; + } + } + + private static Object convert(Object value, Class<?> type) { + if( type.isArray() ) { + if( value.getClass().isArray() ) { + int length = Array.getLength(value); + Class<?> componentType = type.getComponentType(); + Object rc = Array.newInstance(componentType, length); + for (int i = 0; i < length; i++) { + Object o = Array.get(value, i); + Array.set(rc, i, convert(o, componentType)); + } + return rc; + } + } + PropertyEditor editor = PropertyEditorManager.findEditor(type); + if (editor != null) { + editor.setAsText(value.toString()); + return editor.getValue(); + } + return null; + } + + public static String convertToString(Object value, Class<?> type) { + PropertyEditor editor = PropertyEditorManager.findEditor(type); + if (editor != null) { + editor.setValue(value); + return editor.getAsText(); + } + return null; + } + + 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 boolean isSettableType(Class<?> clazz) { + if (PropertyEditorManager.findEditor(clazz) != null) { + return true; + } + + return false; + } + + public static String toString(Object target) { + return toString(target, Object.class, null, (String[])null); + } + + public static String toString(Object target, String...fields) { + return toString(target, Object.class, null, fields); + } + + public static String toString(Object target, Class<?> stopClass) { + return toString(target, stopClass, null, (String[])null); + } + + public static String toString(Object target, Map<String, Object> overrideFields, String...fields) { + return toString(target, Object.class, overrideFields, fields); + } + + public static String toString(Object target, Class<?> stopClass, Map<String, Object> overrideFields, String ... fields) { + try { + LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>(); + addFields(target, target.getClass(), stopClass, map); + if (overrideFields != null) { + for(String key : overrideFields.keySet()) { + Object value = overrideFields.get(key); + map.put(key, value); + } + } + + if( fields!=null ) { + map.keySet().retainAll(Arrays.asList(fields)); + } + + boolean useMultiLine=false; + LinkedHashMap<String, String> props = new LinkedHashMap<String, String>(); + for (Entry<String, Object> entry : map.entrySet()) { + String key = entry.getKey(); + String value = null; + if( entry.getValue() !=null ) { + value = entry.getValue().toString(); + if( value!=null && ( value.indexOf('\n')>=0 || (key.length()+value.length())>70 ) ) { + useMultiLine=true; + } + } + props.put(key, value); + } + + StringBuffer buffer = new StringBuffer(); + if( useMultiLine) { + buffer.append("{\n"); + boolean first = true; + for (Entry<String, String> entry : props.entrySet()) { + if (first) { + first = false; + } else { + buffer.append(",\n"); + } + buffer.append(" "); + buffer.append(entry.getKey()); + buffer.append(": "); + buffer.append(StringSupport.indent(entry.getValue(), 2)); + } + buffer.append("\n}"); + } else { + buffer.append("{"); + boolean first = true; + for (Entry<String, String> entry : props.entrySet()) { + if (first) { + first = false; + } else { + buffer.append(", "); + } + buffer.append(entry.getKey()); + buffer.append(": "); + String value = entry.getValue(); + buffer.append(value); + } + buffer.append("}"); + } + return buffer.toString(); + } catch (Throwable e) { + e.printStackTrace(); + return "Could not toString: "+e.toString(); + } + } + + + public static String simpleName(Class<?> clazz) { + String name = clazz.getName(); + int p = name.lastIndexOf("."); + if (p >= 0) { + name = name.substring(p + 1); + } + return name; + } + + private static void addFields(Object target, Class<?> startClass, Class<?> stopClass, LinkedHashMap<String, Object> map) { + + if (startClass != stopClass) { + addFields(target, startClass.getSuperclass(), stopClass, map); + } + + Field[] fields = startClass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + + try { + field.setAccessible(true); + Object o = field.get(target); + if (o != null && o.getClass().isArray()) { + try { + o = Arrays.asList((Object[])o); + } catch (Throwable e) { + } + } + map.put(field.getName(), o); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/StringSupport.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/StringSupport.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/StringSupport.java new file mode 100644 index 0000000..a8e0cd7 --- /dev/null +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/StringSupport.java @@ -0,0 +1,40 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin.util; + +import java.util.Arrays; + +/** + * Helper class to hold common text/string manipulation methods. + * + */ +public class StringSupport { + + public static String indent(String value, int spaces) { + if( value == null ) { + return null; + } + String indent = fillString(spaces, ' '); + return value.replaceAll("(\\r?\\n)", "$1"+indent); + } + + public static String fillString(int count, char character) { + char t[] = new char[count]; + Arrays.fill(t, character); + return new String(t); + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/URISupport.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/URISupport.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/URISupport.java new file mode 100755 index 0000000..bed7923 --- /dev/null +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/URISupport.java @@ -0,0 +1,332 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin.util; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + */ +public class URISupport { + + public static class CompositeData { + private String host; + private String scheme; + private String path; + private URI components[]; + private Map<String, String> parameters; + private String fragment; + + public URI[] getComponents() { + return components; + } + + public String getFragment() { + return fragment; + } + + public Map<String, String> getParameters() { + return parameters; + } + + public String getScheme() { + return scheme; + } + + public String getPath() { + return path; + } + + public String getHost() { + return host; + } + + public URI toURI() throws URISyntaxException { + StringBuffer sb = new StringBuffer(); + if (scheme != null) { + sb.append(scheme); + sb.append(':'); + } + + if (host != null && host.length() != 0) { + sb.append(host); + } else { + sb.append('('); + for (int i = 0; i < components.length; i++) { + if (i != 0) { + sb.append(','); + } + sb.append(components[i].toString()); + } + sb.append(')'); + } + + if (path != null) { + sb.append('/'); + sb.append(path); + } + if (!parameters.isEmpty()) { + sb.append("?"); + sb.append(createQueryString(parameters)); + } + if (fragment != null) { + sb.append("#"); + sb.append(fragment); + } + return new URI(sb.toString()); + } + } + + public static Map<String, String> parseQuery(String uri) throws URISyntaxException { + try { + Map<String, String> rc = new HashMap<String, String>(); + if (uri != null) { + String[] parameters = uri.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; + } catch (UnsupportedEncodingException e) { + throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e); + } + } + + public static Map<String, String> parseParameters(URI uri) throws URISyntaxException { + return uri.getQuery() == null ? emptyMap() : parseQuery(stripPrefix(uri.getQuery(), "?")); + } + + @SuppressWarnings("unchecked") + private static Map<String, String> emptyMap() { + return Collections.EMPTY_MAP; + } + + /** + * Removes any URI query from the given uri + */ + public static URI removeQuery(URI uri) throws URISyntaxException { + return createURIWithQuery(uri, null); + } + + /** + * Creates a URI with the given query + */ + public static URI createURIWithQuery(URI uri, String query) throws URISyntaxException { + return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), + query, uri.getFragment()); + } + + public static CompositeData parseComposite(URI uri) throws URISyntaxException { + + CompositeData rc = new CompositeData(); + rc.scheme = uri.getScheme(); + String ssp = stripPrefix(uri.getSchemeSpecificPart().trim(), "//").trim(); + + parseComposite(uri, rc, ssp); + + rc.fragment = uri.getFragment(); + return rc; + } + + /** + * @param uri + * @param rc + * @param ssp + * @throws URISyntaxException + */ + private static void parseComposite(URI uri, CompositeData rc, String ssp) throws URISyntaxException { + String componentString; + String params; + + if (!checkParenthesis(ssp)) { + throw new URISyntaxException(uri.toString(), "Not a matching number of '(' and ')' parenthesis"); + } + + int p; + int intialParen = ssp.indexOf("("); + if (intialParen == 0) { + rc.host = ssp.substring(0, intialParen); + p = rc.host.indexOf("/"); + if (p >= 0) { + rc.path = rc.host.substring(p); + rc.host = rc.host.substring(0, p); + } + p = ssp.lastIndexOf(")"); + componentString = ssp.substring(intialParen + 1, p); + params = ssp.substring(p + 1).trim(); + + } else { + componentString = ssp; + params = ""; + } + + String components[] = splitComponents(componentString); + rc.components = new URI[components.length]; + for (int i = 0; i < components.length; i++) { + rc.components[i] = new URI(components[i].trim()); + } + + p = params.indexOf("?"); + if (p >= 0) { + if (p > 0) { + rc.path = stripPrefix(params.substring(0, p), "/"); + } + rc.parameters = parseQuery(params.substring(p + 1)); + } else { + if (params.length() > 0) { + rc.path = stripPrefix(params, "/"); + } + rc.parameters = emptyMap(); + } + } + + /** + * @param str + * @return + */ + private static String[] splitComponents(String str) { + List<String> l = new ArrayList<String>(); + + int last = 0; + int depth = 0; + char chars[] = str.toCharArray(); + for (int i = 0; i < chars.length; i++) { + switch (chars[i]) { + case '(': + depth++; + break; + case ')': + depth--; + break; + case ',': + if (depth == 0) { + String s = str.substring(last, i); + l.add(s); + last = i + 1; + } + break; + default: + } + } + + String s = str.substring(last); + if (s.length() != 0) { + l.add(s); + } + + String rc[] = new String[l.size()]; + l.toArray(rc); + return rc; + } + + public static String stripPrefix(String value, String prefix) { + if (value.startsWith(prefix)) { + return value.substring(prefix.length()); + } + return value; + } + + public static URI stripScheme(URI uri) throws URISyntaxException { + return new URI(stripPrefix(uri.getSchemeSpecificPart().trim(), "//")); + } + + public static String createQueryString(Map<String,String> options) throws URISyntaxException { + try { + if (options.size() > 0) { + StringBuffer rc = new StringBuffer(); + boolean first = true; + for (Map.Entry<String,String> entry : options.entrySet()) { + if (first) { + first = false; + } else { + rc.append("&"); + } + String key = entry.getKey(); + String value = entry.getValue(); + rc.append(URLEncoder.encode(key, "UTF-8")); + rc.append("="); + rc.append(URLEncoder.encode(value, "UTF-8")); + } + return rc.toString(); + } else { + return ""; + } + } catch (UnsupportedEncodingException e) { + throw (URISyntaxException)new URISyntaxException(e.toString(), "Invalid encoding").initCause(e); + } + } + + /** + * Creates a URI from the original URI and the remaining paramaters + * + * @throws URISyntaxException + */ + public static URI createRemainingURI(URI originalURI, Map params) throws URISyntaxException { + String s = createQueryString(params); + if (s.length() == 0) { + s = null; + } + return createURIWithQuery(originalURI, s); + } + + public static URI changeScheme(URI bindAddr, String scheme) throws URISyntaxException { + return new URI(scheme, bindAddr.getUserInfo(), bindAddr.getHost(), bindAddr.getPort(), bindAddr + .getPath(), bindAddr.getQuery(), bindAddr.getFragment()); + } + + public static boolean checkParenthesis(String str) { + boolean result = true; + if (str != null) { + int open = 0; + int closed = 0; + + int i = 0; + while ((i = str.indexOf('(', i)) >= 0) { + i++; + open++; + } + i = 0; + while ((i = str.indexOf(')', i)) >= 0) { + i++; + closed++; + } + result = open == closed; + } + return result; + } + + public int indexOfParenthesisMatch(String str) { + int result = -1; + + return result; + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/UuidGenerator.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/UuidGenerator.java b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/UuidGenerator.java new file mode 100644 index 0000000..7f09e1a --- /dev/null +++ b/provider/fastbin/src/main/java/org/apache/aries/rsa/provider/fastbin/util/UuidGenerator.java @@ -0,0 +1,178 @@ +/** + * 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.aries.rsa.provider.fastbin.util; + +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; + + +/** + * A unique ID generator which is a fast implementation based on + * how <a href="http://activemq.apache.org/>Apache ActiveMQ</a> generates its UUID. + * <p/> + */ +public class UuidGenerator { + + private static final Logger LOG = LoggerFactory.getLogger(UuidGenerator.class); + private static final String UNIQUE_STUB; + private static int instanceCount; + private static String hostName; + private String seed; + private AtomicLong sequence = new AtomicLong(1); + private int length; + + private static UuidGenerator instance = null; + static { + String stub = ""; + boolean canAccessSystemProps = true; + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertiesAccess(); + } + } catch (SecurityException se) { + canAccessSystemProps = false; + } + + if (canAccessSystemProps) { + try { + hostName = getLocalHostName(); + ServerSocket ss = new ServerSocket(0); + stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-"; + Thread.sleep(100); + ss.close(); + } catch (Exception ioe) { + LOG.warn("could not generate unique stub", ioe); + } + } else { + hostName = "localhost"; + stub = "-1-" + System.currentTimeMillis() + "-"; + } + UNIQUE_STUB = stub; + } + + /** + * Construct an IdGenerator + */ + private UuidGenerator(String prefix) { + synchronized (UNIQUE_STUB) { + int hashValue = prefix.hashCode(); + if (hashValue < 0) { + hashValue = - hashValue; + } + this.seed = hashValue + UNIQUE_STUB + (instanceCount++) + ":"; + this.seed = generateSanitizedId(this.seed); + this.length = this.seed.length() + ("" + Long.MAX_VALUE).length(); + } + } + + private UuidGenerator() { + this("ID:" + hostName); + } + + /** + * As we have to find the hostname as a side-affect of generating a unique + * stub, we allow it's easy retrevial here + * + * @return the local host name + */ + + public static String getHostName() { + return hostName; + } + + + /** + * Generate a unqiue id + * + * @return a unique id + */ + + private String generateId() { + StringBuilder sb = new StringBuilder(length); + sb.append(seed); + sb.append(sequence.getAndIncrement()); + return sb.toString(); + } + + /** + * Ensures that the id is friendly for a URL or file system + * + * @param id the unique id + * @return the id as file friendly id + */ + public static String generateSanitizedId(String id) { + id = id.replace(':', '-'); + id = id.replace('_', '-'); + id = id.replace('.', '-'); + id = id.replace('/', '-'); + return id; + } + + + public static String getUUID() { + return getInstance().generateId(); + } + + public static UuidGenerator getInstance() { + if (instance == null) { + instance = new UuidGenerator(); + } + return instance; + } + + /** + * 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 + * @see {@link java.net.InetAddress#getLocalHost()} + * @see {@link java.net.InetAddress#getHostName()} + */ + 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/aries-rsa/blob/62d835de/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/InvocationTest.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/InvocationTest.java b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/InvocationTest.java new file mode 100644 index 0000000..960210b --- /dev/null +++ b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/InvocationTest.java @@ -0,0 +1,581 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.aries.rsa.provider.fastbin.api.AsyncCallback; +import org.apache.aries.rsa.provider.fastbin.api.AsyncCallbackFuture; +import org.apache.aries.rsa.provider.fastbin.api.Dispatched; +import org.apache.aries.rsa.provider.fastbin.api.ProtobufSerializationStrategy; +import org.apache.aries.rsa.provider.fastbin.api.Serialization; +import org.apache.aries.rsa.provider.fastbin.api.SerializationStrategy; +import org.apache.aries.rsa.provider.fastbin.io.ServerInvoker; +import org.apache.aries.rsa.provider.fastbin.tcp.ClientInvokerImpl; +import org.apache.aries.rsa.provider.fastbin.tcp.ServerInvokerImpl; +import org.apache.aries.rsa.provider.fastbin.test.StringValue; +import org.fusesource.hawtdispatch.Dispatch; +import org.fusesource.hawtdispatch.DispatchQueue; +import org.junit.Test; + +import static org.fusesource.hawtdispatch.Dispatch.createQueue; +import static org.junit.Assert.assertEquals; + +public class InvocationTest { + final static long MILLIS_IN_A_NANO = TimeUnit.MILLISECONDS.toNanos(1); + final static long SECONDS_IN_A_NANO = TimeUnit.SECONDS.toNanos(1); + + final int BENCHMARK_CLIENTS = 100; + final int BENCHMARK_INVOCATIONS_PER_CLIENT = 1000; + + + @Test(timeout=30*1000) + public void testInvoke() throws Exception { + + DispatchQueue queue = Dispatch.createQueue(); + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return new HelloImpl(); + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + assertEquals("Hello Fabric!", hello.hello("Fabric")); + assertEquals("Hello World!", hello.helloworld()); + + // Verification the we can pick the right overloaded method even if using a mixure + // of primitives / objects and array dimensions. + assertEquals('a', hello.mix(0)); + assertEquals('b', hello.mix(new int[]{0})); + assertEquals('c', hello.mix(new Integer(0))); + assertEquals('d', hello.mix(new Integer[]{new Integer(0)})); + assertEquals('e', hello.mix(new int[0][0])); + assertEquals('f', hello.mix(new Integer[0][0])); + + AsyncCallbackFuture<String> future1 = new AsyncCallbackFuture<String>(); + hello.hello("Hiram", future1); + assertEquals("Hello Hiram!", future1.get(2, TimeUnit.SECONDS)); + + assertEquals("Hello Hiram!", hello.protobuf(stringValue("Hiram")).getValue()); + + AsyncCallbackFuture<StringValue.Getter> future2 = new AsyncCallbackFuture<StringValue.Getter>(); + hello.protobuf(stringValue("Hiram Async"), future2); + assertEquals("Hello Hiram Async!", future2.get(2, TimeUnit.SECONDS).getValue()); + + } + finally { + server.stop(); + client.stop(); + } + } + + @Test(timeout=30*1000) + public void testOverflowAsync() throws Exception { + + DispatchQueue queue = Dispatch.createQueue(); + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return new HelloImpl(); + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + char[] chars = new char[65*1024]; + String payload = new String(chars); + + final List<AsyncCallbackFuture<String>> futures = new ArrayList<AsyncCallbackFuture<String>>(); + for(int i = 0; i < 100; i++) { + AsyncCallbackFuture<String> future = new AsyncCallbackFuture<String>(); + hello.hello(payload, future); + futures.add(future); + } + + for(Future<String> f : futures) { + f.get(3, TimeUnit.SECONDS); + } +// future2.get(2, TimeUnit.SECONDS); + //assertEquals("Hello Hiram!", future1.get(2, TimeUnit.SECONDS)); + + //assertEquals("Hello Hiram!", hello.protobuf(stringValue(payload)).getValue()); + } + finally { + server.stop(); + client.stop(); + } + } + + @Test(timeout=30*1000) + public void testOverflow() throws Exception { + + DispatchQueue queue = Dispatch.createQueue(); + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return new HelloImpl(); + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + final Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + final AtomicInteger requests = new AtomicInteger(0); + final AtomicInteger responses = new AtomicInteger(0); + final AtomicInteger failures = new AtomicInteger(0); + + char[] chars = new char[65*1024]; + final String payload = new String(chars); + + Thread[] threads = new Thread[BENCHMARK_CLIENTS]; + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + threads[t] = new Thread() { + public void run() { + try { + requests.incrementAndGet(); + + hello.hello(payload); + + responses.incrementAndGet(); + } catch (Throwable t) { + failures.incrementAndGet(); + } + } + }; + threads[t].start(); + } + + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + threads[t].join(10000); + System.err.format("REQUEST: %d of %d%n", requests.get(), BENCHMARK_CLIENTS); + System.err.format("RESPONSES: %d of %d%n", responses.get(), BENCHMARK_CLIENTS); + assertEquals(threads[t].isAlive(), false); + } + + assertEquals(BENCHMARK_CLIENTS, requests.get()); + assertEquals(BENCHMARK_CLIENTS, responses.get()); + assertEquals(0, failures.get()); + + } + finally { + server.stop(); + client.stop(); + } + } + + @Test(timeout=30*1000) + public void testNoOverflow() throws Exception { + + DispatchQueue queue = Dispatch.createQueue(); + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return new HelloImpl(); + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + char[] chars = new char[65*1024]; + String payload = new String(chars); + + for(int i = 0; i < 100; i++) { + hello.hello(payload); + } + } + finally { + server.stop(); + client.stop(); + } + } + + @Test(timeout=30*1000) + public void testUnderLoadSyncObject() throws Exception { + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + + DispatchQueue queue = Dispatch.createQueue(); + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + final HelloImpl helloImpl = new HelloImpl(); + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return helloImpl; + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + + final Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + assertEquals("Hello World!", hello.helloworld()); + + final AtomicInteger requests = new AtomicInteger(0); + final AtomicInteger failures = new AtomicInteger(0); + final long latencies[] = new long[BENCHMARK_CLIENTS * BENCHMARK_INVOCATIONS_PER_CLIENT]; + + final long start = System.nanoTime(); + Thread[] threads = new Thread[BENCHMARK_CLIENTS]; + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + final int thread_idx = t; + threads[t] = new Thread() { + public void run() { + for (int i = 0; i < BENCHMARK_INVOCATIONS_PER_CLIENT; i++) { + try { + requests.incrementAndGet(); + String response; + + final long start = System.nanoTime(); + response = hello.hello("Fabric"); + final long end = System.nanoTime(); + latencies[(thread_idx* BENCHMARK_INVOCATIONS_PER_CLIENT)+i] = end-start; + + assertEquals("Hello Fabric!", response); + } catch (Throwable t) { + latencies[(thread_idx* BENCHMARK_INVOCATIONS_PER_CLIENT)+i] = -1; + failures.incrementAndGet(); + if (t instanceof UndeclaredThrowableException) { + t = ((UndeclaredThrowableException) t).getUndeclaredThrowable(); + } + System.err.println("Error: " + t.getClass().getName() + (t.getMessage() != null ? " (" + t.getMessage() + ")" : "")); + } + } + } + }; + threads[t].start(); + } + + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + threads[t].join(); + } + final long end = System.nanoTime(); + + long latency_sum = 0; + for (int t = 0; t < latencies.length; t++) { + if( latencies[t] != -1 ) { + latency_sum += latencies[t]; + } + } + double latency_avg = ((latency_sum * 1.0d)/requests.get()) / MILLIS_IN_A_NANO; + double request_rate = ((requests.get() * 1.0d)/(end-start)) * SECONDS_IN_A_NANO; + + System.err.println(String.format("Requests/Second: %,.2f", request_rate)); + System.err.println(String.format("Average request latency: %,.2f ms", latency_avg)); + System.err.println("Error Ratio: " + failures.get() + " / " + requests.get()); + } + finally { + server.stop(); + client.stop(); + } + } + + + class AsyncClient implements AsyncCallback<StringValue.Getter> { + + final int thread_idx; + final int nbInvocationsPerThread; + final long latencies[]; + final AtomicInteger requests; + final AtomicInteger failures; + final Hello hello; + + final DispatchQueue queue = createQueue(); + final StringValue.Buffer msg = stringValue("Fabric").freeze(); + final CountDownLatch done = new CountDownLatch(1); + + int i; + long start; + + + AsyncClient(int thread_idx, int nbInvocationsPerThread, Hello hello, AtomicInteger failures, AtomicInteger requests, long[] latencies) { + this.failures = failures; + this.requests = requests; + this.nbInvocationsPerThread = nbInvocationsPerThread; + this.latencies = latencies; + this.hello = hello; + this.thread_idx = thread_idx; + } + + void start() { + queue.execute(new Runnable() { + public void run() { + sendNext(); + } + }); + } + + void join() throws InterruptedException { + done.await(10, TimeUnit.SECONDS); + } + + private void sendNext() { + if( i < nbInvocationsPerThread ) { + requests.incrementAndGet(); + start = System.nanoTime(); + hello.protobuf(msg, this); + } else { + done.countDown(); + } + } + + public void onSuccess(StringValue.Getter result) { + latencies[(thread_idx*nbInvocationsPerThread)+i] = System.nanoTime() -start; + i++; + sendNext(); + } + + public void onFailure(Throwable t) { + failures.incrementAndGet(); + latencies[(thread_idx*nbInvocationsPerThread)+i] = -1; + i++; + if (t instanceof UndeclaredThrowableException) { + t = ((UndeclaredThrowableException) t).getUndeclaredThrowable(); + } + System.err.println("Error: " + t.getClass().getName() + (t.getMessage() != null ? " (" + t.getMessage() + ")" : "")); + sendNext(); + } + } + + @Test(timeout=30*1000) + public void testUnderLoadAsyncProto() throws Exception { + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + DispatchQueue queue = Dispatch.createQueue(); + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + + final HelloImpl helloImpl = new HelloImpl(); + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return helloImpl; + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + + final Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[] { Hello.class }, handler); + + final AtomicInteger requests = new AtomicInteger(0); + final AtomicInteger failures = new AtomicInteger(0); + final long latencies[] = new long[BENCHMARK_CLIENTS * BENCHMARK_INVOCATIONS_PER_CLIENT]; + + final long start = System.nanoTime(); + AsyncClient[] threads = new AsyncClient[BENCHMARK_CLIENTS]; + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + threads[t] = new AsyncClient(t, BENCHMARK_INVOCATIONS_PER_CLIENT, hello, failures, requests, latencies); + threads[t].start(); + } + + for (int t = 0; t < BENCHMARK_CLIENTS; t++) { + threads[t].join(); + } + final long end = System.nanoTime(); + + long latency_sum = 0; + for (int t = 0; t < latencies.length; t++) { + if( latencies[t] != -1 ) { + latency_sum += latencies[t]; + } + } + double latency_avg = ((latency_sum * 1.0d)/requests.get()) / MILLIS_IN_A_NANO; + double request_rate = ((requests.get() * 1.0d)/(end-start)) * SECONDS_IN_A_NANO; + + System.err.println(String.format("Requests/Second: %,.2f", request_rate)); + System.err.println(String.format("Average request latency: %,.2f ms", latency_avg)); + System.err.println("Error Ratio: " + failures.get() + " / " + requests.get()); + } + finally { + server.stop(); + client.stop(); + } + } + + public static interface Hello { + String hello(String name); + + // async version of the hello method. + void hello(String name, AsyncCallback<String> callback); + + String helloworld(); + + char mix(int value); + char mix(int[] value); + char mix(Integer value); + char mix(Integer[] value); + char mix(int[][] value); + char mix(Integer[][] value); + + @Serialization("protobuf") + StringValue.Getter protobuf(StringValue.Getter name); + + @Serialization("protobuf") + void protobuf(StringValue.Getter name, AsyncCallback<StringValue.Getter> callback); + + } + + static private StringValue.Bean stringValue(String hello) { + StringValue.Bean rc = new StringValue.Bean(); + rc.setValue(hello); + return rc; + } + + public static class HelloImpl implements Hello, Dispatched { + + DispatchQueue queue = Dispatch.createQueue(); + + public DispatchQueue queue() { + return queue; + } + + private void queueCheck() { + if( !queue.isExecuting() ) { + throw new IllegalStateException("Not executing on our dispatch queue"); + } + } + + public String helloworld() { + return "Hello World!"; + } + + public String hello(String name) { + queueCheck(); + return "Hello " + name + "!"; + } + + @Serialization("protobuf") + public StringValue.Getter protobuf(StringValue.Getter name) { + return stringValue(hello(name.getValue())); + } + + @Serialization("protobuf") + public void protobuf(StringValue.Getter name, AsyncCallback<StringValue.Getter> callback) { + callback.onSuccess(protobuf(name)); + } + + public void hello(String name, AsyncCallback<String> callback) { + queueCheck(); + callback.onSuccess(hello(name)); + } + + public char mix(int value) { + queueCheck(); + return 'a'; + } + + public char mix(int[] value) { + queueCheck(); + return 'b'; + } + + public char mix(Integer value) { + queueCheck(); + return 'c'; + } + + public char mix(Integer[] value) { + queueCheck(); + return 'd'; + } + + public char mix(int[][] value) { + queueCheck(); + return 'e'; + } + public char mix(Integer[][] value) { + queueCheck(); + return 'f'; + } + + } + + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/ManagerTest.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/ManagerTest.java b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/ManagerTest.java new file mode 100644 index 0000000..427628f --- /dev/null +++ b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/ManagerTest.java @@ -0,0 +1,106 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin; + + +public class ManagerTest { + + /* + @Test + public void testManager() throws Exception { + + ZKServerFactoryBean zkServerFactoryBean = null; + + try { + + int zooKeeperPort = getFreePort(); + int serverPort = getFreePort(); + + zkServerFactoryBean = new ZKServerFactoryBean(); + zkServerFactoryBean.setPurge(true); + zkServerFactoryBean.setClientPortAddress(new InetSocketAddress("localhost", zooKeeperPort)); + zkServerFactoryBean.afterPropertiesSet(); + + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder() + .connectString("localhost:" + zooKeeperPort) + .retryPolicy(new RetryOneTime(1000)) + .connectionTimeoutMs(60000); + + CuratorFramework curator = builder.build(); + curator.start(); + curator.getZookeeperClient().blockUntilConnectedOrTimedOut(); + + BundleContext bundleContext = createMock(BundleContext.class); + ServiceRegistration registration = createMock(ServiceRegistration.class); + Manager manager = new Manager(bundleContext, curator, "tcp://localhost:" + serverPort, "localhost", TimeUnit.MINUTES.toMillis(5)); + + bundleContext.addServiceListener(manager, "(service.exported.interfaces=*)"); + expect(bundleContext.getProperty("org.osgi.framework.uuid")).andReturn("the-framework-uuid"); + expect(bundleContext.registerService( + EasyMock.<String[]>anyObject(), + same(manager), + EasyMock.<Dictionary>same(null))).andReturn(registration); + expect(bundleContext.getServiceReferences((String) null, "(service.exported.interfaces=*)")).andReturn(null); + + replay(bundleContext, registration); + + manager.init(); + + verify(bundleContext, registration); + + reset(bundleContext, registration); + + BundleContext expBundleContext = createMock(BundleContext.class); + Bundle expBundle = createMock(Bundle.class); + ServiceReference reference = createMock(ServiceReference.class); + final Properties props = new Properties(); + props.put(Constants.OBJECTCLASS, new String[]{ConfigurationAdmin.class.getName()}); + expect(reference.getProperty(EasyMock.<String>anyObject())).andAnswer(new IAnswer<Object>() { + public Object answer() throws Throwable { + return props.get(EasyMock.getCurrentArguments()[0]); + } + }).anyTimes(); + expect(reference.getPropertyKeys()).andReturn(props.keySet().toArray(new String[0])); + expect(reference.getBundle()).andReturn(expBundle).anyTimes(); + expect(expBundle.getBundleContext()).andReturn(expBundleContext).anyTimes(); + expect(expBundle.getState()).andReturn(Bundle.ACTIVE).anyTimes(); + + replay(bundleContext, registration, reference, expBundleContext, expBundle); + + manager.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, reference)); + Thread.sleep(1000); + + verify(bundleContext, registration, reference, expBundleContext, expBundle); + + } + finally { + try { + zkServerFactoryBean.destroy(); + } catch (Throwable t) { } + } + } + + static int getFreePort() throws IOException { + ServerSocket sock = new ServerSocket(); + try { + sock.bind(new InetSocketAddress(0)); + return sock.getLocalPort(); + } finally { + sock.close(); + } + } + */ +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/TransportFailureTest.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/TransportFailureTest.java b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/TransportFailureTest.java new file mode 100644 index 0000000..7d3cbf0 --- /dev/null +++ b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/TransportFailureTest.java @@ -0,0 +1,128 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.nio.channels.SocketChannel; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import org.apache.aries.rsa.provider.fastbin.api.AsyncCallback; +import org.apache.aries.rsa.provider.fastbin.api.AsyncCallbackFuture; +import org.apache.aries.rsa.provider.fastbin.api.ProtobufSerializationStrategy; +import org.apache.aries.rsa.provider.fastbin.api.SerializationStrategy; +import org.apache.aries.rsa.provider.fastbin.io.ServerInvoker; +import org.apache.aries.rsa.provider.fastbin.tcp.ClientInvokerImpl; +import org.apache.aries.rsa.provider.fastbin.tcp.ServerInvokerImpl; +import org.fusesource.hawtdispatch.Dispatch; +import org.fusesource.hawtdispatch.DispatchQueue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TransportFailureTest { + + private static long SLEEP_TIME = 100; + private static long MAX_DELAY = 1000; + + @Test + public void testInvoke() throws Exception { + + DispatchQueue queue = Dispatch.createQueue(); + HashMap<String, SerializationStrategy> map = new HashMap<String, SerializationStrategy>(); + map.put("protobuf", new ProtobufSerializationStrategy()); + + ServerInvokerImpl server = new ServerInvokerImpl("tcp://localhost:0", queue, map); + server.start(); + + ClientInvokerImpl client = new ClientInvokerImpl(queue, map); + client.start(); + + try { + server.registerService("service-id", new ServerInvoker.ServiceFactory() { + public Object get() { + return new HelloImpl(); + } + public void unget() { + } + }, HelloImpl.class.getClassLoader()); + + + InvocationHandler handler = client.getProxy(server.getConnectAddress(), "service-id", HelloImpl.class.getClassLoader()); + Hello hello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), new Class[]{Hello.class}, handler); + + AsyncCallbackFuture<String> future1 = new AsyncCallbackFuture<String>(); + hello.hello("Guillaume", future1); + + long t0 = System.currentTimeMillis(); + try { + assertEquals("Hello Guillaume!", future1.get(MAX_DELAY, TimeUnit.MILLISECONDS)); + fail("Should have thrown an exception"); + } catch (Exception e) { + // Expected + long t1 = System.currentTimeMillis(); + assertTrue(t1 - t0 > SLEEP_TIME / 2); + assertTrue(t1 - t0 < MAX_DELAY / 2); + } + + } + finally { + server.stop(); + client.stop(); + } + } + + public static interface Hello { + void hello(String name, AsyncCallback<String> callback) throws Exception; + } + + public static class HelloImpl implements Hello { + public void hello(final String name, final AsyncCallback<String> callback) throws Exception { + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(SLEEP_TIME); + // Big introspection call to access the transport channel and close it, simulating + // a disconnect on the client side. + ((SocketChannel) get(get(get(get(get(callback, "val$helper"), "onComplete"), "this$1"), "val$transport"), "channel")).close(); + } catch (Throwable e) { + e.printStackTrace(); + } + callback.onSuccess("Hello " + name + "!"); + } + }).start(); + } + } + + private static Object get(Object obj, String field) throws Exception { + for (Class cl = obj.getClass(); cl != Object.class; cl = cl.getSuperclass()) { + try { + Field f = obj.getClass().getDeclaredField(field); + f.setAccessible(true); + return f.get(obj); + } catch (Throwable t) { + // Ignore + } + } + throw new NoSuchFieldException(field); + } + +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/tcp/LengthPrefixedCodecTest.java ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/tcp/LengthPrefixedCodecTest.java b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/tcp/LengthPrefixedCodecTest.java new file mode 100644 index 0000000..ca7e7f6 --- /dev/null +++ b/provider/fastbin/src/test/java/org/apache/aries/rsa/provider/fastbin/tcp/LengthPrefixedCodecTest.java @@ -0,0 +1,150 @@ +/** + * Copyright 2005-2015 Red Hat, Inc. + * + * Red Hat 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.aries.rsa.provider.fastbin.tcp; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +import org.apache.aries.rsa.provider.fastbin.io.ProtocolCodec.BufferState; +import org.easymock.IAnswer; +import org.fusesource.hawtbuf.Buffer; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.getCurrentArguments; +import static org.easymock.EasyMock.replay; +import static org.junit.Assert.assertEquals; + +public class LengthPrefixedCodecTest { + private ReadableByteChannel readableByteChannel = createMock(ReadableByteChannel.class); + + private WritableByteChannel writableByteChannel = createMock(WritableByteChannel.class); + private LengthPrefixedCodec codec; + + @Before + public void createLengthPrefixedCodec() throws Exception { + codec = new LengthPrefixedCodec(); + codec.setReadableByteChannel(readableByteChannel); + codec.setWritableByteChannel(writableByteChannel); + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testFull() throws Exception { + assertEquals(false, codec.full()); + } + + @Test + public void testEmpty() throws Exception { + assertEquals(true, codec.empty()); + } + + @Test + public void testGetWriteCounter() throws Exception { + assertEquals(0l, codec.getWriteCounter()); + } + + @Test + public void testGetReadCounter() throws Exception { + assertEquals(0l, codec.getReadCounter()); + } + + @Test + public void testWrite() throws Exception { + final Buffer value = Buffer.ascii("TESTDATA"); + + final BufferState state = codec.write(value); + + assertEquals(BufferState.WAS_EMPTY, state); + assertEquals(false, codec.full()); + assertEquals(false, codec.empty()); + assertEquals(0l, codec.getWriteCounter()); + } + + @Test + public void testWrite$Twice() throws Exception { + final Buffer value1 = Buffer.ascii("TESTDATA"); + final Buffer value2 = Buffer.ascii("TESTDATA"); + codec.write(value1); + + final BufferState state = codec.write(value2); + + assertEquals(BufferState.NOT_EMPTY, state); + assertEquals(false, codec.full()); + assertEquals(false, codec.empty()); + assertEquals(0l, codec.getWriteCounter()); + } + + @Test + public void testFlush() throws Exception { + final Buffer value = Buffer.ascii("TESTDATA"); + codec.write(value); + final int bytesThatWillBeWritten = value.length(); + expect(writableByteChannel.write((ByteBuffer) anyObject())).andAnswer(createWriteAnswer(bytesThatWillBeWritten)); + replay(writableByteChannel); + + final BufferState state = codec.flush(); + + assertEquals(BufferState.EMPTY, state); + assertEquals(false, codec.full()); + assertEquals(true, codec.empty()); + assertEquals(bytesThatWillBeWritten, codec.getWriteCounter()); + + assertEquals(BufferState.WAS_EMPTY, codec.flush()); + } + + @Test + public void testFlush$Partially() throws Exception { + final Buffer value = Buffer.ascii("TESTDATA"); + codec.write(value); + final int bytesThatWillBeWritten = value.length() / 2; + expect(writableByteChannel.write((ByteBuffer) anyObject())).andAnswer(createWriteAnswer(bytesThatWillBeWritten)); + replay(writableByteChannel); + + final BufferState state = codec.flush(); + + assertEquals(BufferState.NOT_EMPTY, state); + assertEquals(false, codec.full()); + assertEquals(false, codec.empty()); + assertEquals(bytesThatWillBeWritten, codec.getWriteCounter()); + } + + private IAnswer<Integer> createWriteAnswer(final int length) { + return new IAnswer<Integer>() { + @Override + public Integer answer() throws Throwable { + final ByteBuffer buffer = (ByteBuffer) getCurrentArguments()[0]; + if(buffer.remaining() < length) + throw new BufferUnderflowException(); + buffer.position(buffer.position() + length); + return length; + } + }; + } +} http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/test/proto/example.proto ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/proto/example.proto b/provider/fastbin/src/test/proto/example.proto new file mode 100644 index 0000000..91c737f --- /dev/null +++ b/provider/fastbin/src/test/proto/example.proto @@ -0,0 +1,28 @@ +// +// Copyright (C) FuseSource, Inc. +// http://fusesource.com +// +// 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. +// +package org.apache.aries.rsa.provider.fastbin.test; + +option java_multiple_files = true; + +/////////////////////////////////////////////////////////////// +// Message related operations. +/////////////////////////////////////////////////////////////// + +message StringValue { + optional string value = 1; +} + http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/fastbin/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/provider/fastbin/src/test/resources/log4j.properties b/provider/fastbin/src/test/resources/log4j.properties new file mode 100644 index 0000000..0a36712 --- /dev/null +++ b/provider/fastbin/src/test/resources/log4j.properties @@ -0,0 +1,35 @@ +# 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. + +# +# The logging properties used during tests.. +# +log4j.rootLogger=WARN, console, file +log4j.logger.org.apache.aries.rsa.provider.fastbin=TRACE + +# Console will only display warnnings +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%-5p | %t | %m%n +log4j.appender.console.threshold=TRACE + +# File appender will contain all info messages +log4j.appender.file=org.apache.log4j.FileAppender +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d | %-5p | %m | %c | %t%n +log4j.appender.file.file=target/test.log +log4j.appender.file.append=true http://git-wip-us.apache.org/repos/asf/aries-rsa/blob/62d835de/provider/pom.xml ---------------------------------------------------------------------- diff --git a/provider/pom.xml b/provider/pom.xml index fb6a769..bbb1ee6 100644 --- a/provider/pom.xml +++ b/provider/pom.xml @@ -39,5 +39,6 @@ <modules> <module>tcp</module> + <module>fastbin</module> </modules> </project>
