summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/trunk/modules/common-java/src/main/java/org
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/trunk/modules/common-java/src/main/java/org')
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/classloader/ClassLoaderDelegate.java97
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CollectionMap.java62
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundEnumeration.java93
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundIterator.java113
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/LRUCache.java88
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/io/IOHelper.java149
-rw-r--r--sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/reflection/JavaIntrospectionHelper.java586
7 files changed, 1188 insertions, 0 deletions
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/classloader/ClassLoaderDelegate.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/classloader/ClassLoaderDelegate.java
new file mode 100644
index 0000000000..b4b99ff9e5
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/classloader/ClassLoaderDelegate.java
@@ -0,0 +1,97 @@
+/*
+ * 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.tuscany.sca.common.java.classloader;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.tuscany.sca.common.java.collection.CompoundEnumeration;
+
+public class ClassLoaderDelegate extends ClassLoader {
+ private final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
+
+ /**
+ * @param parent The parent classloaders
+ * @param loaders A list of classloaders to be used to load classes or resources
+ */
+ public ClassLoaderDelegate(ClassLoader parent, ClassLoader... loaders) {
+ super(parent);
+ if (loaders != null) {
+ for (ClassLoader cl : loaders) {
+ if (cl != null && cl != parent && !classLoaders.contains(cl)) {
+ this.classLoaders.add(cl);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param parent The parent classloaders
+ * @param loaders A list of classloaders to be used to load classes or resources
+ */
+ public ClassLoaderDelegate(ClassLoader parent, Collection<ClassLoader> loaders) {
+ super(parent);
+ if (loaders != null) {
+ for (ClassLoader cl : loaders) {
+ if (cl != null && cl != parent && !classLoaders.contains(cl)) {
+ this.classLoaders.add(cl);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected Class<?> findClass(String className) throws ClassNotFoundException {
+ for (ClassLoader parent : classLoaders) {
+ try {
+ return parent.loadClass(className);
+ } catch (ClassNotFoundException e) {
+ continue;
+ }
+ }
+ throw new ClassNotFoundException(className);
+ }
+
+ @Override
+ protected URL findResource(String resName) {
+ for (ClassLoader parent : classLoaders) {
+ URL url = parent.getResource(resName);
+ if (url != null) {
+ return url;
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Enumeration<URL> findResources(String resName) throws IOException {
+ Enumeration<URL>[] enums = new Enumeration[classLoaders.size()];
+ int index = 0;
+ for (ClassLoader parent : classLoaders) {
+ enums[index++] = parent.getResources(resName);
+ }
+ return new CompoundEnumeration<URL>(enums);
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CollectionMap.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CollectionMap.java
new file mode 100644
index 0000000000..cc3fb4676d
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CollectionMap.java
@@ -0,0 +1,62 @@
+/*
+ * 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.tuscany.sca.common.java.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A Map with Collection values
+ */
+public class CollectionMap<K, V> extends ConcurrentHashMap<K, Collection<V>> {
+ private static final long serialVersionUID = -8926174610229029369L;
+
+ public boolean putValue(K key, V value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ collection = createCollection();
+ put(key, collection);
+ }
+ return collection.add(value);
+ }
+
+ public boolean putValues(K key, Collection<? extends V> value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ collection = createCollection();
+ put(key, collection);
+ }
+ return collection.addAll(value);
+ }
+
+ public boolean removeValue(K key, V value) {
+ Collection<V> collection = get(key);
+ if (collection == null) {
+ return false;
+ }
+ return collection.remove(value);
+ }
+
+ protected Collection<V> createCollection() {
+ return new ArrayList<V>();
+ }
+
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundEnumeration.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundEnumeration.java
new file mode 100644
index 0000000000..dc6a7e0f90
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundEnumeration.java
@@ -0,0 +1,93 @@
+/*
+ * 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.tuscany.sca.common.java.collection;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+public class CompoundEnumeration<T> implements Enumeration<T> {
+ private Enumeration<T>[] enumerations = null;
+ private int index = 0;
+
+ public CompoundEnumeration(Enumeration<T>... enums) {
+ enumerations = enums;
+ }
+
+ public boolean hasMoreElements() {
+ // if the current enum is null that means this enum is finished
+ if (currentEnumeration() == null) {
+ // No next enum
+ return false;
+ }
+ // If the current enum has more elements, lets go
+ return currentEnumeration().hasMoreElements();
+ }
+
+ private Enumeration<T> findNextEnumeration(boolean moveCursor) {
+ return findNextEnumeration(index, moveCursor);
+ }
+
+ private Enumeration<T> findNextEnumeration(int cursor, boolean moveCursor) {
+ // next place in the array
+ int next = cursor + 1;
+ // If the cursor is still in the array
+ if (next < enumerations.length) {
+
+ // If there is something in that place
+ // AND the enum is not empty
+ if (enumerations[next] != null && enumerations[next].hasMoreElements()) {
+ // OK
+ if (moveCursor) {
+ index = next;
+ }
+ return enumerations[next];
+ }
+ // Try next element
+ return findNextEnumeration(next, moveCursor);
+ }
+ // No more elements available
+ return null;
+ }
+
+ public T nextElement() {
+ // ask for the next element of the current enum.
+ if (currentEnumeration() != null) {
+ return currentEnumeration().nextElement();
+ }
+
+ // no more elements in this Enum
+ // We must throw a NoSuchElementException
+ throw new NoSuchElementException("No more elements");
+ }
+
+ private Enumeration<T> currentEnumeration() {
+ if (enumerations != null) {
+ if (index < enumerations.length) {
+ Enumeration<T> e = enumerations[index];
+ if (e == null || !e.hasMoreElements()) {
+ // the current enum is null or empty
+ // we probably want to switch to the next one
+ e = findNextEnumeration(true);
+ }
+ return e;
+ }
+ }
+ return null;
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundIterator.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundIterator.java
new file mode 100644
index 0000000000..997ba89881
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/CompoundIterator.java
@@ -0,0 +1,113 @@
+/*
+ * 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.tuscany.sca.common.java.collection;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class CompoundIterator<T> implements Iterator<T> {
+ private Iterator<T>[] iterators = null;
+ private int index = 0;
+
+ public CompoundIterator(Iterator<T>... iterators) {
+ this.iterators = iterators;
+ }
+
+ @SuppressWarnings("unchecked")
+ public CompoundIterator(Collection<T>... collections) {
+ this.iterators = new Iterator[collections.length];
+ for (int i = 0; i < collections.length; i++) {
+ this.iterators[i] = collections[i].iterator();
+ }
+ }
+
+ public boolean hasNext() {
+ // if the current enum is null that means this enum is finished
+ if (currentIterator() == null) {
+ // No next enum
+ return false;
+ }
+ // If the current enum has more elements, lets go
+ return currentIterator().hasNext();
+ }
+
+ private Iterator<T> findNextIterator(boolean moveCursor) {
+ return findNextIterator(index, moveCursor);
+ }
+
+ private Iterator<T> findNextIterator(int cursor, boolean moveCursor) {
+ // next place in the array
+ int next = cursor + 1;
+ // If the cursor is still in the array
+ if (next < iterators.length) {
+
+ // If there is something in that place
+ // AND the enum is not empty
+ if (iterators[next] != null && iterators[next].hasNext()) {
+ // OK
+ if (moveCursor) {
+ index = next;
+ }
+ return iterators[next];
+ }
+ // Try next element
+ return findNextIterator(next, moveCursor);
+ }
+ // No more elements available
+ return null;
+ }
+
+ public T next() {
+ // ask for the next element of the current enum.
+ if (currentIterator() != null) {
+ return currentIterator().next();
+ }
+
+ // no more elements in this Enum
+ // We must throw a NoSuchElementException
+ throw new NoSuchElementException("No more elements");
+ }
+
+ public void remove() {
+ // ask for the next element of the current enum.
+ if (currentIterator() != null) {
+ currentIterator().remove();
+ }
+
+ // no more elements in this Enum
+ // We must throw a NoSuchElementException
+ throw new NoSuchElementException("No more elements");
+ }
+
+ private Iterator<T> currentIterator() {
+ if (iterators != null) {
+ if (index < iterators.length) {
+ Iterator<T> e = iterators[index];
+ if (e == null || !e.hasNext()) {
+ // the current enum is null or empty
+ // we probably want to switch to the next one
+ e = findNextIterator(true);
+ }
+ return e;
+ }
+ }
+ return null;
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/LRUCache.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/LRUCache.java
new file mode 100644
index 0000000000..d3f472d463
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/collection/LRUCache.java
@@ -0,0 +1,88 @@
+/*
+ * 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.tuscany.sca.common.java.collection;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A Simple LRU Cache
+ *
+ * @version $Revision$
+ * @param <K>
+ * @param <V>
+ */
+
+public class LRUCache<K, V> extends LinkedHashMap<K, V> {
+ private static final long serialVersionUID = -342098639681884413L;
+ protected int maxCacheSize = 4096;
+
+ /**
+ * Default constructor for an LRU Cache The default capacity is 4096
+ */
+ public LRUCache() {
+ this(0, 4096, 0.75f, true);
+ }
+
+ /**
+ * Constructs a LRUCache with a maximum capacity
+ *
+ * @param maximumCacheSize
+ */
+ public LRUCache(int maximumCacheSize) {
+ this(0, maximumCacheSize, 0.75f, true);
+ }
+
+ /**
+ * Constructs an empty <tt>LRUCache</tt> instance with the specified
+ * initial capacity, maximumCacheSize,load factor and ordering mode.
+ *
+ * @param initialCapacity the initial capacity.
+ * @param maximumCacheSize
+ * @param loadFactor the load factor.
+ * @param accessOrder the ordering mode - <tt>true</tt> for access-order,
+ * <tt>false</tt> for insertion-order.
+ * @throws IllegalArgumentException if the initial capacity is negative or
+ * the load factor is non-positive.
+ */
+
+ public LRUCache(int initialCapacity, int maximumCacheSize, float loadFactor, boolean accessOrder) {
+ super(initialCapacity, loadFactor, accessOrder);
+ this.maxCacheSize = maximumCacheSize;
+ }
+
+ /**
+ * @return Returns the maxCacheSize.
+ */
+ public int getMaxCacheSize() {
+ return maxCacheSize;
+ }
+
+ /**
+ * @param maxCacheSize The maxCacheSize to set.
+ */
+ public void setMaxCacheSize(int maxCacheSize) {
+ this.maxCacheSize = maxCacheSize;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > maxCacheSize;
+ }
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/io/IOHelper.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/io/IOHelper.java
new file mode 100644
index 0000000000..469da29e38
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/io/IOHelper.java
@@ -0,0 +1,149 @@
+/*
+ * 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.tuscany.sca.common.java.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+/**
+ * Helper class for I/O operations
+ */
+public class IOHelper {
+
+ public static InputStream openStream(URL url) throws IOException {
+ // Handle file:<relative path> which strictly speaking is not a valid file URL
+ File file = toFile(url);
+ if (file != null) {
+ return new FileInputStream(file);
+ }
+ URLConnection connection = url.openConnection();
+ if (connection instanceof JarURLConnection) {
+ // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041014
+ connection.setUseCaches(false);
+ }
+ InputStream is = connection.getInputStream();
+ return is;
+ }
+
+ public static void close(InputStream is) {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ /**
+ * Escape the space in URL string
+ * @param uri
+ * @return
+ */
+ public static URI createURI(String uri) {
+ if (uri == null) {
+ return null;
+ }
+ if (uri.indexOf('%') != -1) {
+ // Avoid double-escaping
+ return URI.create(uri);
+ }
+ int index = uri.indexOf(':');
+ String scheme = null;
+ String ssp = uri;
+ if (index != -1) {
+ scheme = uri.substring(0, index);
+ ssp = uri.substring(index + 1);
+ }
+ try {
+ return new URI(scheme, ssp, null);
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public static URI toURI(URL url) {
+ if (url == null) {
+ return null;
+ }
+ return createURI(url.toString());
+ }
+
+ public static URL normalize(URL url) {
+ // Make sure the trailing / is added to the file directory URL so that
+ // URLClassLoader can load classes from that
+ try {
+ File file = toFile(url);
+ if (file != null) {
+ return file.toURI().toURL();
+ } else {
+ return toURI(url).toURL();
+ }
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Returns the File object representing the given URL.
+ *
+ * @param url
+ * @return
+ */
+ public static File toFile(URL url) {
+ if (url == null || !url.getProtocol().equals("file")) {
+ return null;
+ } else {
+ String filename = url.getFile().replace('/', File.separatorChar);
+ int pos = 0;
+ while ((pos = filename.indexOf('%', pos)) >= 0) {
+ if (pos + 2 < filename.length()) {
+ String hexStr = filename.substring(pos + 1, pos + 3);
+ char ch = (char)Integer.parseInt(hexStr, 16);
+ filename = filename.substring(0, pos) + ch + filename.substring(pos + 3);
+ }
+ }
+ return new File(filename);
+ }
+ }
+
+ /**
+ * Returns the location of the classpath entry, JAR, WAR etc. containing the given class.
+ *
+ * @param clazz
+ * @return
+ */
+ public static URL codeLocation(Class<?> clazz) {
+ URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
+ if (url == null) {
+ url = clazz.getResource("/" + clazz.getName().replace('.', '/') + ".class");
+ }
+ return url;
+ }
+
+}
diff --git a/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/reflection/JavaIntrospectionHelper.java b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/reflection/JavaIntrospectionHelper.java
new file mode 100644
index 0000000000..ae4f01c032
--- /dev/null
+++ b/sca-java-2.x/trunk/modules/common-java/src/main/java/org/apache/tuscany/sca/common/java/reflection/JavaIntrospectionHelper.java
@@ -0,0 +1,586 @@
+/*
+ * 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.tuscany.sca.common.java.reflection;
+
+import java.beans.Introspector;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.oasisopen.sca.ServiceReference;
+
+/**
+ * Implements various reflection-related operations
+ *
+ * @version $Rev$ $Date$
+ */
+public final class JavaIntrospectionHelper {
+ private static final Logger logger = Logger.getLogger(JavaIntrospectionHelper.class.getName());
+ private static final Class<?>[] EMPTY_CLASS_ARRY = new Class[0];
+
+ private ExtensionPointRegistry registry;
+
+ public JavaIntrospectionHelper(ExtensionPointRegistry registry) {
+ this.registry = registry;
+ }
+
+ public static JavaIntrospectionHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilities.getUtility(JavaIntrospectionHelper.class);
+ }
+
+ private static boolean matches(int modifiers, int include, int exclude) {
+ if (include != -1) {
+ if ((modifiers & include) == 0) {
+ return false;
+ }
+ }
+ if (exclude != -1) {
+ if ((modifiers & exclude) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Recursively evaluates the type hierarchy to return all fields that are
+ * public or protected
+ * @param clazz The java class
+ * @param fields The set that collects all fields
+ * @param include The modifiers to be included
+ * @param exclude The modifiers to be excluded
+ * @return The set that collects all matched fields
+ */
+ private static Set<Field> getAllFields(Class<?> clazz, Set<Field> fields, int include, int exclude) {
+ if (clazz == null || clazz.isArray() || Object.class.equals(clazz)) {
+ return fields;
+ }
+ fields = getAllFields(clazz.getSuperclass(), fields, include, exclude);
+ Field[] declaredFields = clazz.getDeclaredFields();
+ for (final Field field : declaredFields) {
+ int modifiers = field.getModifiers();
+ if (matches(modifiers, include, exclude)) {
+ // Allow privileged access to set accessibility. Requires ReflectPermission
+ // in security policy.
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ field.setAccessible(true); // ignore Java accessibility
+ return null;
+ }
+ });
+ fields.add(field);
+ }
+ }
+ return fields;
+ }
+
+ /**
+ * @param cls
+ * @return
+ */
+ public Set<Field> getAllNonStaticOrFinalFields(Class<?> cls) {
+ Set<Field> fields = new HashSet<Field>();
+ return getAllFields(cls, fields, -1, Modifier.STATIC | Modifier.FINAL);
+ }
+
+ /**
+ * @param cls
+ * @return
+ */
+ public Set<Method> getAllNonStaticMethods(Class<?> cls) {
+ Set<Method> methods = new HashSet<Method>();
+ return getAllUniqueMethods(cls, methods, -1, Modifier.STATIC);
+ }
+
+ /**
+ * Recursively evaluates the type hierarchy to return all unique methods
+ */
+ private static Set<Method> getAllUniqueMethods(Class<?> pClass, Set<Method> methods, int include, int exclude) {
+ if (pClass == null || pClass.isArray() || Object.class.equals(pClass)) {
+ return methods;
+ }
+ // we first evaluate methods of the subclass and then move to the parent
+ Method[] declaredMethods = pClass.getDeclaredMethods();
+ for (final Method declaredMethod : declaredMethods) {
+ int modifiers = declaredMethod.getModifiers();
+ if (!matches(modifiers, include, exclude)) {
+ continue;
+ }
+ if (methods.size() == 0) {
+ methods.add(declaredMethod);
+ } else {
+ List<Method> temp = new ArrayList<Method>();
+ boolean matched = false;
+ for (Method method : methods) {
+ // only add if not already in the set from a superclass (i.e.
+ // the method is not overridden)
+ if (exactMethodMatch(declaredMethod, method)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched) {
+ // Allow privileged access to set accessibility. Requires ReflectPermission
+ // in security policy.
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ declaredMethod.setAccessible(true);
+ return null;
+ }
+ });
+ temp.add(declaredMethod);
+ }
+ methods.addAll(temp);
+ temp.clear();
+ }
+ }
+ // evaluate class hierarchy - this is done last to track inherited
+ // methods
+ methods = getAllUniqueMethods(pClass.getSuperclass(), methods, include, exclude);
+ return methods;
+ }
+
+ /**
+ * Finds the closest matching field with the given name, that is, a field of
+ * the exact specified type or, alternately, of a supertype.
+ *
+ * @param name the name of the field
+ * @param type the field type
+ * @param fields the collection of fields to search
+ * @return the matching field or null if not found
+ */
+ public static Field findClosestMatchingField(String name, Class type, Set<Field> fields) {
+ Field candidate = null;
+ for (Field field : fields) {
+ if (field.getName().equals(name)) {
+ if (field.getType().equals(type)) {
+ return field; // exact match
+ } else if (field.getType().isAssignableFrom(type) || (field.getType().isPrimitive() && primitiveAssignable(field
+ .getType(),
+ type))) {
+ // We could have the situation where a field parameter is a
+ // primitive and the demarshalled value is
+ // an object counterpart (e.g. Integer and int)
+ // @spec issue
+ // either an interface or super class, so keep a reference
+ // until
+ // we know there are no closer types
+ candidate = field;
+ }
+ }
+ }
+ if (candidate != null) {
+ return candidate;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds the closest matching method with the given name, that is, a method
+ * taking the exact parameter types or, alternately, parameter supertypes.
+ *
+ * @param name the name of the method
+ * @param types the method parameter types
+ * @param methods the collection of methods to search
+ * @return the matching method or null if not found
+ */
+ public static Method findClosestMatchingMethod(String name, Class[] types, Set<Method> methods) {
+ if (types == null) {
+ types = EMPTY_CLASS_ARRY;
+ }
+ Method candidate = null;
+ for (Method method : methods) {
+ if (method.getName().equals(name) && method.getParameterTypes().length == types.length) {
+ Class<?>[] params = method.getParameterTypes();
+ boolean disqualify = false;
+ boolean exactMatch = true;
+ for (int i = 0; i < params.length; i++) {
+ if (!params[i].equals(types[i]) && !params[i].isAssignableFrom(types[i])) {
+ // no match
+ disqualify = true;
+ exactMatch = false;
+ break;
+ } else if (!params[i].equals(types[i]) && params[i].isAssignableFrom(types[i])) {
+ // not exact match
+ exactMatch = false;
+ }
+ }
+ if (disqualify) {
+ continue;
+ } else if (exactMatch) {
+ return method;
+ } else {
+ candidate = method;
+ }
+ }
+ }
+ if (candidate != null) {
+ return candidate;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Determines if two methods "match" - that is, they have the same method
+ * names and exact parameter types (one is not a supertype of the other)
+ */
+ public static boolean exactMethodMatch(Method method1, Method method2) {
+ if (!method1.getName().equals(method2.getName())) {
+ return false;
+ }
+ Class<?>[] types1 = method1.getParameterTypes();
+ Class<?>[] types2 = method2.getParameterTypes();
+ if (types1.length != types2.length) {
+ return false;
+ }
+ boolean matched = true;
+ for (int i = 0; i < types1.length; i++) {
+ if (types1[i] != types2[i]) {
+ matched = false;
+ break;
+ }
+ }
+ return matched;
+ }
+
+ public static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) throws NoSuchMethodException {
+ return clazz.getConstructor();
+ }
+
+ /**
+ * Returns the simple name of a class - i.e. the class name devoid of its
+ * package qualifier
+ *
+ * @param implClass the implementation class
+ */
+ public static String getBaseName(Class<?> implClass) {
+ return implClass.getSimpleName();
+ }
+
+ public static boolean isImmutable(Class<?> clazz) {
+ return String.class == clazz || clazz.isPrimitive()
+ || Number.class.isAssignableFrom(clazz)
+ || Boolean.class.isAssignableFrom(clazz)
+ || Character.class.isAssignableFrom(clazz)
+ || Byte.class.isAssignableFrom(clazz);
+ }
+
+ /**
+ * Takes a property name and converts it to a getter method name according
+ * to JavaBean conventions. For example, property
+ * <code>foo<code> is returned as <code>getFoo</code>
+ */
+ public static String toGetter(String name) {
+ return "get" + name.toUpperCase().substring(0, 1) + name.substring(1);
+ }
+
+ /**
+ * Takes a setter or getter method name and converts it to a property name
+ * according to JavaBean conventions. For example, <code>setFoo(var)</code>
+ * is returned as property <code>foo<code>
+ */
+ public static String toPropertyName(Method method) {
+ if (isGetter(method) || isSetter(method)) {
+ String name = method.getName();
+ if (name.startsWith("get") || name.startsWith("set")) {
+ return Introspector.decapitalize(name.substring(3));
+ } else {
+ // Starts with is
+ return Introspector.decapitalize(name.substring(2));
+ }
+ } else {
+ throw new IllegalArgumentException("Method is not a setter or getter: " + method);
+ }
+ }
+
+ public static Class<?> getErasure(Type type) {
+ if (type instanceof Class) {
+ return (Class<?>)type;
+ } else if (type instanceof GenericArrayType) {
+ // FIXME: How to deal with the []?
+ GenericArrayType arrayType = (GenericArrayType)type;
+ return getErasure(arrayType.getGenericComponentType());
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType pType = (ParameterizedType)type;
+ return getErasure(pType.getRawType());
+ } else if (type instanceof WildcardType) {
+ WildcardType wType = (WildcardType)type;
+ Type[] types = wType.getUpperBounds();
+ return getErasure(types[0]);
+ } else if (type instanceof TypeVariable) {
+ TypeVariable<?> var = (TypeVariable<?>)type;
+ Type[] types = var.getBounds();
+ return getErasure(types[0]);
+ }
+ return null;
+ }
+
+ public static Class<?> getBaseType(Class<?> cls, Type genericType) {
+ if (cls.isArray()) {
+ return cls.getComponentType();
+ } else if (Collection.class.isAssignableFrom(cls)) {
+ if (genericType instanceof ParameterizedType) {
+ // Collection<BaseType>
+ ParameterizedType parameterizedType = (ParameterizedType)genericType;
+ Type baseType = parameterizedType.getActualTypeArguments()[0];
+ if (baseType instanceof GenericArrayType) {
+ // Base is array
+ return cls;
+ } else {
+ return getErasure(baseType);
+ }
+ } else {
+ return cls;
+ }
+ } else {
+ return cls;
+ }
+ }
+
+ public static Type getParameterType(Type type) {
+ if (type instanceof ParameterizedType) {
+ // Collection<BaseType>
+ ParameterizedType parameterizedType = (ParameterizedType)type;
+ Type baseType = parameterizedType.getActualTypeArguments()[0];
+ return baseType;
+ } else {
+ return Object.class;
+ }
+ }
+
+ public static Class<?> getBusinessInterface(Class<?> cls, Type callableReferenceType) {
+ if (ServiceReference.class.isAssignableFrom(cls) && callableReferenceType instanceof ParameterizedType) {
+ // Collection<BaseType>
+ ParameterizedType parameterizedType = (ParameterizedType)callableReferenceType;
+ Type baseType = parameterizedType.getActualTypeArguments()[0];
+ if (baseType instanceof GenericArrayType) {
+ // Base is array
+ return cls;
+ } else {
+ return getErasure(baseType);
+ }
+ }
+ return Object.class;
+ }
+
+ /**
+ * Takes a property name and converts it to a setter method name according
+ * to JavaBean conventions. For example, the property
+ * <code>foo<code> is returned as <code>setFoo(var)</code>
+ */
+ public static String toSetter(String name) {
+ return "set" + name.toUpperCase().substring(0, 1) + name.substring(1);
+ }
+
+ /**
+ * Compares a two types, assuming one is a primitive, to determine if the
+ * other is its object counterpart
+ */
+ private static boolean primitiveAssignable(Class<?> memberType, Class<?> param) {
+ if (memberType == Integer.class) {
+ return param == Integer.TYPE;
+ } else if (memberType == Double.class) {
+ return param == Double.TYPE;
+ } else if (memberType == Float.class) {
+ return param == Float.TYPE;
+ } else if (memberType == Short.class) {
+ return param == Short.TYPE;
+ } else if (memberType == Character.class) {
+ return param == Character.TYPE;
+ } else if (memberType == Boolean.class) {
+ return param == Boolean.TYPE;
+ } else if (memberType == Byte.class) {
+ return param == Byte.TYPE;
+ } else if (param == Integer.class) {
+ return memberType == Integer.TYPE;
+ } else if (param == Double.class) {
+ return memberType == Double.TYPE;
+ } else if (param == Float.class) {
+ return memberType == Float.TYPE;
+ } else if (param == Short.class) {
+ return memberType == Short.TYPE;
+ } else if (param == Character.class) {
+ return memberType == Character.TYPE;
+ } else if (param == Boolean.class) {
+ return memberType == Boolean.TYPE;
+ } else if (param == Byte.class) {
+ return memberType == Byte.TYPE;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns the generic types represented in the given type. Usage as
+ * follows: <code>
+ * JavaIntrospectionHelper.getGenerics(field.getGenericType());
+ * <p/>
+ * JavaIntrospectionHelper.getGenerics(m.getGenericParameterTypes()[0];); </code>
+ *
+ * @return the generic types in order of declaration or an empty array if
+ * the type is not genericized
+ */
+ public static List<? extends Type> getGenerics(Type genericType) {
+ List<Type> classes = new ArrayList<Type>();
+ if (genericType instanceof ParameterizedType) {
+ ParameterizedType ptype = (ParameterizedType)genericType;
+ // get the type arguments
+ Type[] targs = ptype.getActualTypeArguments();
+ for (Type targ : targs) {
+ classes.add(targ);
+ }
+ }
+ return classes;
+ }
+
+ /**
+ * Returns the generic type specified by the class at the given position as
+ * in: <p/> <code> public class Foo<Bar,Baz>{ //.. }
+ * <p/>
+ * JavaIntrospectionHelper.introspectGeneric(Foo.class,1); <code>
+ * <p/>
+ * will return Baz.
+ */
+ public static Class introspectGeneric(Class<?> clazz, int pos) {
+ assert clazz != null : "No class specified";
+ Type type = clazz.getGenericSuperclass();
+ if (type instanceof ParameterizedType) {
+ Type[] args = ((ParameterizedType)type).getActualTypeArguments();
+ if (args.length <= pos) {
+ throw new IllegalArgumentException("Invalid index value for generic class " + clazz.getName());
+ }
+ return (Class)((ParameterizedType)type).getActualTypeArguments()[pos];
+ } else {
+ Type[] interfaces = clazz.getGenericInterfaces();
+ for (Type itype : interfaces) {
+ if (!(itype instanceof ParameterizedType)) {
+ continue;
+ }
+ ParameterizedType interfaceType = (ParameterizedType)itype;
+ return (Class)interfaceType.getActualTypeArguments()[0];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the set of interfaces implemented by the given class and its
+ * ancestors or a blank set if none
+ */
+ public Set<Class<?>> getAllInterfaces(Class<?> clazz) {
+ Set<Class<?>> implemented = new HashSet<Class<?>>();
+ getAllInterfaces(clazz, implemented);
+ return implemented;
+ }
+
+ private static void getAllInterfaces(Class<?> clazz, Set<Class<?>> implemented) {
+ Class<?>[] interfaces = clazz.getInterfaces();
+ for (Class<?> interfaze : interfaces) {
+ implemented.add(interfaze);
+ }
+ Class<?> superClass = clazz.getSuperclass();
+ // Object has no superclass so check for null
+ if (superClass != null && !superClass.equals(Object.class)) {
+ getAllInterfaces(superClass, implemented);
+ }
+ }
+
+ /**
+ * Test if a method follows the JavaBeans setter pattern
+ * @param method
+ * @return
+ */
+ public static boolean isSetter(Method method) {
+ return (void.class == method.getReturnType() && method.getParameterTypes().length == 1
+ && method.getName().startsWith("set") && method.getName().length() > 3);
+ }
+
+ /**
+ * Test if a method follows the JavaBeans getter pattern
+ * @param method
+ * @return
+ */
+ public static boolean isGetter(Method method) {
+ if (method.getParameterTypes().length == 0) {
+ return false;
+ }
+ Class<?> returnType = method.getReturnType();
+ if (returnType == void.class || returnType == Void.class) {
+ return false;
+ }
+ String name = method.getName();
+ if (returnType == boolean.class)
+ if (name.length() > 2 && name.startsWith("is")) {
+ return true;
+ }
+ return name.length() > 3 && name.startsWith("get");
+ }
+
+ private final static Map<Class<?>, String> signatures = new HashMap<Class<?>, String>();
+ static {
+ signatures.put(boolean.class, "Z");
+ signatures.put(byte.class, "B");
+ signatures.put(char.class, "C");
+ signatures.put(short.class, "S");
+ signatures.put(int.class, "I");
+ signatures.put(long.class, "J");
+ signatures.put(float.class, "F");
+ signatures.put(double.class, "D");
+ };
+
+ public static String getSignature(Class<?> cls) {
+ if (cls.isPrimitive()) {
+ return signatures.get(cls);
+ }
+ if (cls.isArray()) {
+ return "[" + getSignature(cls.getComponentType());
+ }
+ return "L" + cls.getName().replace('.', '/') + ";";
+ }
+
+ public static Class<?> getArrayType(Class<?> componentType, int dims) throws ClassNotFoundException {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < dims; i++) {
+ buf.append('[');
+ }
+ buf.append(getSignature(componentType));
+ return Class.forName(buf.toString(), false, componentType.getClassLoader());
+ }
+}