Author: jstrachan
Date: Fri Oct 20 03:12:26 2006
New Revision: 466049
URL: http://svn.apache.org/viewvc?view=rev&rev=466049
Log:
added the ability to auto-deploy POJOs as endpoints if they have the @Endpoint
annotation, provided that the <bean:component searchPackages="..."/> attribute
is specified to describe which packages are searched for on the class loader
Added:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
(with props)
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
(with props)
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
(with props)
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
(with props)
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
(with props)
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
(with props)
Modified:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanComponent.java
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanEndpoint.java
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/ConsumerListener.java
Modified:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanComponent.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanComponent.java?view=diff&rev=466049&r1=466048&r2=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanComponent.java
(original)
+++
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanComponent.java
Fri Oct 20 03:12:26 2006
@@ -24,6 +24,8 @@
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationContext;
import org.w3c.dom.DocumentFragment;
import javax.jbi.servicedesc.ServiceEndpoint;
@@ -31,24 +33,25 @@
import java.net.URI;
import java.util.List;
import java.util.Map;
+import java.util.ArrayList;
/**
* A JBI component for binding beans to the JBI bus which work directly off of
the JBI messages
* without requiring any SOAP Processing. If you require support for SOAP,
JAX-WS, JSR-181 then you
* should use the servicemix-jsr181 module instead.
*
+ * @version $Revision: $
* @org.apache.xbean.XBean element="component" description="Bean Component"
- *
- * @version $Revision: $
*/
-public class BeanComponent extends DefaultComponent implements
BeanFactoryAware {
+public class BeanComponent extends DefaultComponent implements
ApplicationContextAware {
public final static String EPR_URI = "urn:servicemix:bean";
public final static QName EPR_SERVICE = new QName(EPR_URI,
"BeanComponent");
public final static String EPR_NAME = "epr";
private BeanEndpoint[] endpoints;
- private BeanFactory beanFactory;
+ private String[] searchPackages;
+ private ApplicationContext applicationContext;
public BeanEndpoint[] getEndpoints() {
@@ -59,12 +62,20 @@
this.endpoints = endpoints;
}
- public BeanFactory getBeanFactory() {
- return beanFactory;
+ public ApplicationContext getApplicationContext() {
+ return applicationContext;
}
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
+ public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ public String[] getSearchPackages() {
+ return searchPackages;
+ }
+
+ public void setSearchPackages(String[] searchPackages) {
+ this.searchPackages = searchPackages;
}
public ServiceEndpoint resolveEndpointReference(DocumentFragment epr) {
@@ -72,7 +83,12 @@
}
protected List getConfiguredEndpoints() {
- return asList(getEndpoints());
+ List list = new ArrayList(asList(getEndpoints()));
+ if (searchPackages != null) {
+ EndpointFinder finder = new EndpointFinder(this);
+ finder.addEndpoints(list);
+ }
+ return list;
}
protected Class[] getEndpointClasses() {
@@ -121,4 +137,10 @@
return endpoint;
}
+ /**
+ * Adds a new component dynamically
+ */
+ public void addEndpoint(BeanEndpoint endpoint) throws Exception {
+ super.addEndpoint(endpoint);
+ }
}
Modified:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanEndpoint.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanEndpoint.java?view=diff&rev=466049&r1=466048&r2=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanEndpoint.java
(original)
+++
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/BeanEndpoint.java
Fri Oct 20 03:12:26 2006
@@ -57,6 +57,8 @@
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationContext;
/**
* Represents a bean endpoint which consists of a together with a [EMAIL
PROTECTED] MethodInvocationStrategy}
@@ -65,9 +67,9 @@
* @version $Revision: $
* @org.apache.xbean.XBean element="endpoint"
*/
-public class BeanEndpoint extends ProviderEndpoint implements BeanFactoryAware
{
+public class BeanEndpoint extends ProviderEndpoint implements
ApplicationContextAware {
- private BeanFactory beanFactory;
+ private ApplicationContext applicationContext;
private String beanName;
private Object bean;
private BeanInfo beanInfo;
@@ -87,7 +89,7 @@
public BeanEndpoint(BeanComponent component, ServiceEndpoint
serviceEndpoint) {
super(component, serviceEndpoint);
- setBeanFactory(component.getBeanFactory());
+ setApplicationContext(component.getApplicationContext());
}
public void start() throws Exception {
@@ -114,12 +116,13 @@
}
}
- public BeanFactory getBeanFactory() {
- return beanFactory;
+
+ public ApplicationContext getApplicationContext() {
+ return applicationContext;
}
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
+ public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
+ this.applicationContext = applicationContext;
}
public String getBeanName() {
@@ -294,10 +297,10 @@
return beanType.newInstance();
} else if (beanName == null) {
throw new IllegalArgumentException("Property 'beanName',
'beanType' or 'beanClassName' must be set!");
- } else if (beanFactory == null) {
+ } else if (applicationContext == null) {
throw new IllegalArgumentException("Property 'beanName' specified,
but no BeanFactory set!");
} else {
- Object answer = beanFactory.getBean(beanName);
+ Object answer = applicationContext.getBean(beanName);
if (answer == null) {
throw new NoSuchBeanException(beanName, this);
}
@@ -423,5 +426,4 @@
public void
setCorrelationExpression(org.apache.servicemix.expression.Expression
correlationExpression) {
this.correlationExpression = correlationExpression;
}
-
}
Added:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,25 @@
+package org.apache.servicemix.bean;
+
+import javax.xml.namespace.QName;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @version $Revision$
+ */
[EMAIL PROTECTED](RUNTIME)
[EMAIL PROTECTED]({ElementType.TYPE})
+public @interface Endpoint {
+
+ String name() default "";
+
+ String uri() default "";
+
+ String serviceName() default "";
+
+ String targetNamespace() default "";
+
+ boolean enabled() default true;
+}
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/Endpoint.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,138 @@
+/**
+ *
+ * Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.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.servicemix.bean;
+
+import org.apache.servicemix.bean.support.ResolverUtil;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import javax.xml.namespace.QName;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Used to find POJOs on the classpath to be auto-exposed as endpoints
+ *
+ * @version $Revision$
+ */
+public class EndpointFinder implements ApplicationContextAware {
+ private ApplicationContext applicationContext;
+ private ResolverUtil resolver = new ResolverUtil();
+ private String[] packages = {};
+ private BeanComponent beanComponent;
+
+ public EndpointFinder(BeanComponent beanComponent) {
+ this.beanComponent = beanComponent;
+ this.packages = beanComponent.getSearchPackages();
+ this.applicationContext = beanComponent.getApplicationContext();
+ }
+
+ public String[] getPackages() {
+ return packages;
+ }
+
+ public void setPackages(String[] packages) {
+ this.packages = packages;
+ }
+
+ public ApplicationContext getApplicationContext() {
+ return applicationContext;
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+
+ public void addEndpoints(List list) {
+ resolver.findAnnotated(Endpoint.class, packages);
+ Set<Class> classes = resolver.getClasses();
+ for (Class aClass : classes) {
+ if (shouldIgnoreBean(aClass)) {
+ continue;
+ }
+ if (isClient(aClass)) {
+ registerClient(aClass);
+ }
+ else if (!Modifier.isAbstract(aClass.getModifiers())) {
+ list.add(createBeanEndpoint(aClass));
+ }
+ }
+ }
+
+ public void destroy() throws Exception {
+ }
+
+ /**
+ * Should the bean be ignored?
+ */
+ protected boolean shouldIgnoreBean(Class type) {
+ Map beans = applicationContext.getBeansOfType(type, true, true);
+ if (beans == null || beans.isEmpty()) {
+ return false;
+ }
+ // TODO apply some filter?
+ return true;
+ }
+
+ /**
+ * Returns true if the interface is a client side interface
+ */
+ protected boolean isClient(Class type) {
+ return type.isInterface() || Modifier.isAbstract(type.getModifiers());
+ }
+
+ protected void registerClient(Class type) {
+ /** TODO */
+ }
+
+
+ protected BeanEndpoint createBeanEndpoint(Class serviceType) {
+ Endpoint endpointAnnotation = (Endpoint)
serviceType.getAnnotation(Endpoint.class);
+ if (endpointAnnotation == null) {
+ throw new IllegalArgumentException("Could not find endpoint
annotation on type: " + serviceType);
+ }
+ BeanEndpoint answer = new BeanEndpoint();
+ answer.setBeanType(serviceType);
+ answer.setEndpoint(endpointAnnotation.name());
+ QName service = createQName(endpointAnnotation.serviceName(),
endpointAnnotation.targetNamespace());
+ if (service == null) {
+ service = BeanComponent.EPR_SERVICE;
+ }
+ answer.setService(service);
+ return answer;
+ }
+
+ protected QName createQName(String localName, String uri) {
+ if (isNotNullOrBlank(localName)) {
+ if (isNotNullOrBlank(uri)) {
+ return new QName(uri, localName);
+ }
+ return new QName(localName);
+ }
+ return null;
+ }
+
+
+ protected boolean isNotNullOrBlank(String text) {
+ return text != null && text.trim().length() > 0;
+ }
+}
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/EndpointFinder.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,325 @@
+/* Copyright 2005-2006 Tim Fennell
+ *
+ * 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.servicemix.bean.support;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * <p>ResolverUtil is used to locate classes that are available in the/a class
path and meet
+ * arbitrary conditions. The two most common conditions are that a class
implements/extends
+ * another class, or that is it annotated with a specific annotation. However,
through the use
+ * of the [EMAIL PROTECTED] Test} class it is possible to search using
arbitrary conditions.</p>
+ *
+ * <p>A ClassLoader is used to locate all locations (directories and jar
files) in the class
+ * path that contain classes within certain packages, and then to load those
classes and
+ * check them. By default the ClassLoader returned by
+ * [EMAIL PROTECTED] Thread.currentThread().getContextClassLoader()} is used,
but this can be overridden
+ * by calling [EMAIL PROTECTED] #setClassLoader(ClassLoader)} prior to
invoking any of the [EMAIL PROTECTED] find()}
+ * methods.</p>
+ *
+ * <p>General searches are initiated by calling the
+ * [EMAIL PROTECTED] #find(ResolverUtil.Test, String)} ()} method and supplying
+ * a package name and a Test instance. This will cause the named package
<b>and all sub-packages</b>
+ * to be scanned for classes that meet the test. There are also utility
methods for the common
+ * use cases of scanning multiple packages for extensions of particular
classes, or classes
+ * annotated with a specific annotation.</p>
+ *
+ * <p>The standard usage pattern for the ResolverUtil class is as follows:</p>
+ *
+ *<pre>
+ *ResolverUtil<ActionBean> resolver = new
ResolverUtil<ActionBean>();
+ *resolver.findImplementation(ActionBean.class, pkg1, pkg2);
+ *resolver.find(new CustomTest(), pkg1);
+ *resolver.find(new CustomTest(), pkg2);
+ *Collection<ActionBean> beans = resolver.getClasses();
+ *</pre>
+ *
+ * @author Tim Fennell
+ */
+public class ResolverUtil<T> {
+ private static final transient Log log =
LogFactory.getLog(ResolverUtil.class);
+
+ /**
+ * A simple interface that specifies how to test classes to determine if
they
+ * are to be included in the results produced by the ResolverUtil.
+ */
+ public static interface Test {
+ /**
+ * Will be called repeatedly with candidate classes. Must return True
if a class
+ * is to be included in the results, false otherwise.
+ */
+ boolean matches(Class type);
+ }
+
+ /**
+ * A Test that checks to see if each class is assignable to the provided
class. Note
+ * that this test will match the parent type itself if it is presented for
matching.
+ */
+ public static class IsA implements Test {
+ private Class parent;
+
+ /** Constructs an IsA test using the supplied Class as the parent
class/interface. */
+ public IsA(Class parentType) { this.parent = parentType; }
+
+ /** Returns true if type is assignable to the parent type supplied in
the constructor. */
+ public boolean matches(Class type) {
+ return type != null && parent.isAssignableFrom(type);
+ }
+
+ @Override public String toString() {
+ return "is assignable to " + parent.getSimpleName();
+ }
+ }
+
+ /**
+ * A Test that checks to see if each class is annotated with a specific
annotation. If it
+ * is, then the test returns true, otherwise false.
+ */
+ public static class AnnotatedWith implements Test {
+ private Class<? extends Annotation> annotation;
+
+ /** Construts an AnnotatedWith test for the specified annotation type.
*/
+ public AnnotatedWith(Class<? extends Annotation> annotation) {
this.annotation = annotation; }
+
+ /** Returns true if the type is annotated with the class provided to
the constructor. */
+ public boolean matches(Class type) {
+ return type != null && type.isAnnotationPresent(annotation);
+ }
+
+ @Override public String toString() {
+ return "annotated with @" + annotation.getSimpleName();
+ }
+ }
+
+ /** The set of matches being accumulated. */
+ private Set<Class<? extends T>> matches = new HashSet<Class<?extends T>>();
+
+ /**
+ * The ClassLoader to use when looking for classes. If null then the
ClassLoader returned
+ * by Thread.currentThread().getContextClassLoader() will be used.
+ */
+ private ClassLoader classloader;
+
+ /**
+ * Provides access to the classes discovered so far. If no calls have been
made to
+ * any of the [EMAIL PROTECTED] find()} methods, this set will be empty.
+ *
+ * @return the set of classes that have been discovered.
+ */
+ public Set<Class<? extends T>> getClasses() {
+ return matches;
+ }
+
+ /**
+ * Returns the classloader that will be used for scanning for classes. If
no explicit
+ * ClassLoader has been set by the calling, the context class loader will
be used.
+ *
+ * @return the ClassLoader that will be used to scan for classes
+ */
+ public ClassLoader getClassLoader() {
+ return classloader == null ?
Thread.currentThread().getContextClassLoader() : classloader;
+ }
+
+ /**
+ * Sets an explicit ClassLoader that should be used when scanning for
classes. If none
+ * is set then the context classloader will be used.
+ *
+ * @param classloader a ClassLoader to use when scanning for classes
+ */
+ public void setClassLoader(ClassLoader classloader) { this.classloader =
classloader; }
+
+ /**
+ * Attempts to discover classes that are assignable to the type provided.
In the case
+ * that an interface is provided this method will collect implementations.
In the case
+ * of a non-interface class, subclasses will be collected. Accumulated
classes can be
+ * accessed by calling [EMAIL PROTECTED] #getClasses()}.
+ *
+ * @param parent the class of interface to find subclasses or
implementations of
+ * @param packageNames one or more package names to scan (including
subpackages) for classes
+ */
+ public void findImplementations(Class parent, String... packageNames) {
+ if (packageNames == null) return;
+
+ Test test = new IsA(parent);
+ for (String pkg : packageNames) {
+ find(test, pkg);
+ }
+ }
+
+ /**
+ * Attempts to discover classes that are annotated with to the annotation.
Accumulated
+ * classes can be accessed by calling [EMAIL PROTECTED] #getClasses()}.
+ *
+ * @param annotation the annotation that should be present on matching
classes
+ * @param packageNames one or more package names to scan (including
subpackages) for classes
+ */
+ public void findAnnotated(Class<? extends Annotation> annotation,
String... packageNames) {
+ if (packageNames == null) return;
+
+ Test test = new AnnotatedWith(annotation);
+ for (String pkg : packageNames) {
+ find(test, pkg);
+ }
+ }
+
+ /**
+ * Scans for classes starting at the package provided and descending into
subpackages.
+ * Each class is offered up to the Test as it is discovered, and if the
Test returns
+ * true the class is retained. Accumulated classes can be fetched by
calling
+ * [EMAIL PROTECTED] #getClasses()}.
+ *
+ * @param test an instance of [EMAIL PROTECTED] Test} that will be used to
filter classes
+ * @param packageName the name of the package from which to start scanning
for
+ * classes, e.g. [EMAIL PROTECTED] net.sourceforge.stripes}
+ */
+ public void find(Test test, String packageName) {
+ packageName = packageName.replace('.', '/');
+ ClassLoader loader = getClassLoader();
+ Enumeration<URL> urls;
+
+ try {
+ urls = loader.getResources(packageName);
+ }
+ catch (IOException ioe) {
+ log.warn("Could not read package: " + packageName, ioe);
+ return;
+ }
+
+ while (urls.hasMoreElements()) {
+ try {
+ String urlPath = urls.nextElement().getFile();
+ urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+ // If it's a file in a directory, trim the stupid file: spec
+ if ( urlPath.startsWith("file:") ) {
+ urlPath = urlPath.substring(5);
+ }
+
+ // Else it's in a JAR, grab the path to the jar
+ if (urlPath.indexOf('!') > 0) {
+ urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+ }
+
+ log.info("Scanning for classes in [" + urlPath + "] matching
criteria: " + test);
+ File file = new File(urlPath);
+ if ( file.isDirectory() ) {
+ loadImplementationsInDirectory(test, packageName, file);
+ }
+ else {
+ loadImplementationsInJar(test, packageName, file);
+ }
+ }
+ catch (IOException ioe) {
+ log.warn("could not read entries", ioe);
+ }
+ }
+ }
+
+
+ /**
+ * Finds matches in a physical directory on a filesystem. Examines all
+ * files within a directory - if the File object is not a directory, and
ends with <i>.class</i>
+ * the file is loaded and tested to see if it is acceptable according to
the Test. Operates
+ * recursively to find classes within a folder structure matching the
package structure.
+ *
+ * @param test a Test used to filter the classes that are discovered
+ * @param parent the package name up to this directory in the package
hierarchy. E.g. if
+ * /classes is in the classpath and we wish to examine files in
/classes/org/apache then
+ * the values of <i>parent</i> would be <i>org/apache</i>
+ * @param location a File object representing a directory
+ */
+ private void loadImplementationsInDirectory(Test test, String parent, File
location) {
+ File[] files = location.listFiles();
+ StringBuilder builder = null;
+
+ for (File file : files) {
+ builder = new StringBuilder(100);
+ builder.append(parent).append("/").append(file.getName());
+ String packageOrClass = ( parent == null ? file.getName() :
builder.toString() );
+
+ if (file.isDirectory()) {
+ loadImplementationsInDirectory(test, packageOrClass, file);
+ }
+ else if (file.getName().endsWith(".class")) {
+ addIfMatching(test, packageOrClass);
+ }
+ }
+ }
+
+ /**
+ * Finds matching classes within a jar files that contains a folder
structure
+ * matching the package structure. If the File is not a JarFile or does
not exist a warning
+ * will be logged, but no error will be raised.
+ *
+ * @param test a Test used to filter the classes that are discovered
+ * @param parent the parent package under which classes must be in order
to be considered
+ * @param jarfile the jar file to be examined for classes
+ */
+ private void loadImplementationsInJar(Test test, String parent, File
jarfile) {
+
+ try {
+ JarEntry entry;
+ JarInputStream jarStream = new JarInputStream(new
FileInputStream(jarfile));
+
+ while ( (entry = jarStream.getNextJarEntry() ) != null) {
+ String name = entry.getName();
+ if (!entry.isDirectory() && name.startsWith(parent) &&
name.endsWith(".class")) {
+ addIfMatching(test, name);
+ }
+ }
+ }
+ catch (IOException ioe) {
+ log.error("Could not search jar file '" + jarfile + "' for classes
matching criteria: " +
+ test + "due to an IOException: " + ioe.getMessage());
+ }
+ }
+
+ /**
+ * Add the class designated by the fully qualified class name provided to
the set of
+ * resolved classes if and only if it is approved by the Test supplied.
+ *
+ * @param test the test used to determine if the class matches
+ * @param fqn the fully qualified name of a class
+ */
+ protected void addIfMatching(Test test, String fqn) {
+ try {
+ String externalName = fqn.substring(0,
fqn.indexOf('.')).replace('/', '.');
+ ClassLoader loader = getClassLoader();
+ log.trace("Checking to see if class " + externalName + " matches
criteria [" + test+ "]");
+
+ Class type = loader.loadClass(externalName);
+ if (test.matches(type) ) {
+ matches.add( (Class<T>) type);
+ }
+ }
+ catch (Throwable t) {
+ log.warn("Could not examine class '"+ fqn + "' due to a " +
+ t.getClass().getName()+ " with message: " +
t.getMessage());
+ }
+ }
+}
\ No newline at end of file
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/main/java/org/apache/servicemix/bean/support/ResolverUtil.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,100 @@
+/**
+ *
+ * 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.servicemix.bean;
+
+import org.apache.servicemix.tck.SpringTestSupport;
+import org.apache.servicemix.client.DefaultServiceMixClient;
+import org.apache.servicemix.jbi.resolver.URIResolver;
+import org.apache.servicemix.jbi.jaxp.StringSource;
+import org.apache.servicemix.jbi.jaxp.SourceTransformer;
+import org.apache.servicemix.bean.beans.PlainBean;
+import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
+import org.w3c.dom.DocumentFragment;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+
+import javax.jbi.servicedesc.ServiceEndpoint;
+import javax.jbi.messaging.InOnly;
+import javax.jbi.messaging.MessageExchange;
+import javax.jbi.messaging.NormalizedMessage;
+import javax.jbi.messaging.ExchangeStatus;
+import javax.xml.namespace.QName;
+
+public class AutoDeployedEndpointTest extends SpringTestSupport {
+
+ public void testSendingToDynamicEndpointForPlainBeanWithFooOperation()
throws Exception {
+ // now lets make a request on this endpoint
+ DefaultServiceMixClient client = new DefaultServiceMixClient(jbi);
+
+ InOnly exchange = client.createInOnlyExchange();
+ exchange.setService(new QName("urn:test", "service"));
+ exchange.setOperation(new QName("foo"));
+ exchange.getInMessage().setContent(new
StringSource("<hello>world</hello>"));
+ client.sendSync(exchange);
+
+ assertExchangeWorked(exchange);
+
+ /*
+ PlainBean bean = (PlainBean) getBean("plainBean");
+ MessageExchange answer = bean.getFoo();
+
+ log.info("Bean's foo() method has been invoked: " + answer);
+
+ assertNotNull("Bean's foo() method should bave been invoked", answer);
+ */
+ }
+
+ public void testSendingToDynamicEndpointForPlainBeanWithBarOperation()
throws Exception {
+ // now lets make a request on this endpoint
+ DefaultServiceMixClient client = new DefaultServiceMixClient(jbi);
+
+ InOnly exchange = client.createInOnlyExchange();
+ exchange.setService(new QName("urn:test", "service"));
+ exchange.setOperation(new QName("bar"));
+ exchange.getInMessage().setContent(new
StringSource("<hello>world</hello>"));
+ client.sendSync(exchange);
+
+ assertExchangeWorked(exchange);
+
+ /*
+ PlainBean bean = (PlainBean) getBean("plainBean");
+ MessageExchange bar = bean.getBar();
+ log.info("Bean's bar() method has been invoked: " + bar);
+
+ assertNotNull("Bean's bar() method should bave been invoked", bar);
+ */
+ }
+
+ protected void assertExchangeWorked(MessageExchange me) throws Exception {
+ if (me.getStatus() == ExchangeStatus.ERROR) {
+ if (me.getError() != null) {
+ throw me.getError();
+ }
+ else {
+ fail("Received ERROR status");
+ }
+ }
+ else if (me.getFault() != null) {
+ fail("Received fault: " + new
SourceTransformer().toString(me.getFault().getContent()));
+ }
+ }
+
+ protected AbstractXmlApplicationContext createBeanFactory() {
+ return new
ClassPathXmlApplicationContext("spring-no-endpoints-or-beans.xml");
+ }
+
+}
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/AutoDeployedEndpointTest.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,51 @@
+/**
+ *
+ * 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.servicemix.bean.beans;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.servicemix.bean.Property;
+import org.apache.servicemix.bean.XPath;
+import org.apache.servicemix.bean.Content;
+import org.apache.servicemix.bean.Endpoint;
+
+import javax.jbi.messaging.MessageExchange;
+
+/**
+ * A simple POJO which uses annotations to expose it on a JBI bus
+ *
+ * @version $Revision: $
+ */
[EMAIL PROTECTED](name="cheese", targetNamespace = "urn:test", serviceName =
"service")
+public class AutoDeployedBean {
+
+ private static final Log log = LogFactory.getLog(AutoDeployedBean.class);
+
+ private MessageExchange foo;
+ private MessageExchange bar;
+
+ public void foo(MessageExchange messageExchange) {
+ this.foo = messageExchange;
+ log.info("foo() called with exchange: " + messageExchange);
+ }
+
+ public void bar(MessageExchange messageExchange) {
+ this.bar = messageExchange;
+ log.info("bar() called with exchange: " + messageExchange);
+ }
+}
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/AutoDeployedBean.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/ConsumerListener.java
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/ConsumerListener.java?view=diff&rev=466049&r1=466048&r2=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/ConsumerListener.java
(original)
+++
incubator/servicemix/trunk/servicemix-bean/src/test/java/org/apache/servicemix/bean/beans/ConsumerListener.java
Fri Oct 20 03:12:26 2006
@@ -16,27 +16,33 @@
*/
package org.apache.servicemix.bean.beans;
+import org.apache.servicemix.MessageExchangeListener;
+import org.apache.servicemix.jbi.util.MessageUtil;
+
import javax.annotation.Resource;
import javax.jbi.messaging.DeliveryChannel;
import javax.jbi.messaging.InOut;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessageExchangeFactory;
import javax.jbi.messaging.MessagingException;
-import javax.jbi.messaging.NormalizedMessage;
-
-import org.apache.servicemix.MessageExchangeListener;
-import org.apache.servicemix.jbi.util.MessageUtil;
public class ConsumerListener implements MessageExchangeListener {
@Resource
private DeliveryChannel channel;
-
+
public void onMessageExchange(MessageExchange exchange) throws
MessagingException {
MessageExchangeFactory factory = channel.createExchangeFactory();
InOut io = factory.createInOutExchange();
- NormalizedMessage nm = io.createMessage();
- MessageUtil.transferInToIn(exchange, io);
+ try {
+ MessageUtil.transferInToIn(exchange, io);
+ }
+ catch (MessagingException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new MessagingException(e);
+ }
}
}
Added:
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
URL:
http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml?view=auto&rev=466049
==============================================================================
---
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
(added)
+++
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
Fri Oct 20 03:12:26 2006
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<beans xmlns:sm="http://servicemix.apache.org/config/1.0"
+ xmlns:bean="http://servicemix.apache.org/bean/1.0"
+ xmlns:test="urn:test">
+
+ <sm:container id="jbi" embedded="true" createMBeanServer="false">
+ <sm:activationSpecs>
+ <sm:activationSpec>
+ <sm:component>
+ <bean:component searchPackages="org.apache.servicemix.bean.beans"/>
+ </sm:component>
+ </sm:activationSpec>
+ </sm:activationSpecs>
+ </sm:container>
+
+</beans>
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange:
incubator/servicemix/trunk/servicemix-bean/src/test/resources/spring-no-endpoints-or-beans.xml
------------------------------------------------------------------------------
svn:mime-type = text/xml