Resurrect dead 1.0 branch so code can be reused for creating a Geronimo kernel bridge
git-svn-id: https://svn.apache.org/repos/asf/geronimo/xbean/branches/xbean-1.0@417577 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/kernel/converting-gbean.apt b/kernel/converting-gbean.apt
new file mode 100644
index 0000000..5b7c683
--- /dev/null
+++ b/kernel/converting-gbean.apt
@@ -0,0 +1,54 @@
+ -----
+ Converting gbean.org from m1 to m2
+ -----
+ Jason van Zyl
+ -----
+
+ What follows is a little description of the the process that I go through
+ when converting an m1 project to an m2 project. In this example I'm going to
+ use gbean.org, Dain Sundstrom's [yada yada yada] ...
+
+ Usually when I start looking at converting a project from m1 to m2 I take a
+ quick look at the directory structure because the standard layout we
+ decided upon for m2 is slightly different from layout most common in m1
+ and it's understandable that folks might not want to change their layout.
+ I talked it over with Dain and because SVN makes it so easy to shuffle things
+ around he decided it would be ok to use the m2 standard. Using the m2
+ standards does make things easier because the standards for m2 are
+ encapsulated in the Super POM that all m2 project inherit from. You can sort of
+ think of the Super POM in Maven as the analog of <<<java.lang.Object>>> in Java.
+
+ - pitfalls in using the default structure
+
+ - resources in the same directories as sources
+
+ - some things we don't have in m2 right now are a clover plugin
+
+ Updating the POM
+
+ - change pomVersion to modelVersion and 3 to 4.0.0
+
+ - the id element is deprecated an calculated in m2, so i changed the
+ id element to artifactId
+
+ - currentVersion to version
+
+ - change the version from 1.0-SNAPSHOT to 1.0-alpha-1-SNAPSHOT
+
+ - package element no longer exists, it will be the job of plugins
+
+ - remove the siteAddress and siteDirectory elemement and replace it
+ with the distributionManagement element
+
+ - removed the entire build element because we are using m2 standards
+ which are encapsulated in the Super POM.
+
+ - remove the reports for now as we don't have many
+
+Annoyances
+
+ The single biggest annoyance with converting from m1 to m2 is the fact that
+ often times people have not made POMs for artifacts we have entered into the
+ repository. With m2 the build will not work if artifacts do not have the
+ accompanying POMs.
+
diff --git a/kernel/m2-readme.txt b/kernel/m2-readme.txt
new file mode 100644
index 0000000..3750464
--- /dev/null
+++ b/kernel/m2-readme.txt
@@ -0,0 +1,9 @@
+Trying Maven 2.x
+----------------
+
+If you want to try m2 then simply run the mavenizer.sh script which
+will produce an "m2" directory. Move into the "m2" directory and
+
+m2 install
+
+That should compile, test, package and install
diff --git a/kernel/maven.xml b/kernel/maven.xml
new file mode 100644
index 0000000..3e2c28a
--- /dev/null
+++ b/kernel/maven.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<project default="default"
+ xmlns:j="jelly:core"
+ xmlns:ant="jelly:ant"
+ >
+
+ <!-- ==================== -->
+ <!-- Default Global Goals -->
+ <!-- ==================== -->
+
+ <goal name="default">
+ <attainGoal name="jar:install"/>
+ </goal>
+
+ <goal name="build">
+ <attainGoal name="default"/>
+ </goal>
+
+ <goal name="rebuild">
+ <attainGoal name="clean"/>
+ <attainGoal name="build"/>
+ </goal>
+
+ <!-- Check if the tests need to run -->
+ <preGoal name="test:test">
+ <j:if test="${context.getVariable('maven.test.force') == null}">
+ <j:if test="${cloveroverride != 'true'}">
+ <j:set var="uptodatePropName" value="tests.uptodate"/>
+ <j:remove var="${uptodatePropName}"/>
+ <ant:mkdir dir="${basedir}/target/test-reports/"/>
+ <j:set var="uptodateFile" value="${basedir}/target/test-reports/tstamp"/>
+
+ <ant:uptodate property="${uptodatePropName}" targetfile="${uptodateFile}">
+ <ant:srcfiles dir="${basedir}/src/" includes="**/*"/>
+ </ant:uptodate>
+
+ <j:if test="${context.getVariable(uptodatePropName) == 'true'}">
+ <ant:echo>NOTICE: Skipping tests; they seem to have passed already</ant:echo>
+ <j:set var="maven.test.skip" value="true"/>
+ <j:set var="unitTestSourcesPresent" value="false"/>
+ </j:if>
+ </j:if>
+ </j:if>
+ </preGoal>
+
+ <!-- Update the timestamp of the last successful test -->
+ <postGoal name="test:test">
+ <j:if test="${context.getVariable('maven.test.failure') == null}">
+ <ant:touch file="${basedir}/target/test-reports/tstamp"/>
+ </j:if>
+ </postGoal>
+</project>
diff --git a/kernel/project.properties b/kernel/project.properties
new file mode 100644
index 0000000..8303fb3
--- /dev/null
+++ b/kernel/project.properties
@@ -0,0 +1,34 @@
+###
+# Copyright 2005 the original author or authors.
+#
+# 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.
+###
+maven.repo.remote=http://www.gbean.org/maven,http://www.openejb.org/maven,http://www.ibiblio.org/maven
+
+maven.compile.source=1.4
+maven.compile.target=1.4
+maven.compile.deprecation=false
+maven.compile.debug=true
+maven.compile.optimize=true
+
+maven.remote.group=gbean
+maven.username=${user.name}
+maven.repo.central=beaver.codehaus.org
+maven.repo.central.directory=/dist
+
+maven.javadoc.source=1.4
+maven.javadoc.links=http://java.sun.com/j2se/1.4.1/docs/api/
+maven.javadoc.additionalparam=-linksource
+
+maven.site.deploy.method=rsync
+maven.site.deploy.clean=true
diff --git a/kernel/project.xml b/kernel/project.xml
new file mode 100644
index 0000000..2ce1f5d
--- /dev/null
+++ b/kernel/project.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<project>
+ <!-- the version of maven's project object model -->
+ <pomVersion>3</pomVersion>
+
+ <name>GBean :: Kernel</name>
+ <id>gbean-kernel</id>
+ <groupId>gbean</groupId>
+ <currentVersion>1.0-SNAPSHOT</currentVersion>
+ <organization>
+ <name>GBean.org</name>
+ <url>http://gbean.org</url>
+ </organization>
+
+ <package>org.gbean</package>
+
+ <shortDescription>GBean: kernel for containers</shortDescription>
+
+ <description>
+ GBean is a kernel architecture and server for ioc containers such as spring.
+ </description>
+
+ <url>http://www.gbean.org/</url>
+
+ <siteAddress>www.gbean.org</siteAddress>
+ <siteDirectory>/home/projects/gbean/public_html/maven</siteDirectory>
+
+ <mailingLists>
+ <mailingList>
+ <name>gbean developers</name>
+ <subscribe>mailto:dev-subscribe@gbean.org</subscribe>
+ <unsubscribe>mailto:dev-unsubscribe@gbean.org</unsubscribe>
+ </mailingList>
+ <mailingList>
+ <name>gbean users</name>
+ <subscribe>mailto:user-subscribe@gbean.org</subscribe>
+ <unsubscribe>mailto:user-unsubscribe@gbean.org</unsubscribe>
+ </mailingList>
+ <mailingList>
+ <name>gbean source control messages</name>
+ <subscribe>mailto:scm-subscribe@gbean.org</subscribe>
+ <unsubscribe>mailto:scm-unsubscribe@gbean.org</unsubscribe>
+ </mailingList>
+ </mailingLists>
+
+ <dependencies>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <version>2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.8</version>
+ </dependency>
+ <dependency>
+ <groupId>geronimo</groupId>
+ <artifactId>geronimo-kernel</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>mx4j</groupId>
+ <artifactId>mx4j</artifactId>
+ <version>3.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>springframework</groupId>
+ <artifactId>spring</artifactId>
+ <version>1.2</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src/java</sourceDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/resources</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <unitTestSourceDirectory>src/test</unitTestSourceDirectory>
+ <unitTest>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/test</directory>
+ <includes>
+ <include>**/*.properties</include>
+ </includes>
+ </resource>
+ </resources>
+ </unitTest>
+ </build>
+
+ <reports>
+ <!-- <report>maven-license-plugin</report> -->
+ <!-- <report>maven-checkstyle-plugin</report>-->
+ <!-- <report>maven-pmd-plugin</report> -->
+ <!-- <report>maven-simian-plugin</report> -->
+ <!-- <report>maven-jdepend-plugin</report> -->
+ <!-- <report>maven-changelog-plugin</report> -->
+ <!-- <report>maven-statcvs-plugin</report> -->
+ <!-- <report>maven-file-activity-plugin</report> -->
+ <!-- <report>maven-developer-activity-plugin</report> -->
+ <report>maven-jxr-plugin</report>
+ <report>maven-javadoc-plugin</report>
+ <report>maven-junit-report-plugin</report>
+ <!-- <report>maven-faq-plugin</report> -->
+ <!-- <report>maven-clover-plugin</report>-->
+ <!-- <report>maven-changes-plugin</report>-->
+ </reports>
+
+</project>
+
diff --git a/kernel/src/java/org/gbean/beans/LiveCollection.java b/kernel/src/java/org/gbean/beans/LiveCollection.java
new file mode 100644
index 0000000..0b23578
--- /dev/null
+++ b/kernel/src/java/org/gbean/beans/LiveCollection.java
@@ -0,0 +1,32 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.beans;
+
+import java.util.Collection;
+
+/**
+ * An extension of collection that allows a client to register for notifications when
+ * members are added to and removed from the collection.
+ *
+ * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
+ */
+public interface LiveCollection extends Collection {
+ void addReferenceCollectionListener(LiveCollectionListener listener);
+
+ void removeReferenceCollectionListener(LiveCollectionListener listener);
+}
diff --git a/kernel/src/java/org/gbean/beans/LiveCollectionEvent.java b/kernel/src/java/org/gbean/beans/LiveCollectionEvent.java
new file mode 100644
index 0000000..12229ba
--- /dev/null
+++ b/kernel/src/java/org/gbean/beans/LiveCollectionEvent.java
@@ -0,0 +1,39 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.beans;
+
+/**
+ * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
+ */
+public class LiveCollectionEvent {
+ private final String referenceName;
+ private final Object member;
+
+ public LiveCollectionEvent(String referenceName, Object member) {
+ this.referenceName = referenceName;
+ this.member = member;
+ }
+
+ public String getReferenceName() {
+ return referenceName;
+ }
+
+ public Object getMember() {
+ return member;
+ }
+}
diff --git a/kernel/src/java/org/gbean/beans/LiveCollectionListener.java b/kernel/src/java/org/gbean/beans/LiveCollectionListener.java
new file mode 100644
index 0000000..8cb3045
--- /dev/null
+++ b/kernel/src/java/org/gbean/beans/LiveCollectionListener.java
@@ -0,0 +1,29 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.beans;
+
+import java.util.EventListener;
+
+/**
+ * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
+ */
+public interface LiveCollectionListener extends EventListener {
+ void memberAdded(LiveCollectionEvent event);
+
+ void memberRemoved(LiveCollectionEvent event);
+}
diff --git a/kernel/src/java/org/gbean/beans/LiveHashSet.java b/kernel/src/java/org/gbean/beans/LiveHashSet.java
new file mode 100644
index 0000000..aa0eb71
--- /dev/null
+++ b/kernel/src/java/org/gbean/beans/LiveHashSet.java
@@ -0,0 +1,288 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.beans;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.KernelUtil;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class LiveHashSet implements LiveCollection, Set {
+ private static final Log log = LogFactory.getLog(LiveHashSet.class);
+ private final Kernel kernel;
+ private final String name;
+ private final Set patterns;
+ private final Map members = new HashMap();
+ private final Set listeners = new HashSet();
+ private boolean stopped = true;
+ private LifecycleListener listener;
+
+ public LiveHashSet(Kernel kernel, String name, Set patterns) {
+ this.kernel = kernel;
+ this.name = name;
+ this.patterns = patterns;
+ }
+
+ public void start() {
+ synchronized (this) {
+ if (!stopped) {
+ throw new IllegalStateException("Already started");
+ }
+ }
+
+ Set targets = KernelUtil.getRunningServiceNames(kernel, patterns);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ addTarget((ObjectName) iterator.next());
+ }
+
+ listener = new CollectionReferenceLifecycleListener();
+ kernel.addLifecycleListener(listener, patterns);
+ stopped = false;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public synchronized void destroy() {
+ stopped = true;
+ members.clear();
+ listeners.clear();
+
+ if (listener != null) {
+ kernel.removeLifecycleListener(listener);
+ listener = null;
+ }
+ }
+
+ private void addTarget(ObjectName target) {
+ Object service = null;
+ ArrayList listenerCopy;
+ synchronized (this) {
+ // if this is not a new target return
+ if (members.containsKey(target)) {
+ return;
+ }
+
+ service = getServiceReference(target);
+ if (service == null) {
+ return;
+ }
+ members.put(target, service);
+
+ // make a snapshot of the listeners
+ listenerCopy = new ArrayList(listeners);
+ }
+
+ // fire the member added event
+ for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+ LiveCollectionListener listener = (LiveCollectionListener) iterator.next();
+ try {
+ listener.memberAdded(new LiveCollectionEvent(name, service));
+ } catch (Throwable t) {
+ log.error("Listener threw exception", t);
+ }
+ }
+ }
+
+ protected Object getServiceReference(ObjectName target) {
+ try {
+ return kernel.getService(target);
+ } catch (ServiceNotFoundException e) {
+ // service was removed before we could add it
+ return null;
+ }
+ }
+
+ private void removeTarget(ObjectName target) {
+ Object service;
+ ArrayList listenerCopy;
+ synchronized (this) {
+ // remove the proxy
+ service = members.remove(target);
+
+ // if this was not a target return
+ if (service == null) {
+ return;
+ }
+
+ // make a snapshot of the listeners
+ listenerCopy = new ArrayList(listeners);
+ }
+
+ // fire the member removed event
+ for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+ LiveCollectionListener listener = (LiveCollectionListener) iterator.next();
+ try {
+ listener.memberRemoved(new LiveCollectionEvent(name, service));
+ } catch (Throwable t) {
+ log.error("Listener threw exception", t);
+ }
+ }
+ }
+
+ public synchronized boolean isStopped() {
+ return stopped;
+ }
+
+ public synchronized void addReferenceCollectionListener(LiveCollectionListener listener) {
+ listeners.add(listener);
+ }
+
+ public synchronized void removeReferenceCollectionListener(LiveCollectionListener listener) {
+ listeners.remove(listener);
+ }
+
+ public synchronized int size() {
+ if (stopped) {
+ return 0;
+ }
+ return members.size();
+ }
+
+ public synchronized boolean isEmpty() {
+ if (stopped) {
+ return true;
+ }
+ return members.isEmpty();
+ }
+
+ public synchronized boolean contains(Object o) {
+ if (stopped) {
+ return false;
+ }
+ return members.containsValue(o);
+ }
+
+ public synchronized Iterator iterator() {
+ if (stopped) {
+ return new Iterator() {
+ public boolean hasNext() {
+ return false;
+ }
+
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ return new Iterator() {
+ // copy the proxies, so the client can iterate without concurrent modification
+ // this is necssary since the client has nothing to synchronize on
+ private final Iterator iterator = new ArrayList(members.values()).iterator();
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public Object next() {
+ return iterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public synchronized Object[] toArray() {
+ if (stopped) {
+ return new Object[0];
+ }
+ return members.values().toArray();
+ }
+
+ public synchronized Object[] toArray(Object a[]) {
+ if (stopped) {
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
+ }
+ return members.values().toArray(a);
+ }
+
+ public synchronized boolean containsAll(Collection c) {
+ if (stopped) {
+ return c.isEmpty();
+ }
+ return members.values().containsAll(c);
+ }
+
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ private class CollectionReferenceLifecycleListener extends LifecycleAdapter {
+ public void running(ObjectName objectName) {
+ addTarget(objectName);
+ }
+
+ public void stopping(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+
+ public void stopped(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/beans/LiveProxyHashSet.java b/kernel/src/java/org/gbean/beans/LiveProxyHashSet.java
new file mode 100644
index 0000000..5e1d7ec
--- /dev/null
+++ b/kernel/src/java/org/gbean/beans/LiveProxyHashSet.java
@@ -0,0 +1,51 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.beans;
+
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.proxy.ProxyFactory;
+import org.gbean.proxy.ProxyManager;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class LiveProxyHashSet extends LiveHashSet {
+ private final ProxyFactory factory;
+
+ public LiveProxyHashSet(Kernel kernel, String name, Set patterns, Class type) {
+ super (kernel, name, patterns);
+
+ try {
+ factory = ProxyManager.findProxyManager(kernel).createProxyFactory(type);
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("No ProxyManager available in kernel");
+ }
+ }
+
+ protected Object getServiceReference(ObjectName target) {
+ try {
+ return factory.createProxy(target);
+ } catch (ServiceNotFoundException e) {
+ // service was removed before we could add it
+ return null;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/classloader/DestroyableClassLoader.java b/kernel/src/java/org/gbean/classloader/DestroyableClassLoader.java
new file mode 100644
index 0000000..50a5f55
--- /dev/null
+++ b/kernel/src/java/org/gbean/classloader/DestroyableClassLoader.java
@@ -0,0 +1,24 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.classloader;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface DestroyableClassLoader {
+ void destroy();
+}
diff --git a/kernel/src/java/org/gbean/classloader/JarFileClassLoader.java b/kernel/src/java/org/gbean/classloader/JarFileClassLoader.java
new file mode 100644
index 0000000..36830d1
--- /dev/null
+++ b/kernel/src/java/org/gbean/classloader/JarFileClassLoader.java
@@ -0,0 +1,324 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.classloader;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.CodeSource;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class JarFileClassLoader extends NamedClassLoader {
+ private final Object lock = new Object();
+ private final LinkedHashMap classPath;
+ private boolean destroyed = false;
+
+ public JarFileClassLoader(String name, List urls) {
+ this(name, urls, Thread.currentThread().getContextClassLoader());
+ }
+
+ public JarFileClassLoader(String name, List urls, ClassLoader parent) {
+ super(name, new URL[0], parent);
+
+ classPath = new LinkedHashMap();
+ addURLs(urls);
+ }
+
+ public URL[] getURLs() {
+ return (URL[]) classPath.keySet().toArray(new URL[classPath.keySet().size()]);
+ }
+
+ protected void addURL(URL url) {
+ addURLs(Collections.singletonList(url));
+ }
+
+ protected void addURLs(List urls) {
+ LinkedList locationStack = new LinkedList(urls);
+ try {
+ while (!locationStack.isEmpty()) {
+ URL url = (URL) locationStack.removeFirst();
+
+ if (!"file".equals(url.getProtocol())) {
+ // download the jar
+ throw new Error("Only local file jars are supported " + url);
+ }
+
+ String path = url.getPath();
+ if (classPath.containsKey(path)) {
+ continue;
+ }
+
+ File file = new File(path);
+ if (!file.canRead()) {
+ // can't read file...
+ continue;
+ }
+
+ // open the jar file
+ JarFile jarFile = null;
+ try {
+ jarFile = new JarFile(file);
+ } catch (IOException e) {
+ // can't seem to open the file
+ continue;
+ }
+ classPath.put(url, jarFile);
+
+ // push the manifest classpath on the stack (make sure to maintain the order)
+ Manifest manifest = null;
+ try {
+ manifest = jarFile.getManifest();
+ } catch (IOException ignored) {
+ }
+
+ if (manifest != null) {
+ Attributes mainAttributes = manifest.getMainAttributes();
+ String manifestClassPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
+ if (manifestClassPath != null) {
+ LinkedList classPathUrls = new LinkedList();
+ for (StringTokenizer tokenizer = new StringTokenizer(manifestClassPath, " "); tokenizer.hasMoreTokens();) {
+ String entry = tokenizer.nextToken();
+ File parentDir = file.getParentFile();
+ File entryFile = new File(parentDir, entry);
+ // manifest entries are optional... if they aren't there it is ok
+ if (entryFile.canRead()) {
+ classPathUrls.addLast(entryFile.getAbsolutePath());
+ }
+ }
+ locationStack.addAll(0, classPathUrls);
+ }
+ }
+ }
+ } catch (Error e) {
+ destroy();
+ throw e;
+ }
+ }
+
+ public void destroy() {
+ synchronized (lock) {
+ if (destroyed) {
+ return;
+ }
+ destroyed = true;
+ for (Iterator iterator = classPath.values().iterator(); iterator.hasNext();) {
+ JarFile jarFile = (JarFile) iterator.next();
+ try {
+ jarFile.close();
+ } catch (IOException ignored) {
+ }
+ }
+ classPath.clear();
+ }
+ super.destroy();
+ }
+
+ public URL findResource(String resourceName) {
+ URL jarUrl = null;
+ synchronized (lock) {
+ if (destroyed) {
+ return null;
+ }
+ for (Iterator iterator = classPath.entrySet().iterator(); iterator.hasNext() && jarUrl == null;) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ JarFile jarFile = (JarFile) entry.getValue();
+ JarEntry jarEntry = jarFile.getJarEntry(resourceName);
+ if (jarEntry != null && !jarEntry.isDirectory()) {
+ jarUrl = (URL) entry.getKey();
+ }
+ }
+ }
+
+
+ try {
+ String urlString = "jar:" + jarUrl + "!/" + resourceName;
+ return new URL(jarUrl, urlString);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ public Enumeration findResources(String resourceName) throws IOException {
+ LinkedList resources = new LinkedList();
+ synchronized (lock) {
+ if (destroyed) {
+ return null;
+ }
+ for (Iterator iterator = classPath.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ JarFile jarFile = (JarFile) entry.getValue();
+ JarEntry jarEntry = jarFile.getJarEntry(resourceName);
+ if (jarEntry != null && !jarEntry.isDirectory()) {
+ try {
+ URL url = (URL) entry.getKey();
+ String urlString = "jar:" + url + "!/" + resourceName;
+ resources.add(new URL(url, urlString));
+ } catch (MalformedURLException e) {
+ }
+ }
+ }
+ }
+
+ return Collections.enumeration(resources);
+ }
+
+ protected Class findClass(String className) throws ClassNotFoundException {
+ SecurityManager securityManager = System.getSecurityManager();
+ if (securityManager != null) {
+ String packageName = null;
+ int packageEnd = className.lastIndexOf('.');
+ if (packageEnd >= 0) {
+ packageName = className.substring(0, packageEnd);
+ securityManager.checkPackageDefinition(packageName);
+ }
+ }
+
+ Certificate[] certificates = null;
+ URL jarUrl = null;
+ Manifest manifest = null;
+ byte[] bytes;
+ synchronized (lock) {
+ if (destroyed) {
+ throw new ClassNotFoundException("Class loader has been destroyed: " + className);
+ }
+
+ try {
+ String entryName = className.replace('.', '/') + ".class";
+ InputStream inputStream = null;
+ for (Iterator iterator = classPath.entrySet().iterator(); iterator.hasNext() && inputStream == null;) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ jarUrl = (URL) entry.getKey();
+ JarFile jarFile = (JarFile) entry.getValue();
+ JarEntry jarEntry = jarFile.getJarEntry(entryName);
+ if (jarEntry != null && !jarEntry.isDirectory()) {
+ inputStream = jarFile.getInputStream(jarEntry);
+ certificates = jarEntry.getCertificates();
+ manifest = jarFile.getManifest();
+ }
+ }
+ if (inputStream == null) {
+ throw new ClassNotFoundException(className);
+ }
+
+ try {
+ byte[] buffer = new byte[4096];
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ for (int count = inputStream.read(buffer); count >= 0; count = inputStream.read(buffer)) {
+ out.write(buffer, 0, count);
+ }
+ bytes = out.toByteArray();
+ } finally {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(className, e);
+ }
+ }
+
+ definePackage(className, jarUrl, manifest);
+ CodeSource codeSource = new CodeSource(jarUrl, certificates);
+ Class clazz = defineClass(className, bytes, 0, bytes.length, codeSource);
+ return clazz;
+ }
+
+ private void definePackage(String className, URL jarUrl, Manifest manifest) {
+ int packageEnd = className.lastIndexOf('.');
+ if (packageEnd < 0) {
+ return;
+ }
+
+ String packageName = className.substring(0, packageEnd);
+ String packagePath = packageName.replace('.', '/') + "/";
+
+ Attributes packageAttributes = null;
+ Attributes mainAttributes = null;
+ if (manifest != null) {
+ packageAttributes = manifest.getAttributes(packagePath);
+ mainAttributes = manifest.getMainAttributes();
+ }
+ Package pkg = getPackage(packageName);
+ if (pkg != null) {
+ if (pkg.isSealed()) {
+ if (!pkg.isSealed(jarUrl)) {
+ throw new SecurityException("Package was already sealed with another URL: package=" + packageName + ", url=" + jarUrl);
+ }
+ } else {
+ if (isSealed(packageAttributes, mainAttributes)) {
+ throw new SecurityException("Package was already been loaded and not sealed: package=" + packageName + ", url=" + jarUrl);
+ }
+ }
+ } else {
+ String specTitle = getAttribute(Attributes.Name.SPECIFICATION_TITLE, packageAttributes, mainAttributes);
+ String specVendor = getAttribute(Attributes.Name.SPECIFICATION_VENDOR, packageAttributes, mainAttributes);
+ String specVersion = getAttribute(Attributes.Name.SPECIFICATION_VERSION, packageAttributes, mainAttributes);
+ String implTitle = getAttribute(Attributes.Name.IMPLEMENTATION_TITLE, packageAttributes, mainAttributes);
+ String implVendor = getAttribute(Attributes.Name.IMPLEMENTATION_VENDOR, packageAttributes, mainAttributes);
+ String implVersion = getAttribute(Attributes.Name.IMPLEMENTATION_VERSION, packageAttributes, mainAttributes);
+
+ URL sealBase = null;
+ if (isSealed(packageAttributes, mainAttributes)) {
+ sealBase = jarUrl;
+ }
+
+ definePackage(packageName, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
+ }
+ }
+
+ private String getAttribute(Attributes.Name name, Attributes packageAttributes, Attributes mainAttributes) {
+ if (packageAttributes != null) {
+ String value = packageAttributes.getValue(name);
+ if (value != null) {
+ return value;
+ }
+ }
+ if (mainAttributes != null) {
+ return mainAttributes.getValue(name);
+ }
+ return null;
+ }
+
+ private boolean isSealed(Attributes packageAttributes, Attributes mainAttributes) {
+ String sealed = getAttribute(Attributes.Name.SEALED, packageAttributes, mainAttributes);
+ if (sealed == null) {
+ return false;
+ }
+ if (sealed == null) {
+ return false;
+ }
+ return "true".equalsIgnoreCase(sealed);
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/classloader/NamedClassLoader.java b/kernel/src/java/org/gbean/classloader/NamedClassLoader.java
new file mode 100644
index 0000000..78b8094
--- /dev/null
+++ b/kernel/src/java/org/gbean/classloader/NamedClassLoader.java
@@ -0,0 +1,87 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.classloader;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLStreamHandlerFactory;
+import java.util.Map;
+
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class NamedClassLoader extends URLClassLoader implements DestroyableClassLoader {
+ private final String name;
+
+ public NamedClassLoader(String name, URL[] urls) {
+ super(urls);
+ this.name = name;
+ }
+
+ public NamedClassLoader(String name, URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+ this.name = name;
+ }
+
+ public NamedClassLoader(String name, URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
+ super(urls, parent, factory);
+ this.name = name;
+ }
+
+ public void destroy() {
+ LogFactory.release(this);
+ clearSoftCache(ObjectInputStream.class, "subclassAudits");
+ clearSoftCache(ObjectOutputStream.class, "subclassAudits");
+ clearSoftCache(ObjectStreamClass.class, "localDescs");
+ clearSoftCache(ObjectStreamClass.class, "reflectors");
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ private static Object clearSoftCacheLock = new Object();
+ private static boolean clearSoftCacheFailed = false;
+ private void clearSoftCache(Class clazz, String fieldName) {
+ Map cache = null;
+ try {
+ Field f = clazz.getDeclaredField(fieldName);
+ f.setAccessible(true);
+ cache = (Map) f.get(null);
+ } catch (Throwable e) {
+ synchronized (clearSoftCacheLock) {
+ // only print the failed message once per vm
+ if (!clearSoftCacheFailed) {
+ clearSoftCacheFailed = true;
+ LogFactory.getLog(JarFileClassLoader.class).error("Unable to clear SoftCache field " + fieldName + " in class " + clazz);
+ }
+ }
+ }
+
+ if (cache != null) {
+ synchronized (cache) {
+ cache.clear();
+ }
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/configuration/Configuration.java b/kernel/src/java/org/gbean/configuration/Configuration.java
new file mode 100644
index 0000000..200f753
--- /dev/null
+++ b/kernel/src/java/org/gbean/configuration/Configuration.java
@@ -0,0 +1,33 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.configuration;
+
+import java.net.URI;
+import java.util.Set;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface Configuration {
+ URI getConfigurationId();
+
+ URI getParentId();
+
+ ClassLoader getClassLoader();
+
+ Set getServiceNames();
+}
diff --git a/kernel/src/java/org/gbean/configuration/ConfigurationInfo.java b/kernel/src/java/org/gbean/configuration/ConfigurationInfo.java
new file mode 100644
index 0000000..b6b685e
--- /dev/null
+++ b/kernel/src/java/org/gbean/configuration/ConfigurationInfo.java
@@ -0,0 +1,114 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.configuration;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ConfigurationInfo {
+ /**
+ * URI used to referr to this configuration in the configuration manager
+ */
+ private URI configurationId;
+
+ /**
+ * The uri of the parent of this configuration. May be null.
+ */
+ private URI parentId;
+
+ /**
+ * The domain name of the configurations. This is used to autogenerate names for sub components.
+ */
+ private String domain;
+
+ /**
+ * The server name of the configurations. This is used to autogenerate names for sub components.
+ */
+ private String server;
+
+ /**
+ * List of URIs of jar files on which this configuration is dependent on.
+ */
+ private final LinkedHashSet dependencies = new LinkedHashSet();
+
+ public ConfigurationInfo() {
+ }
+
+ public ConfigurationInfo(ConfigurationInfo configurationInfo) {
+ configurationId = configurationInfo.configurationId;
+ parentId = configurationInfo.getParentId();
+ domain = configurationInfo.domain;
+ server = configurationInfo.server;
+ setDependencies(new ArrayList(configurationInfo.dependencies));
+ }
+
+ public URI getConfigurationId() {
+ return configurationId;
+ }
+
+ public void setConfigurationId(URI configurationId) {
+ this.configurationId = configurationId;
+ }
+
+ public URI getParentId() {
+ return parentId;
+ }
+
+ public void setParentId(URI parentId) {
+ this.parentId = parentId;
+ }
+
+ public String getDomain() {
+ return domain;
+ }
+
+ public void setDomain(String domain) {
+ this.domain = domain;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public List getDependencies() {
+ return Collections.unmodifiableList(new ArrayList(dependencies));
+ }
+
+ public void setDependencies(List dependencies) {
+ this.dependencies.clear();
+ for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
+ URI dependency = (URI) iterator.next();
+ addDependency(dependency);
+ }
+ }
+
+ public void addDependency(URI dependency) {
+ assert dependency != null;
+ this.dependencies.add(dependency);
+ }
+}
diff --git a/kernel/src/java/org/gbean/configuration/ConfigurationUtil.java b/kernel/src/java/org/gbean/configuration/ConfigurationUtil.java
new file mode 100644
index 0000000..59b279d
--- /dev/null
+++ b/kernel/src/java/org/gbean/configuration/ConfigurationUtil.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.configuration;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.gbean.classloader.NamedClassLoader;
+import org.gbean.repository.Repository;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public final class ConfigurationUtil {
+ private ConfigurationUtil() {
+ }
+
+ public static ClassLoader createClassLoader(String name, List dependencies, ClassLoader parentClassLoader, Collection repositories) {
+ List urls = new LinkedList();
+ for (Iterator i = dependencies.iterator(); i.hasNext();) {
+ URI uri = (URI) i.next();
+ URL url = null;
+ for (Iterator j = repositories.iterator(); j.hasNext();) {
+ Repository repository = (Repository) j.next();
+ if (repository.containsResource(uri)) {
+ url = repository.getResource(uri);
+ break;
+ }
+ }
+ if (url == null) {
+ throw new MissingDependencyException("Unable to resolve dependency " + uri);
+ }
+ if (!"file".equals(url.getProtocol())) {
+ throw new MissingDependencyException("Only local file jars are supported " + url);
+ }
+ urls.add(url);
+ }
+ return new NamedClassLoader(name, (URL[]) urls.toArray(new URL[urls.size()]), parentClassLoader);
+ }
+}
diff --git a/kernel/src/java/org/gbean/configuration/InvalidConfigurationException.java b/kernel/src/java/org/gbean/configuration/InvalidConfigurationException.java
new file mode 100644
index 0000000..0387114
--- /dev/null
+++ b/kernel/src/java/org/gbean/configuration/InvalidConfigurationException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.configuration;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class InvalidConfigurationException extends RuntimeException {
+ public InvalidConfigurationException() {
+ }
+
+ public InvalidConfigurationException(String s) {
+ super(s);
+ }
+
+ public InvalidConfigurationException(String s, Throwable throwable) {
+ super(s, throwable);
+ }
+
+ public InvalidConfigurationException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/kernel/src/java/org/gbean/configuration/MissingDependencyException.java b/kernel/src/java/org/gbean/configuration/MissingDependencyException.java
new file mode 100644
index 0000000..25c6667
--- /dev/null
+++ b/kernel/src/java/org/gbean/configuration/MissingDependencyException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.configuration;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class MissingDependencyException extends RuntimeException {
+ public MissingDependencyException() {
+ }
+
+ public MissingDependencyException(String s) {
+ super(s);
+ }
+
+ public MissingDependencyException(String s, Throwable throwable) {
+ super(s, throwable);
+ }
+
+ public MissingDependencyException(Throwable throwable) {
+ super(throwable);
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/CollectionReference.java b/kernel/src/java/org/gbean/geronimo/CollectionReference.java
new file mode 100644
index 0000000..9d4c107
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/CollectionReference.java
@@ -0,0 +1,115 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.ClassLoading;
+import org.gbean.service.ServiceContext;
+import org.gbean.spring.ServiceContextThreadLocal;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class CollectionReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition(String name, Set patterns, String type) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(CollectionReference.class, 0);
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ propertyValues.addPropertyValue("name", name);
+ propertyValues.addPropertyValue("patterns", patterns);
+ propertyValues.addPropertyValue("type", type);
+ return new BeanDefinitionHolder(beanDefinition, CollectionReference.class.getName());
+ }
+
+ /**
+ * Name of this reference.
+ */
+ private String name;
+
+ /**
+ * Proxy type which is injected into the service.
+ */
+ private String type;
+
+ /**
+ * The target objectName patterns to watch for a connection.
+ */
+ private Set patterns;
+
+ public CollectionReference() {
+ }
+
+ public CollectionReference(String name, Set patterns, String type) {
+ this.name = name;
+ this.patterns = patterns;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Set getPatterns() {
+ return patterns;
+ }
+
+ public void setPatterns(Set patterns) {
+ this.patterns = patterns;
+ }
+
+ public void setPattern(ObjectName pattern) {
+ this.patterns = Collections.singleton(pattern);
+ }
+
+ public final Class getObjectType() {
+ return Collection.class;
+ }
+
+ public synchronized final Object getObject() throws ClassNotFoundException {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ Class proxyType = ClassLoading.loadClass(type, serviceContext.getClassLoader());
+ return new ProxyReferenceCollection(this, name, proxyType, serviceContext.getKernel(), patterns);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/DependencyManagerBridge.java b/kernel/src/java/org/gbean/geronimo/DependencyManagerBridge.java
new file mode 100644
index 0000000..b37e98a
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/DependencyManagerBridge.java
@@ -0,0 +1,77 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.util.Set;
+import java.util.Collection;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.DependencyManager;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class DependencyManagerBridge implements org.apache.geronimo.kernel.DependencyManager {
+ private final DependencyManager dependencyManager;
+
+ public DependencyManagerBridge(DependencyManager dependencyManager) {
+ this.dependencyManager = dependencyManager;
+ }
+
+ public void close() {
+ }
+
+ public void addDependency(ObjectName child, ObjectName parent) {
+ dependencyManager.addDependency(child, parent);
+ }
+
+ public void removeDependency(ObjectName child, ObjectName parent) {
+ dependencyManager.removeDependency(child, parent);
+ }
+
+ public void removeAllDependencies(ObjectName child) {
+ dependencyManager.removeAllDependencies(child);
+ }
+
+ public void addDependencies(ObjectName child, Set parents) {
+ dependencyManager.addDependencies(child, parents);
+ }
+
+ public Set getParents(ObjectName child) {
+ return dependencyManager.getParents(child);
+ }
+
+ public Set getChildren(ObjectName parent) {
+ return dependencyManager.getChildren(parent);
+ }
+
+ public void addStartHolds(ObjectName objectName, Collection holds) {
+ dependencyManager.addStartHolds(objectName, holds);
+ }
+
+ public void removeStartHolds(ObjectName objectName, Collection holds) {
+ dependencyManager.removeStartHolds(objectName, holds);
+ }
+
+ public void removeAllStartHolds(ObjectName objectName) {
+ dependencyManager.removeAllStartHolds(objectName);
+ }
+
+ public ObjectName checkBlocker(ObjectName objectName) {
+ return dependencyManager.checkBlocker(objectName);
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/DynamicGBeanProcessor.java b/kernel/src/java/org/gbean/geronimo/DynamicGBeanProcessor.java
new file mode 100644
index 0000000..a554198
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/DynamicGBeanProcessor.java
@@ -0,0 +1,62 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.geronimo.gbean.DynamicGBean;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class DynamicGBeanProcessor implements BeanPostProcessor {
+ private final String beanName;
+ private final Map dynamicProperties;
+
+ public DynamicGBeanProcessor(String beanName, Map dynamicProperties) {
+ this.beanName = beanName;
+ this.dynamicProperties = dynamicProperties;
+ }
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if (this.beanName.equals(beanName)) {
+ for (Iterator iterator = dynamicProperties.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String propertyName = (String) entry.getKey();
+ Object propertyValue = entry.getValue();
+ try {
+ ((DynamicGBean) bean).setAttribute(propertyName, propertyValue);
+ } catch (Exception e) {
+ throw new BeanInitializationException("Error invoking dynamic property setter method:" +
+ " beanName " + beanName +
+ " beanClass " + bean.getClass() +
+ " propertyName " + propertyName +
+ " propertyValue " + propertyValue, e);
+ }
+ }
+ }
+ return bean;
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/FactoryBeanProvider.java b/kernel/src/java/org/gbean/geronimo/FactoryBeanProvider.java
new file mode 100644
index 0000000..01c673c
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/FactoryBeanProvider.java
@@ -0,0 +1,26 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface FactoryBeanProvider {
+ FactoryBean getFactoryBean();
+}
diff --git a/kernel/src/java/org/gbean/geronimo/GeronimoKernelReference.java b/kernel/src/java/org/gbean/geronimo/GeronimoKernelReference.java
new file mode 100644
index 0000000..98f8fb8
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/GeronimoKernelReference.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.io.Serializable;
+
+import org.apache.geronimo.kernel.Kernel;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.gbean.service.ServiceContext;
+import org.gbean.spring.ServiceContextThreadLocal;
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class GeronimoKernelReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(GeronimoKernelReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, GeronimoKernelReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return Kernel.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ try {
+ return (Kernel) serviceContext.getKernel().getService(Kernel.KERNEL);
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("A Geronimo kernel has not been loaded");
+ }
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/GeronimoLifecycleControllerReference.java b/kernel/src/java/org/gbean/geronimo/GeronimoLifecycleControllerReference.java
new file mode 100644
index 0000000..66b9fc7
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/GeronimoLifecycleControllerReference.java
@@ -0,0 +1,69 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.io.Serializable;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.apache.geronimo.gbean.GBeanLifecycleController;
+import org.gbean.service.ServiceContext;
+import org.gbean.spring.ServiceContextThreadLocal;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class GeronimoLifecycleControllerReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(GeronimoLifecycleControllerReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, GeronimoLifecycleControllerReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return GBeanLifecycleController.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ return new GBeanLifecycleControllerImpl(serviceContext);
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ private static class GBeanLifecycleControllerImpl implements GBeanLifecycleController {
+ private final ServiceContext serviceContext;
+
+ public GBeanLifecycleControllerImpl(ServiceContext serviceContext) {
+ this.serviceContext = serviceContext;
+ }
+
+ public int getState() {
+ return serviceContext.getState();
+ }
+
+ public void stop() throws Exception {
+ serviceContext.stop();
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/GeronimoMetadataProvider.java b/kernel/src/java/org/gbean/geronimo/GeronimoMetadataProvider.java
new file mode 100644
index 0000000..a94e29e
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/GeronimoMetadataProvider.java
@@ -0,0 +1,131 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.geronimo.gbean.GAttributeInfo;
+import org.apache.geronimo.gbean.GBeanInfo;
+import org.apache.geronimo.gbean.GReferenceInfo;
+import org.gbean.kernel.ClassLoading;
+import org.gbean.kernel.ConstructorSignature;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MetadataProvider;
+import org.gbean.metadata.ParameterMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class GeronimoMetadataProvider implements MetadataProvider {
+ public void addClassMetadata(ClassMetadata classMetadata) {
+ Class type = classMetadata.getType();
+ GBeanInfo gbeanInfo = getGBeanInfo(type);
+ if (gbeanInfo == null) {
+ return;
+ }
+
+ classMetadata.put("j2eeType", gbeanInfo.getJ2eeType());
+
+ Set attributes = gbeanInfo.getAttributes();
+ Set references = gbeanInfo.getReferences();
+ Map attributeTypes = new HashMap(attributes.size() + references.size());
+ Set persistentProperties = new HashSet();
+ for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
+ GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
+ Class attributeType = null;
+ try {
+ attributeType = ClassLoading.loadClass(attributeInfo.getType(), type.getClassLoader());
+ } catch (ClassNotFoundException ignored) {
+ // couldn't load the type.. just proceed and we'll skip the constructor declaration
+ }
+ attributeTypes.put(attributeInfo.getName(), attributeType);
+
+ if (attributeInfo.isPersistent()) {
+ persistentProperties.add(fixPropertyName(attributeInfo.getName()));
+ }
+ }
+
+ for (Iterator iterator = references.iterator(); iterator.hasNext();) {
+ GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
+ Class attributeType = null;
+ try {
+ attributeType = ClassLoading.loadClass(referenceInfo.getProxyType(), type.getClassLoader());
+ } catch (ClassNotFoundException ignored) {
+ // couldn't load the type.. just proceed and we'll skip the constructor declaration
+ }
+ attributeTypes.put(referenceInfo.getName(), attributeType);
+ persistentProperties.add(fixPropertyName(referenceInfo.getName()));
+ }
+
+
+ List constructorArgNames = gbeanInfo.getConstructor().getAttributeNames();
+ List constructorArgTypes = new ArrayList(constructorArgNames.size());
+ for (Iterator iterator = constructorArgNames.iterator(); iterator.hasNext();) {
+ String constructorArgName = (String) iterator.next();
+ constructorArgTypes.add(attributeTypes.get(constructorArgName));
+ }
+
+ if (!constructorArgTypes.contains(null)) {
+ ConstructorMetadata constructor = classMetadata.getConstructor(new ConstructorSignature(constructorArgTypes));
+ if (constructor != null) {
+ constructor.put("always-use", "true");
+ for (ListIterator iterator = constructor.getParameters().listIterator(); iterator.hasNext();) {
+ ParameterMetadata parameter = (ParameterMetadata) iterator.next();
+ String name = (String) constructorArgNames.get(iterator.previousIndex());
+ parameter.put("name", fixPropertyName(name));
+ }
+ }
+ }
+
+ if (!persistentProperties.isEmpty()) {
+ classMetadata.put("persistentProperties", persistentProperties);
+ }
+ }
+
+ private static GBeanInfo getGBeanInfo(Class type) {
+ try {
+ Method method = type.getDeclaredMethod("getGBeanInfo", new Class[]{});
+ return (GBeanInfo) method.invoke(type, new Object[]{});
+ } catch (Exception ignored) {
+ }
+
+ try {
+ Class gbeanClass = ClassLoading.loadClass(type.getName() + "GBean", type.getClassLoader());
+ Method method = gbeanClass.getDeclaredMethod("getGBeanInfo", new Class[]{});
+ return (GBeanInfo) method.invoke(gbeanClass, new Object[]{});
+ } catch (Exception ignored) {
+ }
+
+ return null;
+ }
+
+ private static String fixPropertyName(String propertyName) {
+ if (Character.isUpperCase(propertyName.charAt(0))) {
+ return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
+ }
+ return propertyName;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/GeronimoServiceFactory.java b/kernel/src/java/org/gbean/geronimo/GeronimoServiceFactory.java
new file mode 100644
index 0000000..34d01a9
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/GeronimoServiceFactory.java
@@ -0,0 +1,359 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.geronimo.gbean.GBeanLifecycleController;
+import org.apache.geronimo.kernel.Kernel;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.metadata.ParameterMetadata;
+import org.gbean.proxy.ProxyManager;
+import org.gbean.service.ConfigurableServiceFactory;
+import org.gbean.service.ServiceContext;
+import org.gbean.spring.LifecycleDetector;
+import org.gbean.spring.NamedConstructorArgs;
+import org.gbean.spring.ServiceContextThreadLocal;
+import org.gbean.spring.SpringUtil;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.support.GenericApplicationContext;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class GeronimoServiceFactory implements ConfigurableServiceFactory {
+ private final MetadataManager metadataManager;
+ private final Set persistentProperties;
+ private final ConstructorMetadata constructor;
+ private final Map dependencies;
+ private final Map dynamicProperties;
+ private final ProxyManager proxyManager;
+ private RootBeanDefinition beanDefinition;
+ private GenericApplicationContext applicationContext;
+ private Object service;
+ private boolean enabled;
+ private final List constructorArgNames;
+
+ public GeronimoServiceFactory(RootBeanDefinition beanDefinition, Map dynamicProperties, MetadataManager metadataManager, ProxyManager proxyManager) throws Exception {
+ this.metadataManager = metadataManager;
+ this.proxyManager = proxyManager;
+ this.beanDefinition = beanDefinition;
+ this.dynamicProperties = dynamicProperties;
+ dependencies = SpringUtil.extractDependencies(beanDefinition, Collections.EMPTY_MAP);
+
+ // find the constructor... geronimo always uses the same constructor
+ ClassMetadata classMetadata = metadataManager.getClassMetadata(beanDefinition.getBeanClass());
+ ConstructorMetadata constructorMetadata = null;
+ for (Iterator iterator = classMetadata.getConstructors().iterator(); iterator.hasNext();) {
+ ConstructorMetadata c = (ConstructorMetadata) iterator.next();
+ if (c.getProperties().containsKey("always-use")) {
+ constructorMetadata = c;
+ break;
+ }
+ }
+ constructor = constructorMetadata;
+
+ // determine the constructor arg names... these are alwasys defined in the gbean info
+ List constructorArgNames = new LinkedList();
+ for (Iterator iterator = constructor.getParameters().iterator(); iterator.hasNext();) {
+ ParameterMetadata parameter = (ParameterMetadata) iterator.next();
+ Object parameterName = parameter.get("name");
+ if (parameterName == null) {
+ throw new IllegalArgumentException("Parameter name is not defined");
+ }
+ constructorArgNames.add(parameterName);
+ }
+ this.constructorArgNames = Collections.unmodifiableList(constructorArgNames);
+
+ // determine the persistent properties
+ Set persistentProperties = (Set) classMetadata.get("persistentProperties");
+ if (persistentProperties == null) {
+ persistentProperties = Collections.EMPTY_SET;
+ }
+ this.persistentProperties = Collections.unmodifiableSet(persistentProperties);
+ }
+
+ public Set getPersistentProperties() {
+ return persistentProperties;
+ }
+
+ public List getConstructorArgNames() {
+ return constructorArgNames;
+ }
+
+ public Map getDynamicProperties() {
+ return dynamicProperties;
+ }
+
+ public RootBeanDefinition getBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(this.beanDefinition);
+ if (service != null) {
+ updatePersistentValues(service, beanDefinition);
+ }
+ return this.beanDefinition;
+ }
+
+ public void setBeanDefinition(RootBeanDefinition beanDefinition) {
+ this.beanDefinition = beanDefinition;
+ }
+
+ public Map getDependencies() {
+ return dependencies;
+ }
+
+ public void addDependency(String name, Set patterns) {
+ dependencies.put(name, patterns);
+ }
+
+ public Object createService(ServiceContext serviceContext) throws Exception {
+ try {
+ Object service = null;
+ ServiceContext oldServiceContext = ServiceContextThreadLocal.get();
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ ServiceContextThreadLocal.set(serviceContext);
+ Thread.currentThread().setContextClassLoader(serviceContext.getClassLoader());
+
+ // dereference all factories
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ PropertyValue[] values = propertyValues.getPropertyValues();
+ for (int i = 0; i < values.length; i++) {
+ PropertyValue propertyValue = values[i];
+ if (propertyValue.getValue() instanceof FactoryBean) {
+ FactoryBean factoryBean = (FactoryBean) propertyValue.getValue();
+ Object object = factoryBean.getObject();
+ propertyValues.removePropertyValue(propertyValue.getName());
+ propertyValues.addPropertyValue(propertyValue.getName(), object);
+ }
+ }
+
+ applicationContext = new GenericApplicationContext();
+
+ // register the post processors
+ NamedConstructorArgs namedConstructorArgs = new NamedConstructorArgs(metadataManager);
+ namedConstructorArgs.addDefaultValue("objectName", String.class, serviceContext.getObjectName());
+ namedConstructorArgs.addDefaultValue("objectName", ObjectName.class, new ObjectName(serviceContext.getObjectName()));
+ namedConstructorArgs.addDefaultValue("classLoader", ClassLoader.class, serviceContext.getClassLoader());
+ namedConstructorArgs.addDefaultValue("gbeanLifecycleController", GBeanLifecycleController.class, new GeronimoLifecycleControllerReference().getObject());
+ namedConstructorArgs.addDefaultValue("kernel", Kernel.class, serviceContext.getKernel().getService(Kernel.KERNEL));
+
+ applicationContext.addBeanFactoryPostProcessor(namedConstructorArgs);
+ LifecycleDetector lifecycleDetector = new LifecycleDetector();
+ lifecycleDetector.addLifecycleInterface(org.apache.geronimo.gbean.GBeanLifecycle.class, "doStart", "doStop");
+ applicationContext.addBeanFactoryPostProcessor(lifecycleDetector);
+ applicationContext.getBeanFactory().addBeanPostProcessor(new DynamicGBeanProcessor(serviceContext.getObjectName(), dynamicProperties));
+
+ // copy the bean definition, so we don't modify the original value
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(this.beanDefinition);
+
+ // build the bean
+ applicationContext.registerBeanDefinition(serviceContext.getObjectName(), beanDefinition);
+ applicationContext.refresh();
+ service = applicationContext.getBean(serviceContext.getObjectName());
+ } finally {
+ ServiceContextThreadLocal.set(oldServiceContext);
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+ this.service = service;
+ return service;
+ } catch (Throwable t) {
+ applicationContext = null;
+
+ if (t instanceof Exception) {
+ throw (Exception) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else {
+ throw new Error(t);
+ }
+ }
+ }
+
+ public void destroyService(ServiceContext serviceContext, Object service) {
+ // update the persistent attributes
+ try {
+ if (service != null) {
+ // update the persistent values
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(this.beanDefinition);
+ updatePersistentValues(service, beanDefinition);
+ this.beanDefinition = beanDefinition;
+ }
+ } finally {
+ this.service = null;
+ if (applicationContext != null) {
+ applicationContext.close();
+ applicationContext = null;
+ }
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Set getPropertyNames() {
+ if (persistentProperties != null) {
+ return persistentProperties;
+ } else {
+ return Collections.EMPTY_SET;
+ }
+ }
+
+ public Object getProperty(String propertyName) {
+ if (persistentProperties == null || !persistentProperties.contains(propertyName)) {
+ throw new IllegalArgumentException("Property is not persistent:" +
+ " propertyName=" + propertyName +
+ ", serviceType: " + beanDefinition.getBeanClassName());
+ }
+
+ PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(propertyName);
+ if (propertyValue != null) {
+ return propertyValue.getValue();
+ }
+
+ if (dynamicProperties.containsKey(propertyName)) {
+ return dynamicProperties.get(propertyValue);
+ }
+
+ return null;
+ }
+
+ public void setProperty(String propertyName, Object persistentValue) {
+ if (persistentProperties == null || !persistentProperties.contains(propertyName)) {
+ throw new IllegalArgumentException("Property is not persistent:" +
+ " propertyName=" + propertyName +
+ ", serviceType: " + beanDefinition.getBeanClassName());
+ }
+
+ if (dynamicProperties.containsKey(propertyName)) {
+ dynamicProperties.put(propertyName, persistentValue);
+ return;
+ }
+
+ beanDefinition.getPropertyValues().removePropertyValue(propertyName);
+ beanDefinition.getPropertyValues().addPropertyValue(propertyName, persistentValue);
+ }
+
+ private void updatePersistentValues(Object service, RootBeanDefinition beanDefinition) {
+ Map getters = new HashMap();
+ Method[] methods = service.getClass().getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+ if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() != Void.TYPE) {
+ if (methodName.length() > 3 && methodName.startsWith("get") && !methodName.equals("getClass")) {
+ String propertyName = fixPropertyName(methodName.substring(3));
+ getters.put(propertyName, method);
+ } else if (methodName.length() > 2 && methodName.startsWith("is")) {
+ String propertyName = fixPropertyName(methodName.substring(2));
+ getters.put(propertyName, method);
+ }
+ }
+ }
+ }
+
+ for (Iterator iterator = persistentProperties.iterator(); iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+
+ if (dynamicProperties.containsKey(propertyName)) {
+ Object value = getCurrentValue(getters, service, propertyName, dynamicProperties.get(propertyName));
+ dynamicProperties.put(propertyName, value);
+ } else {
+ // get the new property value
+ Object value = null;
+ PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue(propertyName);
+ if (propertyValue != null) {
+ value = propertyValue.getValue();
+ }
+ value = getCurrentValue(getters, service, propertyName, value);
+
+ // update the property value
+ beanDefinition.getPropertyValues().removePropertyValue(propertyName);
+ if (value != null) {
+ beanDefinition.getPropertyValues().addPropertyValue(propertyName, value);
+ }
+ }
+ }
+ }
+
+ private Object getCurrentValue(Map getters, Object service, String propertyName, Object defaultValue) {
+ Object value = defaultValue;
+ try {
+ Method getter = (Method) getters.get(propertyName);
+ if (getter != null) {
+ value = getter.invoke(service, null);
+ }
+ } catch (Throwable throwable) {
+ while (throwable instanceof InvocationTargetException) {
+ throwable = ((InvocationTargetException) throwable).getTargetException();
+ }
+
+ throw new RuntimeException("Problem while obtaining the currennt persistent value of property: " +
+ "propertyName=" + propertyName +
+ ", serviceType: " + beanDefinition.getBeanClassName(),
+ throwable);
+ }
+
+ // we should never get a bean definition holder
+ // we don't support them sice it is not serizlizable
+ if (value instanceof BeanDefinitionHolder) {
+ throw new IllegalArgumentException("Got a bean definition holder");
+ }
+
+ // turn proxies back into the factory bean
+ // the factory bean is serizlizable
+ if (value instanceof FactoryBeanProvider) {
+ value = ((FactoryBeanProvider) value).getFactoryBean();
+ } else {
+ Object proxyData = proxyManager.getProxyData(value);
+ if (proxyData instanceof FactoryBeanProvider) {
+ value = ((FactoryBeanProvider) proxyData).getFactoryBean();
+ } else if (proxyData instanceof FactoryBean) {
+ value = proxyData;
+ }
+ }
+ return value;
+ }
+
+ private static String fixPropertyName(String propertyName) {
+ if (Character.isUpperCase(propertyName.charAt(0))) {
+ return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
+ }
+ return propertyName;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/GeronimoUtil.java b/kernel/src/java/org/gbean/geronimo/GeronimoUtil.java
new file mode 100644
index 0000000..610dac9
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/GeronimoUtil.java
@@ -0,0 +1,311 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.geronimo.gbean.DynamicGAttributeInfo;
+import org.apache.geronimo.gbean.GAttributeInfo;
+import org.apache.geronimo.gbean.GBeanData;
+import org.apache.geronimo.gbean.GBeanInfo;
+import org.apache.geronimo.gbean.GConstructorInfo;
+import org.apache.geronimo.gbean.GReferenceInfo;
+import org.apache.geronimo.gbean.InvalidConfigurationException;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.proxy.ProxyManager;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class GeronimoUtil {
+ /**
+ * Converts the GeronimoServiceFactory into a geronimo GBeanData
+ *
+ * @return the gbean data
+ */
+ public static GBeanData createGBeanData(ObjectName objectName, GeronimoServiceFactory serviceFactory) {
+ RootBeanDefinition beanDefinition = serviceFactory.getBeanDefinition();
+ Set persistentProperties = serviceFactory.getPersistentProperties();
+ GBeanData gbeanData = new GBeanData(objectName, createGBeanInfo(serviceFactory));
+ gbeanData.setAttribute("gbeanEnabled", Boolean.valueOf(serviceFactory.isEnabled()));
+
+ // add the normal properties
+ PropertyValue[] properties = beanDefinition.getPropertyValues().getPropertyValues();
+ for (int i = 0; i < properties.length; i++) {
+ PropertyValue propertyValue = properties[i];
+ if (persistentProperties.contains(propertyValue.getName())) {
+ gbeanData.setAttribute(propertyValue.getName(), propertyValue.getValue());
+ }
+ }
+
+ // add the dynamic properties
+ for (Iterator iterator = serviceFactory.getDynamicProperties().entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String propertyName = (String) entry.getKey();
+ Object propertyValue = entry.getValue();
+ gbeanData.setAttribute(propertyName, propertyValue);
+ }
+
+ return gbeanData;
+ }
+
+ /**
+ * Converts the GeronimoServiceFactory into a geronimo GBeanInfo
+ *
+ * @return the GBeanInfo for the service
+ */
+ public static GBeanInfo createGBeanInfo(GeronimoServiceFactory serviceFactory) {
+ RootBeanDefinition beanDefinition = serviceFactory.getBeanDefinition();
+ Set persistentProperties = serviceFactory.getPersistentProperties();
+
+ // add the normal properties
+ Set attributeInfos = new HashSet();
+ PropertyValue[] properties = beanDefinition.getPropertyValues().getPropertyValues();
+ for (int i = 0; i < properties.length; i++) {
+ PropertyValue propertyValue = properties[i];
+ String propertyName = propertyValue.getName();
+ attributeInfos.add(new GAttributeInfo(propertyName,
+ "java.lang.Object",
+ persistentProperties.contains(propertyName),
+ null,
+ null));
+ }
+
+ // add the dynamic properties
+ for (Iterator iterator = serviceFactory.getDynamicProperties().keySet().iterator(); iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+ attributeInfos.add(new DynamicGAttributeInfo(propertyName,
+ "java.lang.Object",
+ true,
+ true,
+ true));
+ }
+
+ return new GBeanInfo(beanDefinition.getBeanClassName(),
+ "GBean",
+ attributeInfos,
+ new GConstructorInfo(serviceFactory.getConstructorArgNames()),
+ Collections.EMPTY_SET,
+ null);
+ }
+
+ public static GeronimoServiceFactory createGeronimoServiceFactory(GBeanData gbeanData, ClassLoader classLoader, MetadataManager metadataManager, ProxyManager proxyManager) throws Exception {
+ ObjectName objectName = gbeanData.getName();
+ String beanClassName = gbeanData.getGBeanInfo().getClassName();
+
+ // get a list of all methods in the target class
+ Class beanClass = null;
+ try {
+ beanClass = classLoader.loadClass(beanClassName);
+ } catch (ClassNotFoundException e) {
+ throw new InvalidConfigurationException("Could not load class for GBeanInstance: objectName=" + objectName + " className=" + beanClassName);
+ }
+ Method[] methods = beanClass.getMethods();
+
+ // build a map of the property names in lower case to the real property name
+ // this fixes problem where geronimo property names were loosly matched
+ Map lowerCasePropertyNameMap = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+ if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() != Void.TYPE) {
+ if (methodName.length() > 3 && methodName.startsWith("get") && !methodName.equals("getClass")) {
+ String propertyName = fixPropertyName(methodName.substring(3));
+ lowerCasePropertyNameMap.put(propertyName.toLowerCase(), propertyName);
+ } else if (methodName.length() > 2 && methodName.startsWith("is")) {
+ String propertyName = fixPropertyName(methodName.substring(2));
+ lowerCasePropertyNameMap.put(propertyName.toLowerCase(), propertyName);
+ }
+ }
+ if (method.getParameterTypes().length == 1 &&
+ method.getReturnType() == Void.TYPE &&
+ methodName.length() > 3 &&
+ methodName.startsWith("set")) {
+ String propertyName = fixPropertyName(methodName.substring(3));
+ lowerCasePropertyNameMap.put(propertyName.toLowerCase(), propertyName);
+ }
+ }
+ }
+
+ // build a list of constructor args... adjust any incoming names to match the property name as determined by the getters and setters
+ List constructorArgs = new ArrayList();
+ for (Iterator iterator = gbeanData.getGBeanInfo().getConstructor().getAttributeNames().iterator(); iterator.hasNext();) {
+ // for constructor args we only use simple fixPropertyName method
+ String argName = fixPropertyName((String) iterator.next());
+ constructorArgs.add(argName);
+ lowerCasePropertyNameMap.put(argName.toLowerCase(), argName);
+ }
+
+ // determine the types of all properties... these are needed for constructor args
+ Map persistentTypes = new HashMap();
+ for (Iterator iterator = gbeanData.getGBeanInfo().getAttributes().iterator(); iterator.hasNext();) {
+ GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
+ String propertyName = attributeInfo.getName();
+ if (!(attributeInfo instanceof DynamicGAttributeInfo)) {
+ propertyName = fixPropertyName(attributeInfo.getName());
+ if (lowerCasePropertyNameMap.containsKey(propertyName.toLowerCase())) {
+ propertyName = (String) lowerCasePropertyNameMap.get(propertyName.toLowerCase());
+ }
+ }
+ persistentTypes.put(propertyName, attributeInfo.getType());
+ }
+ for (Iterator iterator = gbeanData.getGBeanInfo().getReferences().iterator(); iterator.hasNext();) {
+ GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
+ String propertyName = fixPropertyName(referenceInfo.getName());
+ if (lowerCasePropertyNameMap.containsKey(propertyName.toLowerCase())) {
+ propertyName = (String) lowerCasePropertyNameMap.get(propertyName.toLowerCase());
+ }
+ persistentTypes.put(propertyName, referenceInfo.getProxyType());
+ }
+
+ // determine which properties are dynamic
+ Map dynamicProperties = new HashMap();
+ for (Iterator iterator = gbeanData.getGBeanInfo().getAttributes().iterator(); iterator.hasNext();) {
+ GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
+ if (attributeInfo instanceof DynamicGAttributeInfo) {
+ dynamicProperties.put(attributeInfo.getName(), null);
+ }
+ }
+
+ // values from the properties
+ MutablePropertyValues propertyValues = new MutablePropertyValues();
+ for (Iterator iterator = gbeanData.getGBeanInfo().getAttributes().iterator(); iterator.hasNext();) {
+ GAttributeInfo attributeInfo = (GAttributeInfo) iterator.next();
+ String propertyName = attributeInfo.getName();
+
+ // skip the gbeanEnabled property... it is handled below
+ if (propertyName.equals("gbeanEnabled")) {
+ continue;
+ }
+
+ // fix any non-dynamic property name so that it matches spring's rules
+ if (!dynamicProperties.containsKey(propertyName)) {
+ propertyName = fixPropertyName(propertyName);
+ if (lowerCasePropertyNameMap.containsKey(propertyName.toLowerCase())) {
+ propertyName = (String) lowerCasePropertyNameMap.get(propertyName.toLowerCase());
+ }
+ }
+
+// String propertyType = (String) persistentTypes.get(propertyName);
+ Object propertyValue = gbeanData.getAttribute(attributeInfo.getName());
+
+ // magic attributes
+// if (attributeInfo.isWritable() || constructorArgs.contains(propertyName)) {
+// if (propertyName.equals("objectName") && propertyType.equals(String.class.getName())) {
+// propertyValue = new ObjectNameStringReference();
+// } else if (propertyName.equals("objectName") && propertyType.equals(ObjectName.class.getName())) {
+// propertyValue = new ObjectNameReference();
+// } else if (propertyName.equals("classLoader") && propertyType.equals(ClassLoader.class.getName())) {
+// propertyValue = new ClassLoaderReference();
+// } else if (propertyName.equals("gbeanLifecycleController") && propertyType.equals(GBeanLifecycleController.class.getName())) {
+// propertyValue = new GeronimoLifecycleControllerReference();
+// } else if (propertyName.equals("kernel") && propertyType.equals(Kernel.class.getName())) {
+// propertyValue = new GeronimoKernelReference();
+// }
+// }
+
+ // set the property... we only set properties that have a defined value
+ if (propertyValue != null || gbeanData.getAttributes().containsKey(attributeInfo.getName())) {
+ if (dynamicProperties.containsKey(propertyName)) {
+ dynamicProperties.put(propertyName, propertyValue);
+ } else {
+ propertyValues.addPropertyValue(propertyName, propertyValue);
+ }
+ }
+ }
+
+ // values from the references
+ //
+ // NOTE: we need to add the reference values after the attribue values so that newly added
+ // reference patterns will overwrite references stored in properties in a previous run
+ for (Iterator iterator = gbeanData.getGBeanInfo().getReferences().iterator(); iterator.hasNext();) {
+ GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
+ String propertyName = referenceInfo.getName();
+
+ // get the patterns before we mess with the proptery name
+ Set patterns = gbeanData.getReferencePatterns(propertyName);
+
+ // fix any non-dynamic property name so that it matches spring's rules
+ if (!dynamicProperties.containsKey(propertyName)) {
+ propertyName = fixPropertyName(propertyName);
+ if (lowerCasePropertyNameMap.containsKey(propertyName.toLowerCase())) {
+ propertyName = (String) lowerCasePropertyNameMap.get(propertyName.toLowerCase());
+ }
+ }
+
+ // get the patterns
+ if (patterns != null && !patterns.isEmpty()) {
+ // Remove all nulls from the patterns... there is bad code out there
+ patterns = new HashSet(patterns);
+ for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
+ Object pattern = patternIterator.next();
+ if (pattern == null) {
+ patternIterator.remove();
+ }
+ }
+ }
+
+ // set the property... we only set properties that have a defined value
+ if (patterns != null && !patterns.isEmpty()) {
+ Object propertyValue;
+ if (referenceInfo.getProxyType().equals(Collection.class.getName())) {
+ propertyValue = new CollectionReference(propertyName, patterns, referenceInfo.getReferenceType());
+ } else {
+ propertyValue = new SingletonReference(propertyName, patterns, referenceInfo.getReferenceType());
+ }
+ if (dynamicProperties.containsKey(propertyName)) {
+ dynamicProperties.put(propertyName, propertyValue);
+ } else {
+ propertyValues.addPropertyValue(propertyName, propertyValue);
+ }
+ }
+ }
+
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass, propertyValues);
+ GeronimoServiceFactory geronimoServiceFactory = new GeronimoServiceFactory(beanDefinition, dynamicProperties, metadataManager, proxyManager);
+
+ boolean enabled = true;
+ if (gbeanData.getAttributes().containsKey("gbeanEnabled")) {
+ enabled = ((Boolean) gbeanData.getAttribute("gbeanEnabled")).booleanValue();
+ }
+ geronimoServiceFactory.setEnabled(enabled);
+
+ return geronimoServiceFactory;
+ }
+
+ private static String fixPropertyName(String propertyName) {
+ if (Character.isUpperCase(propertyName.charAt(0))) {
+ return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
+ }
+ return propertyName;
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/KernelBridge.java b/kernel/src/java/org/gbean/geronimo/KernelBridge.java
new file mode 100644
index 0000000..811dc0c
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/KernelBridge.java
@@ -0,0 +1,467 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.NoSuchAttributeException;
+import org.gbean.kernel.NoSuchOperationException;
+import org.gbean.kernel.ServiceAlreadyExistsException;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.runtime.ServiceState;
+import org.gbean.kernel.simple.SimpleKernel;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.proxy.ProxyManager;
+import org.gbean.reflect.PropertyInvoker;
+import org.gbean.reflect.ServiceInvoker;
+import org.gbean.reflect.ServiceInvokerManager;
+import org.gbean.service.ConfigurableServiceFactory;
+import org.gbean.service.ServiceFactory;
+
+
+/**
+ * @version $Rev: 154947 $ $Date: 2005-02-22 20:10:45 -0800 (Tue, 22 Feb 2005) $
+ */
+public class KernelBridge implements org.apache.geronimo.kernel.Kernel {
+ /**
+ * Helper objects for invoke and getAttribute
+ */
+ private static final Object[] NO_ARGS = new Object[0];
+ private static final String[] NO_TYPES = new String[0];
+
+ private final SimpleKernel kernel;
+ private final DependencyManagerBridge dependencyManagerBridge;
+ private final MetadataManager metadataManager;
+ private final ServiceInvokerManager serviceInvokerManager;
+ private final ProxyManager proxyManager;
+ private final ProxyManagerBridge proxyManagerBridge;
+ private final LifecycleMonitorBridge lifecycleMonitorBridge;
+
+ public KernelBridge(SimpleKernel kernel, MetadataManager metadataManager, ServiceInvokerManager serviceInvokerManager, ProxyManager proxyManager) {
+ this.kernel = kernel;
+ this.dependencyManagerBridge = new DependencyManagerBridge(kernel.getDependencyManager());
+ this.metadataManager = metadataManager;
+ this.serviceInvokerManager = serviceInvokerManager;
+ this.proxyManager = proxyManager;
+ this.lifecycleMonitorBridge = new LifecycleMonitorBridge(kernel);
+ this.proxyManagerBridge = new ProxyManagerBridge(proxyManager);
+ System.setProperty("geronimo.base.dir", System.getProperty("gbean.base.dir"));
+ }
+
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ public String getKernelName() {
+ return kernel.getKernelName();
+ }
+
+ public org.apache.geronimo.kernel.DependencyManager getDependencyManager() {
+ return dependencyManagerBridge;
+ }
+
+ public org.apache.geronimo.kernel.lifecycle.LifecycleMonitor getLifecycleMonitor() {
+ return lifecycleMonitorBridge;
+ }
+
+ public org.apache.geronimo.kernel.proxy.ProxyManager getProxyManager() {
+ return proxyManagerBridge;
+ }
+
+ public Object getAttribute(ObjectName objectName, String attributeName)
+ throws org.apache.geronimo.kernel.GBeanNotFoundException,
+ org.apache.geronimo.kernel.NoSuchAttributeException,
+ Exception {
+
+ boolean running = isRunning(objectName);
+ if (running) {
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ try {
+ Object value = serviceInvoker.getAttribute(attributeName);
+ return value;
+ } catch (NoSuchAttributeException e) {
+ throw new org.apache.geronimo.kernel.NoSuchAttributeException(e);
+ }
+ } else {
+ ServiceFactory serviceFactory = getServiceFactory(objectName);
+ if (!(serviceFactory instanceof ConfigurableServiceFactory)) {
+ throw new NoSuchAttributeException("Service is stopped and the service factory not configurable: objectName=" + objectName + ", propertyName=" + attributeName);
+ }
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ return configurableServiceFactory.getProperty(attributeName);
+ }
+ }
+
+ public void setAttribute(ObjectName objectName, String attributeName, Object attributeValue)
+ throws org.apache.geronimo.kernel.GBeanNotFoundException,
+ org.apache.geronimo.kernel.NoSuchAttributeException,
+ Exception {
+
+ boolean running = isRunning(objectName);
+ if (running) {
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ try {
+ serviceInvoker.setAttribute(attributeName, attributeValue);
+ } catch (NoSuchAttributeException e) {
+ throw new org.apache.geronimo.kernel.NoSuchAttributeException(e);
+ }
+ } else {
+ ServiceFactory serviceFactory = getServiceFactory(objectName);
+ if (!(serviceFactory instanceof ConfigurableServiceFactory)) {
+ throw new NoSuchAttributeException("Service is stopped and the service factory not configurable: objectName=" + objectName + ", propertyName=" + attributeName);
+ }
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ configurableServiceFactory.setProperty(attributeName, attributeValue);
+ }
+ }
+
+ public Object invoke(ObjectName objectName, String methodName)
+ throws org.apache.geronimo.kernel.GBeanNotFoundException,
+ org.apache.geronimo.kernel.NoSuchOperationException,
+ Exception {
+
+ boolean running = isRunning(objectName);
+ if (!running) {
+ throw new IllegalStateException("Service is not running: name=" + objectName);
+ }
+
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ try {
+ Object value = serviceInvoker.invoke(methodName, NO_ARGS, NO_TYPES);
+ return value;
+ } catch (NoSuchOperationException e) {
+ throw new org.apache.geronimo.kernel.NoSuchOperationException(e);
+ }
+ }
+
+ public Object invoke(ObjectName objectName, String methodName, Object[] args, String[] types) throws org.apache.geronimo.kernel.GBeanNotFoundException,
+ org.apache.geronimo.kernel.NoSuchOperationException,
+ Exception {
+
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ try {
+ Object value = serviceInvoker.invoke(methodName, args, types);
+ return value;
+ } catch (NoSuchOperationException e) {
+ throw new org.apache.geronimo.kernel.NoSuchOperationException(e);
+ }
+ }
+
+ public boolean isLoaded(ObjectName name) {
+ return kernel.isLoaded(name);
+ }
+
+ public org.apache.geronimo.gbean.GBeanInfo getGBeanInfo(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ ServiceFactory serviceFactory = getServiceFactory(name);
+ if (serviceFactory instanceof GeronimoServiceFactory) {
+ GeronimoServiceFactory geronimoServiceFactory = (GeronimoServiceFactory) serviceFactory;
+ return GeronimoUtil.createGBeanInfo(geronimoServiceFactory);
+ }
+
+ return createGBeanInfo(name);
+ }
+
+ public org.apache.geronimo.gbean.GBeanData getGBeanData(ObjectName objectName) throws org.apache.geronimo.kernel.GBeanNotFoundException{
+ ServiceFactory serviceFactory = getServiceFactory(objectName);
+ if (serviceFactory instanceof GeronimoServiceFactory) {
+ GeronimoServiceFactory geronimoServiceFactory = null;
+ geronimoServiceFactory = (GeronimoServiceFactory) serviceFactory;
+ return GeronimoUtil.createGBeanData(objectName, geronimoServiceFactory);
+ }
+
+ return createGBeanData(objectName);
+ }
+
+ public void loadGBean(org.apache.geronimo.gbean.GBeanData gbeanData, ClassLoader classLoader) throws org.apache.geronimo.kernel.GBeanAlreadyExistsException {
+ ObjectName objectName = gbeanData.getName();
+
+ GeronimoServiceFactory geronimoServiceFactory = null;
+ try {
+ geronimoServiceFactory =GeronimoUtil.createGeronimoServiceFactory(gbeanData, classLoader, metadataManager, proxyManager);
+ } catch (Exception e) {
+ throw new org.apache.geronimo.kernel.InternalKernelException(e);
+ }
+ try {
+ kernel.loadService(objectName, geronimoServiceFactory, classLoader);
+ } catch (ServiceAlreadyExistsException e) {
+ throw new org.apache.geronimo.kernel.GBeanAlreadyExistsException(e);
+ }
+ }
+
+ public void startGBean(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException, IllegalStateException {
+ try {
+ kernel.startService(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public void startRecursiveGBean(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException, IllegalStateException {
+ try {
+ kernel.startRecursiveService(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public void stopGBean(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException, IllegalStateException {
+ try {
+ kernel.stopService(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public void unloadGBean(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException, IllegalStateException {
+ try {
+ kernel.unloadService(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public int getGBeanState(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return kernel.getServiceState(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public long getGBeanStartTime(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return kernel.getServiceStartTime(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public boolean isGBeanEnabled(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return kernel.isServiceEnabled(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public void setGBeanEnabled(ObjectName name, boolean enabled) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ kernel.setServiceEnabled(name, enabled);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ public Set listGBeans(ObjectName pattern) {
+ return kernel.listServiceNames(pattern);
+ }
+
+ public Set listGBeans(Set patterns) {
+ return kernel.listServiceNames(patterns);
+ }
+
+ public void boot() throws Exception {
+ org.apache.geronimo.kernel.KernelRegistry.registerKernel(this);
+ kernel.registerShutdownHook(new Runnable() {
+ public void run() {
+ synchronized (KernelBridge.this) {
+ KernelBridge.this.notify();
+ }
+ org.apache.geronimo.kernel.KernelRegistry.unregisterKernel(KernelBridge.this);
+ }
+ });
+ }
+
+ public Date getBootTime() {
+ return kernel.getBootTime();
+ }
+
+ public void registerShutdownHook(Runnable hook) {
+ kernel.registerShutdownHook(hook);
+ }
+
+ public void unregisterShutdownHook(Runnable hook) {
+ kernel.unregisterShutdownHook(hook);
+ }
+
+ public void shutdown() {
+ kernel.shutdown();
+ }
+
+ public boolean isRunning() {
+ return kernel.isRunning();
+ }
+
+ public ClassLoader getClassLoaderFor(ObjectName name) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return kernel.getClassLoaderFor(name);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ private ServiceInvoker getServiceInvoker(ObjectName objectName) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return serviceInvokerManager.getServiceInvoker(objectName);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+
+ private ServiceFactory getServiceFactory(ObjectName objectName) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ try {
+ return kernel.getServiceFactory(objectName);
+ } catch (ServiceNotFoundException e) {
+ throw new org.apache.geronimo.kernel.GBeanNotFoundException(e);
+ }
+ }
+ private boolean isRunning(ObjectName objectName) {
+ try {
+ int serviceState = kernel.getServiceState(objectName);
+ boolean running = serviceState == ServiceState.RUNNING_INDEX || serviceState == ServiceState.STOPPING_INDEX;
+ return running;
+ } catch (ServiceNotFoundException e) {
+ return false;
+ }
+ }
+
+ private org.apache.geronimo.gbean.GBeanInfo createGBeanInfo(ObjectName objectName) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ boolean running = isRunning(objectName);
+ if (running) {
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ return createGBeanInfo(serviceInvoker);
+ } else {
+ ServiceFactory serviceFactory = getServiceFactory(objectName);
+ return createGBeanInfo(serviceFactory);
+ }
+
+ }
+
+ private org.apache.geronimo.gbean.GBeanInfo createGBeanInfo(ServiceInvoker serviceInvoker) {
+ Set attributeInfos = new HashSet();
+ List propertyIndex = serviceInvoker.getPropertyIndex();
+ for (Iterator iterator = propertyIndex.iterator(); iterator.hasNext();) {
+ PropertyInvoker propertyInvoker = (PropertyInvoker) iterator.next();
+ String getterName = null;
+ if (propertyInvoker.isReadable()) {
+ getterName = propertyInvoker.getGetterSignature().getName();
+ }
+ String setterName = null;
+ if (propertyInvoker.isWritable()) {
+ setterName = propertyInvoker.getSetterSignature().getName();
+ }
+ attributeInfos.add(new org.apache.geronimo.gbean.GAttributeInfo(propertyInvoker.getPropertyName(),
+ propertyInvoker.getType().getName(),
+ false,
+ getterName,
+ setterName));
+ }
+ return new org.apache.geronimo.gbean.GBeanInfo(serviceInvoker.getServiceType().getName(),
+ "GBean",
+ attributeInfos,
+ new org.apache.geronimo.gbean.GConstructorInfo(new String[] {}),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ }
+
+ private org.apache.geronimo.gbean.GBeanInfo createGBeanInfo(ServiceFactory serviceFactory) {
+ String serviceType;
+ Set attributeInfos = new HashSet();
+ serviceType = Object.class.getName();
+ if (serviceFactory instanceof ConfigurableServiceFactory) {
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ Set propertyNames = configurableServiceFactory.getPropertyNames();
+ for (Iterator iterator = propertyNames.iterator(); iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+ String ucase = Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
+ String getterName = "get" + ucase;
+ String setterName = "set" + ucase;
+ attributeInfos.add(new org.apache.geronimo.gbean.GAttributeInfo(propertyName,
+ Object.class.getName(),
+ false,
+ getterName,
+ setterName));
+ }
+ }
+ return new org.apache.geronimo.gbean.GBeanInfo(serviceType,
+ "GBean",
+ attributeInfos,
+ new org.apache.geronimo.gbean.GConstructorInfo(new String[] {}),
+ Collections.EMPTY_SET,
+ Collections.EMPTY_SET);
+ }
+
+ private org.apache.geronimo.gbean.GBeanData createGBeanData(ObjectName objectName) throws org.apache.geronimo.kernel.GBeanNotFoundException {
+ boolean running = isRunning(objectName);
+ if (running) {
+ ServiceInvoker serviceInvoker = getServiceInvoker(objectName);
+ return createGBeanData(serviceInvoker);
+ } else {
+ ServiceFactory serviceFactory = getServiceFactory(objectName);
+ return createGBeanData(objectName, serviceFactory);
+ }
+
+ }
+
+ private org.apache.geronimo.gbean.GBeanData createGBeanData(ServiceInvoker serviceInvoker) {
+ org.apache.geronimo.gbean.GBeanInfo gbeanInfo = createGBeanInfo(serviceInvoker);
+ org.apache.geronimo.gbean.GBeanData gbeanData = new org.apache.geronimo.gbean.GBeanData(serviceInvoker.getServiceName(), gbeanInfo);
+ for (Iterator iterator = gbeanInfo.getAttributes().iterator(); iterator.hasNext();) {
+ org.apache.geronimo.gbean.GAttributeInfo attribute = (org.apache.geronimo.gbean.GAttributeInfo) iterator.next();
+ if (attribute.isReadable()) {
+ try {
+ String attributeName = attribute.getName();
+ Object attributeValue = serviceInvoker.getAttribute(attributeName);
+ gbeanData.setAttribute(attributeName, attributeValue);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+ return gbeanData;
+ }
+
+ private org.apache.geronimo.gbean.GBeanData createGBeanData(ObjectName objectName, ServiceFactory serviceFactory) {
+ org.apache.geronimo.gbean.GBeanInfo gbeanInfo = createGBeanInfo(serviceFactory);
+ org.apache.geronimo.gbean.GBeanData gbeanData = new org.apache.geronimo.gbean.GBeanData(objectName, gbeanInfo);
+ if (serviceFactory instanceof ConfigurableServiceFactory) {
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ for (Iterator iterator = gbeanInfo.getAttributes().iterator(); iterator.hasNext();) {
+ org.apache.geronimo.gbean.GAttributeInfo attribute = (org.apache.geronimo.gbean.GAttributeInfo) iterator.next();
+ if (attribute.isReadable()) {
+ try {
+ String attributeName = attribute.getName();
+ Object attributeValue = configurableServiceFactory.getProperty(attributeName);
+ gbeanData.setAttribute(attributeName, attributeValue);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+ }
+ return gbeanData;
+ }
+}
+
diff --git a/kernel/src/java/org/gbean/geronimo/KernelBridgeFactory.java b/kernel/src/java/org/gbean/geronimo/KernelBridgeFactory.java
new file mode 100644
index 0000000..8ee8758
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/KernelBridgeFactory.java
@@ -0,0 +1,27 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class KernelBridgeFactory extends org.apache.geronimo.kernel.KernelFactory {
+ public org.apache.geronimo.kernel.Kernel createKernel(String kernelName) {
+// return new KernelBridge(kernelName);
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/LifecycleMonitorBridge.java b/kernel/src/java/org/gbean/geronimo/LifecycleMonitorBridge.java
new file mode 100644
index 0000000..8fed6b4
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/LifecycleMonitorBridge.java
@@ -0,0 +1,98 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.HashMap;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleListener;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class LifecycleMonitorBridge implements org.apache.geronimo.kernel.lifecycle.LifecycleMonitor {
+ private final Kernel kernel;
+ private final Map listenerBridgeMap = new HashMap();
+
+ public LifecycleMonitorBridge(Kernel kernel) {
+ this.kernel = kernel;
+ }
+
+ public void addLifecycleListener(org.apache.geronimo.kernel.lifecycle.LifecycleListener listener, ObjectName pattern) {
+ LifecycleListenerBridge listenerBridge = getListenerBridge(listener);
+ kernel.addLifecycleListener(listenerBridge, pattern);
+ }
+
+ public void addLifecycleListener(org.apache.geronimo.kernel.lifecycle.LifecycleListener listener, Set patterns) {
+ LifecycleListenerBridge listenerBridge = getListenerBridge(listener);
+ kernel.addLifecycleListener(listenerBridge, patterns);
+ }
+
+ public void removeLifecycleListener(org.apache.geronimo.kernel.lifecycle.LifecycleListener listener) {
+ LifecycleListenerBridge listenerBridge = getListenerBridge(listener);
+ if (listenerBridge != null) {
+ kernel.removeLifecycleListener(listenerBridge);
+ }
+ }
+
+ private LifecycleListenerBridge getListenerBridge(org.apache.geronimo.kernel.lifecycle.LifecycleListener listener) {
+ synchronized (listenerBridgeMap) {
+ LifecycleListenerBridge listenerBridge = (LifecycleListenerBridge) listenerBridgeMap.get(listener);
+ if (listenerBridge == null) {
+ listenerBridge = new LifecycleListenerBridge(listener);
+ listenerBridgeMap.put(listener, listenerBridge);
+ }
+ return listenerBridge;
+ }
+ }
+
+
+ private static class LifecycleListenerBridge implements LifecycleListener {
+ private final org.apache.geronimo.kernel.lifecycle.LifecycleListener lifecycleListener;
+
+ public LifecycleListenerBridge(org.apache.geronimo.kernel.lifecycle.LifecycleListener lifecycleListener) {
+ this.lifecycleListener = lifecycleListener;
+ }
+
+ public void loaded(ObjectName objectName) {
+ lifecycleListener.loaded(objectName);
+ }
+
+ public void starting(ObjectName objectName) {
+ lifecycleListener.starting(objectName);
+ }
+
+ public void running(ObjectName objectName) {
+ lifecycleListener.running(objectName);
+ }
+
+ public void stopping(ObjectName objectName) {
+ lifecycleListener.stopping(objectName);
+ }
+
+ public void stopped(ObjectName objectName) {
+ lifecycleListener.stopped(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ lifecycleListener.unloaded(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/LoaderBridge.java b/kernel/src/java/org/gbean/geronimo/LoaderBridge.java
new file mode 100644
index 0000000..38fad10
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/LoaderBridge.java
@@ -0,0 +1,43 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.net.URI;
+import javax.management.ObjectName;
+
+import org.apache.geronimo.kernel.config.ConfigurationStore;
+import org.gbean.loader.Loader;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LoaderBridge implements Loader {
+ private final ConfigurationStore configurationStore;
+
+ public LoaderBridge(ConfigurationStore configurationStore) {
+ this.configurationStore = configurationStore;
+ }
+
+ public ObjectName load(String location) {
+ URI configurationUri = URI.create(location);
+ try {
+ return configurationStore.loadConfiguration(configurationUri);
+ } catch (Exception e) {
+ throw new RuntimeException("Error loading configuration: " + configurationUri, e);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/ProxyManagerBridge.java b/kernel/src/java/org/gbean/geronimo/ProxyManagerBridge.java
new file mode 100644
index 0000000..26aa8af
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/ProxyManagerBridge.java
@@ -0,0 +1,73 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import javax.management.ObjectName;
+
+import org.gbean.proxy.ProxyManager;
+import org.gbean.proxy.ProxyFactory;
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ProxyManagerBridge implements org.apache.geronimo.kernel.proxy.ProxyManager {
+ private final ProxyManager proxyManager;
+
+ public ProxyManagerBridge(ProxyManager proxyManager) {
+ this.proxyManager = proxyManager;
+ }
+
+ public org.apache.geronimo.kernel.proxy.ProxyFactory createProxyFactory(Class type) {
+ return new ProxyFactoryBridge(proxyManager.createProxyFactory(type));
+ }
+
+ public Object createProxy(ObjectName target, Class type) {
+ try {
+ return proxyManager.createProxy(target, type);
+ } catch (ServiceNotFoundException e) {
+ throw (IllegalStateException) new IllegalStateException("Service was not loaded: " + target).initCause(e);
+ }
+ }
+
+ public synchronized void destroyProxy(Object proxy) {
+ }
+
+ public boolean isProxy(Object proxy) {
+ return proxyManager.isProxy(proxy);
+ }
+
+ public synchronized ObjectName getProxyTarget(Object proxy) {
+ return proxyManager.getProxyTarget(proxy);
+ }
+
+ private class ProxyFactoryBridge implements org.apache.geronimo.kernel.proxy.ProxyFactory {
+ private final ProxyFactory proxyFactory;
+
+ public ProxyFactoryBridge(ProxyFactory proxyFactory) {
+ this.proxyFactory = proxyFactory;
+ }
+
+ public Object createProxy(ObjectName target) {
+ try {
+ return proxyFactory.createProxy(target);
+ } catch (ServiceNotFoundException e) {
+ throw (IllegalStateException) new IllegalStateException("Service was not loaded: " + target).initCause(e);
+ }
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/ProxyReferenceCollection.java b/kernel/src/java/org/gbean/geronimo/ProxyReferenceCollection.java
new file mode 100644
index 0000000..711141f
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/ProxyReferenceCollection.java
@@ -0,0 +1,285 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.KernelUtil;
+import org.gbean.proxy.ProxyFactory;
+import org.gbean.proxy.ProxyManager;
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ProxyReferenceCollection implements org.apache.geronimo.gbean.ReferenceCollection, FactoryBeanProvider {
+ private static final Log log = LogFactory.getLog(ProxyReferenceCollection.class);
+ private final FactoryBean factoryBean;
+ private final String name;
+ private final ProxyFactory factory;
+ private final Map proxies = new HashMap();
+ private final Set listeners = new HashSet();
+ private boolean stopped = false;
+ private LifecycleListener listener;
+ private final Kernel kernel;
+
+ public ProxyReferenceCollection(FactoryBean factoryBean, String name, Class type, Kernel kernel, Set patterns) {
+ this.factoryBean = factoryBean;
+ this.name = name;
+ this.kernel = kernel;
+ try {
+ factory = ProxyManager.findProxyManager(kernel).createProxyFactory(type);
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("No ProxyManager available in kernel");
+ }
+
+ Set targets = KernelUtil.getRunningServiceNames(kernel, patterns);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ addTarget((ObjectName) iterator.next());
+ }
+
+ listener = new CollectionReferenceLifecycleListener();
+ kernel.addLifecycleListener(listener, patterns);
+ }
+
+ public FactoryBean getFactoryBean() {
+ return factoryBean;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public synchronized void destroy() {
+ stopped = true;
+ proxies.clear();
+ listeners.clear();
+
+ if (listener != null) {
+ kernel.removeLifecycleListener(listener);
+ listener = null;
+ }
+ }
+
+ private void addTarget(ObjectName target) {
+ Object proxy = null;
+ ArrayList listenerCopy;
+ synchronized (this) {
+ // if this is not a new target return
+ if (proxies.containsKey(target)) {
+ return;
+ }
+
+ // create and add the proxy
+ try {
+ proxy = factory.createProxy(target);
+ } catch (ServiceNotFoundException e) {
+ // service was removed before we could add it
+ }
+ proxies.put(target, proxy);
+
+ // make a snapshot of the listeners
+ listenerCopy = new ArrayList(listeners);
+ }
+
+ // fire the member added event
+ for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+ org.apache.geronimo.gbean.ReferenceCollectionListener listener = (org.apache.geronimo.gbean.ReferenceCollectionListener) iterator.next();
+ try {
+ listener.memberAdded(new org.apache.geronimo.gbean.ReferenceCollectionEvent(name, proxy));
+ } catch (Throwable t) {
+ log.error("Listener threw exception", t);
+ }
+ }
+ }
+
+ private void removeTarget(ObjectName target) {
+ Object proxy;
+ ArrayList listenerCopy;
+ synchronized (this) {
+ // remove the proxy
+ proxy = proxies.remove(target);
+
+ // if this was not a target return
+ if (proxy == null) {
+ return;
+ }
+
+ // make a snapshot of the listeners
+ listenerCopy = new ArrayList(listeners);
+ }
+
+ // fire the member removed event
+ for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+ org.apache.geronimo.gbean.ReferenceCollectionListener listener = (org.apache.geronimo.gbean.ReferenceCollectionListener) iterator.next();
+ try {
+ listener.memberRemoved(new org.apache.geronimo.gbean.ReferenceCollectionEvent(name, proxy));
+ } catch (Throwable t) {
+ log.error("Listener threw exception", t);
+ }
+ }
+ }
+
+ public synchronized boolean isStopped() {
+ return stopped;
+ }
+
+ public synchronized void addReferenceCollectionListener(org.apache.geronimo.gbean.ReferenceCollectionListener listener) {
+ listeners.add(listener);
+ }
+
+ public synchronized void removeReferenceCollectionListener(org.apache.geronimo.gbean.ReferenceCollectionListener listener) {
+ listeners.remove(listener);
+ }
+
+ public synchronized int size() {
+ if (stopped) {
+ return 0;
+ }
+ return proxies.size();
+ }
+
+ public synchronized boolean isEmpty() {
+ if (stopped) {
+ return true;
+ }
+ return proxies.isEmpty();
+ }
+
+ public synchronized boolean contains(Object o) {
+ if (stopped) {
+ return false;
+ }
+ return proxies.containsValue(o);
+ }
+
+ public synchronized Iterator iterator() {
+ if (stopped) {
+ return new Iterator() {
+ public boolean hasNext() {
+ return false;
+ }
+
+ public Object next() {
+ throw new NoSuchElementException();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ return new Iterator() {
+ // copy the proxies, so the client can iterate without concurrent modification
+ // this is necssary since the client has nothing to synchronize on
+ private final Iterator iterator = new ArrayList(proxies.values()).iterator();
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public Object next() {
+ return iterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public synchronized Object[] toArray() {
+ if (stopped) {
+ return new Object[0];
+ }
+ return proxies.values().toArray();
+ }
+
+ public synchronized Object[] toArray(Object a[]) {
+ if (stopped) {
+ if (a.length > 0) {
+ a[0] = null;
+ }
+ return a;
+ }
+ return proxies.values().toArray(a);
+ }
+
+ public synchronized boolean containsAll(Collection c) {
+ if (stopped) {
+ return c.isEmpty();
+ }
+ return proxies.values().containsAll(c);
+ }
+
+ public boolean add(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean addAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean removeAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean retainAll(Collection c) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ private class CollectionReferenceLifecycleListener extends LifecycleAdapter {
+ public void running(ObjectName objectName) {
+ addTarget(objectName);
+ }
+
+ public void stopping(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+
+ public void stopped(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ removeTarget(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/geronimo/SingletonReference.java b/kernel/src/java/org/gbean/geronimo/SingletonReference.java
new file mode 100644
index 0000000..327ac9b
--- /dev/null
+++ b/kernel/src/java/org/gbean/geronimo/SingletonReference.java
@@ -0,0 +1,189 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.geronimo;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.ClassLoading;
+import org.gbean.kernel.KernelUtil;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.proxy.ProxyManager;
+import org.gbean.service.ServiceContext;
+import org.gbean.spring.DependencyProvider;
+import org.gbean.spring.ServiceContextThreadLocal;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class SingletonReference implements FactoryBean, DependencyProvider, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition(String name, Set patterns, String referenceType) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(SingletonReference.class, 0);
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ propertyValues.addPropertyValue("name", name);
+ propertyValues.addPropertyValue("patterns", patterns);
+ propertyValues.addPropertyValue("referenceType", referenceType);
+ return new BeanDefinitionHolder(beanDefinition, SingletonReference.class.getName());
+ }
+
+ public static Map getDependencies(RootBeanDefinition beanDefinition) {
+ if (!beanDefinition.getBeanClass().equals(SingletonReference.class)) {
+ throw new IllegalArgumentException("Bean definition is for another bean type:" +
+ " expected=" + SingletonReference.class.getName() +
+ " actual=" + beanDefinition.getBeanClass().getName());
+ }
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ if (!propertyValues.contains("name")) {
+ throw new IllegalArgumentException("Bean definition does not contain a name property");
+ }
+ String name = (String) propertyValues.getPropertyValue("name").getValue();
+ if (!propertyValues.contains("patterns")) {
+ throw new IllegalArgumentException("Bean definition does not contain a patterns property: name=" + name);
+ }
+ Set patterns = (Set) propertyValues.getPropertyValue("patterns").getValue();
+ return Collections.singletonMap(name, patterns);
+ }
+
+ /**
+ * Name of this reference.
+ */
+ private String name;
+
+ /**
+ * Proxy type which is injected into the service.
+ */
+ private String referenceType;
+
+ /**
+ * The target objectName patterns to watch for a connection.
+ */
+ private Set patterns;
+
+ /**
+ * Proxy type which is injected into the service.
+ */
+ private transient Class objectType;
+
+ public SingletonReference() {
+ }
+
+ public SingletonReference(String name, Set patterns, String referenceType) {
+ this.name = name;
+ this.patterns = patterns;
+ this.referenceType = referenceType;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getReferenceType() {
+ return referenceType;
+ }
+
+ public void setReferenceType(String referenceType) {
+ this.referenceType = referenceType;
+ }
+
+ public Set getPatterns() {
+ return patterns;
+ }
+
+ public void setPatterns(Set patterns) {
+ this.patterns = patterns;
+ }
+
+ public Map getDependencies() {
+ return Collections.singletonMap(name, patterns);
+ }
+
+ public final Class getObjectType() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ synchronized (this) {
+ if (objectType == null) {
+ try {
+ objectType = ClassLoading.loadClass(referenceType, serviceContext.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Could not load singleton reference object type");
+ }
+ }
+ }
+ return objectType;
+ }
+
+ public synchronized final Object getObject() throws ClassNotFoundException {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ synchronized (this) {
+ if (objectType == null) {
+ objectType = ClassLoading.loadClass(referenceType, serviceContext.getClassLoader());
+ }
+ }
+
+ Set targets = KernelUtil.getRunningServiceNames(serviceContext.getKernel(), patterns);
+ if (targets.size() != 1) {
+ throw new IllegalStateException("Invalid reference: name=" + name + ", targetCount=" + targets.size() + ", patterns=" + getPatternsText());
+ }
+
+ // add a dependency on our target and create the proxy
+ ObjectName target = (ObjectName) targets.iterator().next();
+ ProxyManager proxyManager = null;
+ try {
+ proxyManager = ProxyManager.findProxyManager(serviceContext.getKernel());
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("ProxyManger has not been loaded");
+
+ }
+
+ try {
+ return proxyManager.createProxy(target, objectType, this);
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("Referenced object was unregistered before a proxy could be created: name=" + name + ", targetCount=" + targets.size() + ", patterns=" + getPatternsText());
+ }
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ private String getPatternsText() {
+ StringBuffer buf = new StringBuffer();
+ for (Iterator iterator = patterns.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ buf.append(objectName.getCanonicalName()).append(" ");
+ }
+ return buf.toString();
+ }
+}
diff --git a/kernel/src/java/org/gbean/jmx/JMXBridge.java b/kernel/src/java/org/gbean/jmx/JMXBridge.java
new file mode 100644
index 0000000..3e6e71d
--- /dev/null
+++ b/kernel/src/java/org/gbean/jmx/JMXBridge.java
@@ -0,0 +1,180 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.jmx;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.JMException;
+import javax.management.JMRuntimeException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.ServiceName;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.simple.SimpleLifecycle;
+import org.gbean.reflect.ServiceInvokerManager;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class JMXBridge implements SimpleLifecycle {
+ private static final ObjectName ALL = ServiceName.createName("*:*");
+ private static final Log log = LogFactory.getLog(JMXBridge.class);
+
+ private final HashMap registry = new HashMap();
+ private final Kernel kernel;
+ private final ServiceInvokerManager serviceInvokerManager;
+ private final MBeanServer mbeanServer;
+
+ public JMXBridge(Kernel kernel, ServiceInvokerManager serviceInvokerManager) {
+ this.kernel = kernel;
+ this.serviceInvokerManager = serviceInvokerManager;
+ mbeanServer = MBeanServerFactory.createMBeanServer(kernel.getKernelName());
+ }
+
+ public JMXBridge(Kernel kernel, ServiceInvokerManager serviceInvokerManager, String mbeanServerId) {
+ this.kernel = kernel;
+ this.serviceInvokerManager = serviceInvokerManager;
+ ArrayList servers = MBeanServerFactory.findMBeanServer(mbeanServerId);
+ if (servers.size() == 0) {
+ throw new IllegalStateException("No MBeanServers were found with the agent id " + mbeanServerId);
+ } else if (servers.size() > 1) {
+ throw new IllegalStateException(servers.size() + " MBeanServers were found with the agent id " + mbeanServerId);
+ }
+ mbeanServer = (MBeanServer) servers.get(0);
+ }
+
+ public JMXBridge(Kernel kernel, ServiceInvokerManager serviceInvokerManager, MBeanServer mbeanServer) {
+ this.kernel = kernel;
+ this.serviceInvokerManager = serviceInvokerManager;
+ this.mbeanServer = mbeanServer;
+ }
+
+ public void start() {
+ kernel.addLifecycleListener(new ServiceRegistrationListener(), ALL);
+
+ HashMap beans = new HashMap();
+ synchronized (this) {
+ Set allNames = kernel.listServiceNames(ALL);
+ for (Iterator iterator = allNames.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ if (registry.containsKey(objectName)) {
+ // instance already registered
+ continue;
+ }
+ try {
+ ServiceMBean serviceMBean = new ServiceMBean(kernel, serviceInvokerManager, objectName);
+ registry.put(objectName, serviceMBean);
+ beans.put(objectName, serviceMBean);
+ } catch (ServiceNotFoundException e) {
+ // ignore - service died on us
+ }
+ }
+ }
+ for (Iterator iterator = beans.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ ObjectName objectName = (ObjectName) entry.getKey();
+ ServiceMBean serviceMBean = (ServiceMBean) entry.getValue();
+ try {
+ mbeanServer.registerMBean(serviceMBean, objectName);
+ } catch (InstanceAlreadyExistsException e) {
+ // ignore - service already has an mbean shadow object
+ } catch (Exception e) {
+ log.info("Unable to register MBean shadow object for service: " + objectName, unwrapJMException(e));
+ }
+ }
+ }
+
+ public void stop() {
+ // unregister all of our mbeans from the MBeanServer
+ Map beans;
+ synchronized (this) {
+ beans = new HashMap(registry);
+ registry.clear();
+ }
+ for (Iterator i = beans.keySet().iterator(); i.hasNext();) {
+ ObjectName objectName = (ObjectName) i.next();
+ try {
+ mbeanServer.unregisterMBean(objectName);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ private void register(ObjectName objectName) {
+ try {
+ ServiceMBean serviceMBean = null;
+ synchronized (this) {
+ if (registry.containsKey(objectName)) {
+ return;
+ }
+ serviceMBean = new ServiceMBean(kernel, serviceInvokerManager, objectName);
+ registry.put(objectName, serviceMBean);
+ }
+ mbeanServer.registerMBean(serviceMBean, objectName);
+ } catch (InstanceAlreadyExistsException e) {
+ // ignore - service already has a mbean shadow object
+ } catch (Exception e) {
+ log.info("Unable to register MBean shadow object for service", unwrapJMException(e));
+ }
+ }
+
+ private void unregister(ObjectName objectName) {
+ synchronized (this) {
+ if (registry.remove(objectName) == null) {
+ return;
+ }
+ }
+
+ try {
+ mbeanServer.unregisterMBean(objectName);
+ } catch (InstanceNotFoundException e) {
+ // ignore - something else may have unregistered us
+ // if there truely is no service then we will catch it below whwn we call the superclass
+ } catch (Exception e) {
+ log.info("Unable to unregister MBean shadow object for service", unwrapJMException(e));
+ }
+ }
+
+ private Throwable unwrapJMException(Throwable cause) {
+ while ((cause instanceof JMException || cause instanceof JMRuntimeException) && cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+ return cause;
+ }
+
+ private class ServiceRegistrationListener extends LifecycleAdapter {
+ public void loaded(ObjectName objectName) {
+ register(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ unregister(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/jmx/NotificationType.java b/kernel/src/java/org/gbean/jmx/NotificationType.java
new file mode 100644
index 0000000..7d71a74
--- /dev/null
+++ b/kernel/src/java/org/gbean/jmx/NotificationType.java
@@ -0,0 +1,79 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.jmx;
+
+
+/**
+ * Static constants class which contains all of the J2EE notification types from the
+ * J2EE management specification.
+ *
+ * @version $Rev: 109314 $ $Date: 2004-12-01 00:01:37 -0800 (Wed, 01 Dec 2004) $
+ */
+public final class NotificationType {
+ private NotificationType() {
+ }
+
+ /**
+ * A new managed object was created.
+ */
+ public static final String OBJECT_CREATED = "j2ee.object.created";
+
+ /**
+ * A managed object was deleted
+ */
+ public static final String OBJECT_DELETED = "j2ee.object.deleted";
+
+ /**
+ * A state manageable object entered the starting state
+ */
+ public static final String STATE_STARTING = "j2ee.state.starting";
+
+ /**
+ * A state manageable object entered the running state
+ */
+ public static final String STATE_RUNNING = "j2ee.state.running";
+
+ /**
+ * A state manageable object entered the stopping state
+ */
+ public static final String STATE_STOPPING = "j2ee.state.stopping";
+
+ /**
+ * A state manageable object entered the stopped state.
+ */
+ public static final String STATE_STOPPED = "j2ee.state.stopped";
+
+ /**
+ * A state manageable object entered the failed state
+ */
+ public static final String STATE_FAILED = "j2ee.state.failed";
+
+ /**
+ * An attribute has change value
+ */
+ public static final String ATTRIBUTE_CHANGED = "j2ee.attribute.changed";
+
+ /**
+ * An array containg all of the know J2EE notification types
+ */
+ public static final String[] TYPES = new String[]{
+ OBJECT_CREATED, OBJECT_DELETED,
+ STATE_STARTING, STATE_RUNNING, STATE_STOPPING, STATE_STOPPED, STATE_FAILED,
+ ATTRIBUTE_CHANGED
+ };
+}
diff --git a/kernel/src/java/org/gbean/jmx/ServiceMBean.java b/kernel/src/java/org/gbean/jmx/ServiceMBean.java
new file mode 100644
index 0000000..e5c2e70
--- /dev/null
+++ b/kernel/src/java/org/gbean/jmx/ServiceMBean.java
@@ -0,0 +1,456 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.jmx;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.JMException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.NoSuchAttributeException;
+import org.gbean.kernel.NoSuchOperationException;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.runtime.ServiceState;
+import org.gbean.reflect.OperationInvoker;
+import org.gbean.reflect.PropertyInvoker;
+import org.gbean.reflect.ServiceInvoker;
+import org.gbean.reflect.ServiceInvokerManager;
+import org.gbean.service.ConfigurableServiceFactory;
+import org.gbean.service.ServiceFactory;
+
+/**
+ * @version $Rev: 109772 $ $Date: 2004-12-03 21:06:02 -0800 (Fri, 03 Dec 2004) $
+ */
+public final class ServiceMBean implements DynamicMBean, NotificationEmitter {
+ private static final Log log = LogFactory.getLog(ServiceMBean.class);
+
+ private static final String ATTRIBUTE_CLASS_LOADER = "classLoader";
+ private static final String ATTRIBUTE_STATE = "state";
+ private static final String ATTRIBUTE_START_TIME = "startTime";
+ private static final String ATTRIBUTE_STATE_MANAGEABLE = "stateManageable";
+ private static final String ATTRIBUTE_STATISTICS_PROVIDER = "statisticsProvider";
+ private static final String ATTRIBUTE_EVENT_PROVIDER = "eventProvider";
+ private static final String ATTRIBUTE_EVENT_TYPES = "eventTypes";
+ private static final String ATTRIBUTE_GBEAN_ENABLED = "gbeanEnabled";
+
+ private static final String OPERATION_START = "start";
+ private static final String OPERATION_START_RECURSIVE = "startRecursive";
+ private static final String OPERATION_STOP = "stop";
+
+ /**
+ * The kernel
+ */
+ private final Kernel kernel;
+
+ /**
+ * The unique name of this service.
+ */
+ private final ObjectName objectName;
+
+ /**
+ * The broadcaster for notifications
+ */
+ private final NotificationBroadcasterSupport notificationBroadcaster = new NotificationBroadcasterSupport();
+
+ /**
+ * Listenes for kernel lifecycle events for this service and broadcasts them via JMX.
+ */
+ private final LifecycleBridge lifecycleBridge;
+
+ /**
+ * The service invocation manager from which we get the service invoker
+ */
+ private final ServiceInvokerManager serviceInvokerManager;
+
+ /**
+ * The factory for this service
+ */
+ private final ServiceFactory serviceFactory;
+
+ /**
+ * The service invoker
+ */
+ private ServiceInvoker serviceInvoker;
+
+ public ServiceMBean(Kernel kernel, ServiceInvokerManager serviceInvokerManager, ObjectName objectName) throws ServiceNotFoundException {
+ this.kernel = kernel;
+ serviceFactory = kernel.getServiceFactory(objectName);
+ this.serviceInvokerManager = serviceInvokerManager;
+ this.objectName = objectName;
+ lifecycleBridge = new LifecycleBridge(notificationBroadcaster);
+ }
+
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ public ObjectName preRegister(MBeanServer mBeanServer, ObjectName objectName) throws Exception {
+ return objectName;
+ }
+
+ public synchronized void postRegister(Boolean registrationDone) {
+ if (Boolean.TRUE.equals(registrationDone)) {
+ // fire the loaded event from the mbean.. it was already fired from the GBeanInstance when it was created
+ kernel.addLifecycleListener(lifecycleBridge, objectName);
+ lifecycleBridge.loaded(objectName);
+ updateState();
+ }
+ }
+
+ public synchronized void preDeregister() {
+ kernel.removeLifecycleListener(lifecycleBridge);
+ lifecycleBridge.unloaded(objectName);
+ serviceInvoker = null;
+ }
+
+ public void postDeregister() {
+ }
+
+ private synchronized void updateState() {
+ try {
+ int serviceState = kernel.getServiceState(objectName);
+ boolean running = serviceState == ServiceState.RUNNING_INDEX || serviceState == ServiceState.STOPPING_INDEX;
+ if (running) {
+ serviceInvoker = serviceInvokerManager.getServiceInvoker(objectName);
+ return;
+ }
+ } catch (Exception e) {
+ // ignore cleaned up below
+ }
+ serviceInvoker = null;
+ }
+
+ public synchronized MBeanInfo getMBeanInfo() {
+ try {
+ String className;
+ String description = "No description available";
+ MBeanAttributeInfo[] attributes;
+ MBeanOperationInfo[] operations;
+
+ if (serviceInvoker != null) {
+ className = serviceInvoker.getServiceType().getName();
+
+ // attributes
+ List propertyIndex = serviceInvoker.getPropertyIndex();
+ attributes = new MBeanAttributeInfo[propertyIndex.size()];
+ for (ListIterator iterator = propertyIndex.listIterator(); iterator.hasNext();) {
+ PropertyInvoker propertyInvoker = (PropertyInvoker) iterator.next();
+
+ boolean isIs = false;
+ if (propertyInvoker.isReadable()) {
+ isIs = propertyInvoker.getGetterSignature().getName().startsWith("is");
+ }
+
+ attributes[iterator.previousIndex()] = new MBeanAttributeInfo(propertyInvoker.getPropertyName(),
+ propertyInvoker.getType().getName(),
+ "no description available",
+ propertyInvoker.isReadable(),
+ propertyInvoker.isWritable(),
+ isIs);
+ }
+
+
+ // operations
+ List operationIndex = serviceInvoker.getOperationIndex();
+ operations = new MBeanOperationInfo[operationIndex.size()];
+ for (ListIterator iterator = operationIndex.listIterator(); iterator.hasNext();) {
+ OperationInvoker operationInvoker = (OperationInvoker) iterator.next();
+
+ OperationSignature signature = operationInvoker.getSignature();
+
+ List argumentTypes = signature.getParameterTypes();
+ MBeanParameterInfo[] parameters = new MBeanParameterInfo[argumentTypes.size()];
+ for (ListIterator argIterator = argumentTypes.listIterator(); argIterator.hasNext();) {
+ String type = (String) argIterator.next();
+ parameters[argIterator.previousIndex()] = new MBeanParameterInfo("parameter" + argIterator.previousIndex(),
+ type,
+ "no description available");
+ }
+
+ operations[iterator.previousIndex()] = new MBeanOperationInfo(signature.getName(), "no description available", parameters, "java.lang.Object", MBeanOperationInfo.UNKNOWN);
+ }
+ } else {
+ className = Object.class.getName();
+ operations = new MBeanOperationInfo[0];
+ if (serviceFactory instanceof ConfigurableServiceFactory) {
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ List propertyNames = new ArrayList(configurableServiceFactory.getPropertyNames());
+ attributes = new MBeanAttributeInfo[propertyNames.size()];
+ for (ListIterator iterator = propertyNames.listIterator(); iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+ attributes[iterator.previousIndex()] = new MBeanAttributeInfo(propertyName,
+ Object.class.getName(),
+ "no description available",
+ true,
+ true,
+ false);
+ }
+ } else {
+ attributes = new MBeanAttributeInfo[0];
+ }
+
+ }
+
+ MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[1];
+ notifications[0] = new MBeanNotificationInfo(NotificationType.TYPES, "javax.management.Notification", "J2EE Notifications");
+
+ MBeanInfo mbeanInfo = new MBeanInfo(className, description, attributes, new MBeanConstructorInfo[0], operations, notifications);
+ return mbeanInfo;
+ } catch (RuntimeException e) {
+ log.info("Unable to create MBeanInfo", e);
+ throw e;
+ }
+ }
+
+ public Object getAttribute(String attributeName) throws ReflectionException, AttributeNotFoundException {
+ try {
+ if (ATTRIBUTE_CLASS_LOADER.equals(attributeName)) {
+ return kernel.getClassLoaderFor(objectName);
+ } else if (ATTRIBUTE_STATE.equals(attributeName)) {
+ return new Integer(kernel.getServiceState(objectName));
+ } else if (ATTRIBUTE_START_TIME.equals(attributeName)) {
+ return new Long(kernel.getServiceStartTime(objectName));
+ } else if (ATTRIBUTE_STATE_MANAGEABLE.equals(attributeName)) {
+ return Boolean.TRUE;
+ } else if (ATTRIBUTE_STATISTICS_PROVIDER.equals(attributeName)) {
+ return Boolean.FALSE;
+ } else if (ATTRIBUTE_EVENT_PROVIDER.equals(attributeName)) {
+ return Boolean.TRUE;
+ } else if (ATTRIBUTE_EVENT_TYPES.equals(attributeName)) {
+ return NotificationType.TYPES;
+ } else if (ATTRIBUTE_GBEAN_ENABLED.equals(attributeName)) {
+ return Boolean.valueOf(kernel.isServiceEnabled(objectName));
+ }
+
+ ServiceInvoker serviceInvoker;
+ synchronized (this) {
+ serviceInvoker = this.serviceInvoker;
+ }
+
+ if (serviceInvoker != null) {
+ Object value = serviceInvoker.getAttribute(attributeName);
+ return value;
+ } else {
+ if (!(serviceFactory instanceof ConfigurableServiceFactory)) {
+ throw new AttributeNotFoundException("Service is stopped and the service factory not configurable: objectName=" + objectName + ", propertyName=" + attributeName);
+ }
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ return configurableServiceFactory.getProperty(attributeName);
+ }
+ } catch (AttributeNotFoundException e) {
+ throw e;
+ } catch (NoSuchAttributeException e) {
+ throw new AttributeNotFoundException(attributeName);
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ public void setAttribute(Attribute attribute) throws ReflectionException, AttributeNotFoundException {
+ String attributeName = attribute.getName();
+ Object attributeValue = attribute.getValue();
+ try {
+ if (ATTRIBUTE_GBEAN_ENABLED.equals(attributeName)) {
+ kernel.setServiceEnabled(objectName, ((Boolean) attributeValue).booleanValue());
+ } else {
+ ServiceInvoker serviceInvoker;
+ synchronized (this) {
+ serviceInvoker = this.serviceInvoker;
+ }
+
+ if (serviceInvoker != null) {
+ serviceInvoker.setAttribute(attributeName, attributeValue);
+ } else {
+ if (!(serviceFactory instanceof ConfigurableServiceFactory)) {
+ throw new AttributeNotFoundException("Service is stopped and the service factory not configurable: objectName=" + objectName + ", propertyName=" + attributeName);
+ }
+ ConfigurableServiceFactory configurableServiceFactory = (ConfigurableServiceFactory) serviceFactory;
+ configurableServiceFactory.setProperty(attributeName, attributeValue);
+ }
+ }
+ } catch (AttributeNotFoundException e) {
+ throw e;
+ } catch (NoSuchAttributeException e) {
+ throw new AttributeNotFoundException(attributeName);
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ public AttributeList getAttributes(String[] attributes) {
+ AttributeList results = new AttributeList(attributes.length);
+ for (int i = 0; i < attributes.length; i++) {
+ String name = attributes[i];
+ try {
+ Object value = getAttribute(name);
+ results.add(new Attribute(name, value));
+ } catch (JMException e) {
+ log.warn("Exception while getting attribute " + name, e);
+ }
+ }
+ return results;
+ }
+
+ public AttributeList setAttributes(AttributeList attributes) {
+ AttributeList results = new AttributeList(attributes.size());
+ for (Iterator iterator = attributes.iterator(); iterator.hasNext();) {
+ Attribute attribute = (Attribute) iterator.next();
+ try {
+ setAttribute(attribute);
+ results.add(attribute);
+ } catch (JMException e) {
+ log.warn("Exception while setting attribute " + attribute.getName(), e);
+ }
+ }
+ return results;
+ }
+
+ public Object invoke(String operationName, Object[] arguments, String[] types) throws ReflectionException {
+ try {
+ if (arguments.length == 0 && OPERATION_START.equals(operationName)) {
+ kernel.startService(objectName);
+ return null;
+ } else if (arguments.length == 0 && OPERATION_START_RECURSIVE.equals(operationName)) {
+ kernel.startRecursiveService(objectName);
+ return null;
+ } else if (arguments.length == 0 && OPERATION_STOP.equals(operationName)) {
+ kernel.startService(objectName);
+ return null;
+ } else {
+ ServiceInvoker serviceInvoker;
+ synchronized (this) {
+ serviceInvoker = this.serviceInvoker;
+ }
+ if (serviceInvoker == null) {
+ throw new IllegalStateException("Service is not running: name=" + objectName);
+ }
+ return serviceInvoker.invoke(operationName, arguments, types);
+ }
+ } catch (NoSuchOperationException e) {
+ throw new ReflectionException(new NoSuchMethodException(new OperationSignature(operationName, types).toString()));
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ return new MBeanNotificationInfo[]{
+ new MBeanNotificationInfo(NotificationType.TYPES, "javax.management.Notification", "J2EE Notifications")
+ };
+ }
+
+ public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
+ notificationBroadcaster.addNotificationListener(listener, filter, handback);
+ }
+
+ public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
+ notificationBroadcaster.removeNotificationListener(listener);
+ }
+
+ public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
+ notificationBroadcaster.removeNotificationListener(listener, filter, handback);
+ }
+
+ public String toString() {
+ return objectName.toString();
+ }
+
+ private class LifecycleBridge implements LifecycleListener {
+ /**
+ * Sequence number used for notifications
+ */
+ private long sequence;
+
+ /**
+ * The notification broadcaster to use
+ */
+ private final NotificationBroadcasterSupport notificationBroadcaster;
+
+ public LifecycleBridge(NotificationBroadcasterSupport notificationBroadcaster) {
+ this.notificationBroadcaster = notificationBroadcaster;
+ }
+
+ public void loaded(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.OBJECT_CREATED, objectName, nextSequence()));
+ }
+ }
+
+ public void starting(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.STATE_STARTING, objectName, nextSequence()));
+ }
+ }
+
+ public void running(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ updateState();
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.STATE_RUNNING, objectName, nextSequence()));
+ }
+ }
+
+ public void stopping(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.STATE_STOPPING, objectName, nextSequence()));
+ }
+ }
+
+ public void stopped(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ updateState();
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.STATE_STOPPED, objectName, nextSequence()));
+ }
+ }
+
+ public void unloaded(ObjectName objectName) {
+ if (objectName.equals(objectName)) {
+ updateState();
+ notificationBroadcaster.sendNotification(new Notification(NotificationType.OBJECT_DELETED, objectName, nextSequence()));
+ }
+ }
+
+ public synchronized long nextSequence() {
+ return sequence++;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/ClassLoading.java b/kernel/src/java/org/gbean/kernel/ClassLoading.java
new file mode 100644
index 0000000..44f4b58
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/ClassLoading.java
@@ -0,0 +1,225 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.lang.reflect.Array;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utilities for loading classes.
+ *
+ * @version $Rev: 169154 $ $Date: 2005-05-08 12:35:23 -0700 (Sun, 08 May 2005) $
+ */
+public class ClassLoading {
+ /**
+ * Load a class for the given name.
+ * <p/>
+ * <p>Handles loading primitive types as well as VM class and array syntax.
+ *
+ * @param className The name of the Class to be loaded.
+ * @param classLoader The class loader to load the Class object from.
+ * @return The Class object for the given name.
+ * @throws ClassNotFoundException Failed to load Class object.
+ */
+ public static Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
+ if (className == null) {
+ throw new IllegalArgumentException("className is null");
+ }
+ if (classLoader == null) {
+ throw new IllegalArgumentException("classLoader is null");
+ }
+
+ // First just try to load
+ try {
+ return classLoader.loadClass(className);
+ } catch (ClassNotFoundException ignore) {
+ // handle special cases below
+ }
+
+ Class type = null;
+
+ // Check if it is a primitive type
+ type = getPrimitiveType(className);
+ if (type != null) return type;
+
+ // Check if it is a vm primitive
+ type = getVMPrimitiveType(className);
+ if (type != null) return type;
+
+ // Handle VM class syntax (Lclassname;)
+ if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
+ return classLoader.loadClass(className.substring(1, className.length() - 1));
+ }
+
+ // Handle VM array syntax ([type)
+ if (className.charAt(0) == '[') {
+ int arrayDimension = className.lastIndexOf('[') + 1;
+ String componentClassName = className.substring(arrayDimension, className.length());
+ type = loadClass(componentClassName, classLoader);
+
+ int dim[] = new int[arrayDimension];
+ java.util.Arrays.fill(dim, 0);
+ return Array.newInstance(type, dim).getClass();
+ }
+
+ // Handle user friendly type[] syntax
+ if (className.endsWith("[]")) {
+ // get the base component class name and the arrayDimensions
+ int arrayDimension = 0;
+ String componentClassName = className;
+ while (componentClassName.endsWith("[]")) {
+ componentClassName = componentClassName.substring(0, componentClassName.length() - 2);
+ arrayDimension++;
+ }
+
+ // load the base type
+ type = loadClass(componentClassName, classLoader);
+
+ // return the array type
+ int[] dim = new int[arrayDimension];
+ java.util.Arrays.fill(dim, 0);
+ return Array.newInstance(type, dim).getClass();
+ }
+
+ // Else we can not load (give up)
+ throw new ClassNotFoundException(className);
+ }
+
+ public static String getClassName(Class clazz) {
+ StringBuffer rc = new StringBuffer();
+ while (clazz.isArray()) {
+ rc.append('[');
+ clazz = clazz.getComponentType();
+ }
+ if (!clazz.isPrimitive()) {
+ rc.append('L');
+ rc.append(clazz.getName());
+ rc.append(';');
+ } else {
+ rc.append(VM_PRIMITIVES_REVERSE.get(clazz));
+ }
+ return rc.toString();
+ }
+
+ /**
+ * Primitive type name -> class map.
+ */
+ private static final Map PRIMITIVES = new HashMap();
+
+ /** Setup the primitives map. */
+ static {
+ PRIMITIVES.put("boolean", Boolean.TYPE);
+ PRIMITIVES.put("byte", Byte.TYPE);
+ PRIMITIVES.put("char", Character.TYPE);
+ PRIMITIVES.put("short", Short.TYPE);
+ PRIMITIVES.put("int", Integer.TYPE);
+ PRIMITIVES.put("long", Long.TYPE);
+ PRIMITIVES.put("float", Float.TYPE);
+ PRIMITIVES.put("double", Double.TYPE);
+ PRIMITIVES.put("void", Void.TYPE);
+ }
+
+ /**
+ * Get the primitive type for the given primitive name.
+ *
+ * @param name Primitive type name (boolean, byte, int, ...)
+ * @return Primitive type or null.
+ */
+ private static Class getPrimitiveType(final String name) {
+ return (Class) PRIMITIVES.get(name);
+ }
+
+ /**
+ * VM primitive type name -> primitive type
+ */
+ private static final HashMap VM_PRIMITIVES = new HashMap();
+
+ /** Setup the vm primitives map. */
+ static {
+ VM_PRIMITIVES.put("B", byte.class);
+ VM_PRIMITIVES.put("C", char.class);
+ VM_PRIMITIVES.put("D", double.class);
+ VM_PRIMITIVES.put("F", float.class);
+ VM_PRIMITIVES.put("I", int.class);
+ VM_PRIMITIVES.put("J", long.class);
+ VM_PRIMITIVES.put("S", short.class);
+ VM_PRIMITIVES.put("Z", boolean.class);
+ VM_PRIMITIVES.put("V", void.class);
+ }
+
+ /**
+ * VM primitive type primitive type -> name
+ */
+ private static final HashMap VM_PRIMITIVES_REVERSE = new HashMap();
+
+ /** Setup the vm primitives reverse map. */
+ static {
+ VM_PRIMITIVES_REVERSE.put(byte.class, "B");
+ VM_PRIMITIVES_REVERSE.put(char.class, "C");
+ VM_PRIMITIVES_REVERSE.put(double.class, "D");
+ VM_PRIMITIVES_REVERSE.put(float.class, "F");
+ VM_PRIMITIVES_REVERSE.put(int.class, "I");
+ VM_PRIMITIVES_REVERSE.put(long.class, "J");
+ VM_PRIMITIVES_REVERSE.put(short.class, "S");
+ VM_PRIMITIVES_REVERSE.put(boolean.class, "Z");
+ VM_PRIMITIVES_REVERSE.put(void.class, "V");
+ }
+
+ /**
+ * Get the primitive type for the given VM primitive name.
+ * <p/>
+ * <p>Mapping:
+ * <pre>
+ * B - byte
+ * C - char
+ * D - double
+ * F - float
+ * I - int
+ * J - long
+ * S - short
+ * Z - boolean
+ * V - void
+ * </pre>
+ *
+ * @param name VM primitive type name (B, C, J, ...)
+ * @return Primitive type or null.
+ */
+ private static Class getVMPrimitiveType(final String name) {
+ return (Class) VM_PRIMITIVES.get(name);
+ }
+
+ /**
+ * Map of primitive types to their wrapper classes
+ */
+ private static final Map PRIMITIVE_WRAPPERS = new HashMap();
+
+ /** Setup the wrapper map. */
+ static {
+ PRIMITIVE_WRAPPERS.put(Boolean.TYPE, Boolean.class);
+ PRIMITIVE_WRAPPERS.put(Byte.TYPE, Byte.class);
+ PRIMITIVE_WRAPPERS.put(Character.TYPE, Character.class);
+ PRIMITIVE_WRAPPERS.put(Double.TYPE, Double.class);
+ PRIMITIVE_WRAPPERS.put(Float.TYPE, Float.class);
+ PRIMITIVE_WRAPPERS.put(Integer.TYPE, Integer.class);
+ PRIMITIVE_WRAPPERS.put(Long.TYPE, Long.class);
+ PRIMITIVE_WRAPPERS.put(Short.TYPE, Short.class);
+ PRIMITIVE_WRAPPERS.put(Void.TYPE, Void.class);
+ }
+}
+
diff --git a/kernel/src/java/org/gbean/kernel/ConstructorSignature.java b/kernel/src/java/org/gbean/kernel/ConstructorSignature.java
new file mode 100644
index 0000000..988cb7a
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/ConstructorSignature.java
@@ -0,0 +1,127 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @version $Rev: 109957 $ $Date: 2004-12-05 23:52:06 -0800 (Sun, 05 Dec 2004) $
+ */
+public final class ConstructorSignature {
+ private final static String[] NO_TYPES = new String[0];
+ private final String[] parameterTypes;
+
+ public ConstructorSignature(Constructor constructor) {
+ Class[] parameters = constructor.getParameterTypes();
+ parameterTypes = new String[parameters.length];
+ for (int i = 0; i < parameters.length; i++) {
+ parameterTypes[i] = parameters[i].getName();
+ }
+ }
+
+ public ConstructorSignature(String[] argumentTypes) {
+ for (int i = 0; i < argumentTypes.length; i++) {
+ if (argumentTypes[i] == null) {
+ throw new IllegalArgumentException("Argument " + i + " is null");
+ }
+ }
+
+ if (argumentTypes != null) {
+ this.parameterTypes = argumentTypes;
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public ConstructorSignature(Class[] argumentTypes) {
+ if (argumentTypes != null) {
+ this.parameterTypes = new String[argumentTypes.length];
+ for (int i = 0; i < argumentTypes.length; i++) {
+ this.parameterTypes[i] = argumentTypes[i].getName();
+ }
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public ConstructorSignature(List argumentTypes) {
+ if (argumentTypes != null) {
+ this.parameterTypes = new String[argumentTypes.size()];
+ for (int i = 0; i < argumentTypes.size(); i++) {
+ Object argumentType = argumentTypes.get(i);
+ if (argumentType instanceof Class) {
+ this.parameterTypes[i] = ((Class) argumentType).getName();
+ } else if (argumentType instanceof String) {
+ this.parameterTypes[i] = (String) argumentType;
+ } else {
+ throw new IllegalArgumentException("Argument type must be a String or a Class: index=" + i + ", type=" + argumentType.getClass());
+ }
+ }
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public List getParameterTypes() {
+ return Collections.unmodifiableList(Arrays.asList(parameterTypes));
+ }
+
+ public boolean equals(Object object) {
+ if (!(object instanceof ConstructorSignature)) {
+ return false;
+ }
+
+ ConstructorSignature constructorSignature = (ConstructorSignature) object;
+
+ // match arg length
+ int length = constructorSignature.parameterTypes.length;
+ if (length != parameterTypes.length) {
+ return false;
+ }
+
+ // match each arg
+ for (int i = 0; i < length; i++) {
+ if (!constructorSignature.parameterTypes[i].equals(parameterTypes[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ for (int i = 0; i < parameterTypes.length; i++) {
+ result = 37 * result + parameterTypes[i].hashCode();
+ }
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer("<init>(");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(parameterTypes[i]);
+ }
+ return buffer.append(")").toString();
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/DependencyManager.java b/kernel/src/java/org/gbean/kernel/DependencyManager.java
new file mode 100644
index 0000000..b21ff2e
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/DependencyManager.java
@@ -0,0 +1,123 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.Collection;
+import java.util.Set;
+import javax.management.ObjectName;
+
+/**
+ * DependencyManager is the record keeper of the dependencies in the kernel. The DependencyManager
+ * does not enforce any dependencies, it is simply a place where components can register their intent
+ * to be dependent on another component.
+ * <p/>
+ * The DependencyManager uses the nomenclature of parent-child where a child is dependent on a parent.
+ * The names parent and child have no other meaning are just a convience to make the code readable.
+ *
+ * @version $Rev: 169154 $ $Date: 2005-05-08 12:35:23 -0700 (Sun, 08 May 2005) $
+ */
+public interface DependencyManager {
+ /**
+ * Starts the dependency manager
+ */
+ public void start();
+
+ /**
+ * Stops the dependency manager releasing all resources
+ */
+ public void stop();
+
+ /**
+ * Declares a dependency from a child to a parent.
+ *
+ * @param child the dependent component
+ * @param parent the component the child is depending on
+ */
+ public void addDependency(ObjectName child, ObjectName parent);
+
+ /**
+ * Removes a dependency from a child to a parent
+ *
+ * @param child the dependnet component
+ * @param parent the component that the child wil no longer depend on
+ */
+ public void removeDependency(ObjectName child, ObjectName parent);
+
+ /**
+ * Removes all dependencies for a child
+ *
+ * @param child the component that will no longer depend on anything
+ */
+ public void removeAllDependencies(ObjectName child);
+
+ /**
+ * Adds dependencies from the child to every parent in the parents set
+ *
+ * @param child the dependent component
+ * @param parents the set of components the child is depending on
+ */
+ public void addDependencies(ObjectName child, Set parents);
+
+ /**
+ * Gets the set of parents that the child is depending on
+ *
+ * @param child the dependent component
+ * @return a collection containing all of the components the child depends on; will never be null
+ */
+ public Set getParents(ObjectName child);
+
+ /**
+ * Gets all of the services that have a dependency on the specified startParent.
+ *
+ * @param parent the component the returned childen set depend on
+ * @return a collection containing all of the components that depend on the parent; will never be null
+ */
+ public Set getChildren(ObjectName parent);
+
+ /**
+ * Adds a hold on a collection of object name patterns. If the name of a component matches an object name
+ * pattern in the collection, the component should not start.
+ *
+ * @param objectName the name of the component placing the holds
+ * @param holds a collection of object name patterns which should not start
+ */
+ public void addStartHolds(ObjectName objectName, Collection holds);
+
+ /**
+ * Removes a collection of holds.
+ *
+ * @param objectName the object name of the components owning the holds
+ * @param holds a collection of the holds to remove
+ */
+ public void removeStartHolds(ObjectName objectName, Collection holds);
+
+ /**
+ * Removes all of the holds owned by a component.
+ *
+ * @param objectName the object name of the component that will no longer have any holds
+ */
+ public void removeAllStartHolds(ObjectName objectName);
+
+ /**
+ * Gets the object name of the bean blocking the start specified bean.
+ *
+ * @param objectName the bean to check for blockers
+ * @return the bean blocking the specified bean, or null if there are no blockers
+ */
+ public ObjectName checkBlocker(ObjectName objectName);
+}
diff --git a/kernel/src/java/org/gbean/kernel/Kernel.java b/kernel/src/java/org/gbean/kernel/Kernel.java
new file mode 100644
index 0000000..a719726
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/Kernel.java
@@ -0,0 +1,236 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.Set;
+import java.util.Date;
+import java.util.Collection;
+import javax.management.ObjectName;
+
+import org.gbean.service.ServiceFactory;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface Kernel {
+ /**
+ * The name used by a Kernel to register itself when it boots.
+ */
+ ObjectName KERNEL = ServiceName.createName(":j2eeType=Kernel");
+
+ /**
+ * Get the name of this kernel
+ *
+ * @return the name of this kernel
+ */
+ String getKernelName();
+
+ /**
+ * Load a specific service into this kernel.
+ * This is intended for applications that are embedding the kernel.
+ *
+ * @param serviceFactory the service to load
+ * @param classLoader the class loader to use to load the service
+ * @throws ServiceAlreadyExistsException if the name is already used
+ */
+ void loadService(ObjectName name, ServiceFactory serviceFactory, ClassLoader classLoader) throws ServiceAlreadyExistsException;
+
+ /**
+ * Is there a service registered with the kernel under the specified name?
+ * @param name the name to check
+ * @return true if there is a service registered under the specified name; false otherwise
+ */
+ boolean isLoaded(ObjectName name);
+
+ /**
+ * Start a specific service.
+ *
+ * @param name the service to start
+ * @throws ServiceNotFoundException if the service could not be found
+ * @throws IllegalStateException If the service is disabled
+ */
+ void startService(ObjectName name) throws ServiceNotFoundException, IllegalStateException;
+
+ /**
+ * Start a specific service and its children.
+ *
+ * @param name the service to start
+ * @throws ServiceNotFoundException if the service could not be found
+ * @throws IllegalStateException If the service is disabled
+ */
+ void startRecursiveService(ObjectName name) throws ServiceNotFoundException, IllegalStateException;
+
+ /**
+ * Stop a specific service.
+ *
+ * @param name the service to stop
+ * @throws ServiceNotFoundException if the service could not be found
+ * @throws IllegalStateException If the service is disabled
+ */
+ void stopService(ObjectName name) throws ServiceNotFoundException, IllegalStateException;
+
+ /**
+ * Unload a specific service.
+ * This is intended for applications that are embedding the kernel.
+ *
+ * @param name the name of the service to unregister
+ * @throws ServiceNotFoundException if the service could not be found
+ */
+ void unloadService(ObjectName name) throws ServiceNotFoundException, IllegalStateException;
+
+ /**
+ * Gets a service instance. This method should be use with extreme caution, as this method
+ * returns hard reference to the instance which if handled improperly will lead to memory
+ * leaks.
+ * @param name the name of the object to fetch
+ * @return the service instance
+ * @throws ServiceNotFoundException if the service is not loaded in to the kernel
+ * @throws IllegalStateException if the service is not in the RUNNING or STOPPING states
+ */
+ Object getService(ObjectName name) throws ServiceNotFoundException, IllegalStateException;
+
+ /**
+ * Gets the state of the specified service.
+ * @param name the name of the service
+ * @return the state of the service
+ * @throws ServiceNotFoundException if the service could not be found
+ */
+ int getServiceState(ObjectName name) throws ServiceNotFoundException;
+
+ /**
+ * Gets the time the specified service was started
+ * @param name the name of the service
+ * @return the start time of the service or 0 if not running
+ * @throws ServiceNotFoundException if the service could not be found
+ */
+ long getServiceStartTime(ObjectName name) throws ServiceNotFoundException;
+
+ /**
+ * Is the specified service enabled?
+ * @param name the name if the service
+ * @return true if the service is enabled
+ * @throws ServiceNotFoundException if the service could not be found
+ */
+ boolean isServiceEnabled(ObjectName name) throws ServiceNotFoundException;
+
+ /**
+ * Sets the eneabled status of the specified service. A disabled service can not be started, and
+ * will not be started via startRecursive.
+ * @param name the name if the service
+ * @param enabled the new enabled status
+ * @throws ServiceNotFoundException if the service could not be found
+ */
+ void setServiceEnabled(ObjectName name, boolean enabled) throws ServiceNotFoundException;
+
+ /**
+ * Gets the ClassLoader used to register the specified service
+ * @param name the name of the service from which the class loader should be extracted
+ * @return the class loader associated with the specified service
+ * @throws ServiceNotFoundException if the specified service is not registered with the kernel
+ */
+ ClassLoader getClassLoaderFor(ObjectName name) throws ServiceNotFoundException;
+
+ /**
+ * Return the ServiceFactory for a registered service instance.
+ * @param name the name of the service whose info should be returned
+ * @return the info for that instance
+ * @throws ServiceNotFoundException if there is no instance with the supplied name
+ */
+ ServiceFactory getServiceFactory(ObjectName name) throws ServiceNotFoundException;
+
+ /**
+ * Returns a Set of all services matching the object name pattern
+ * @return a List of the matching services registered with this kernel
+ */
+ Collection listServices(ObjectName pattern);
+
+ /**
+ * Returns a Set of all services matching the set of object name pattern
+ * @return a List of the matching services registered with this kernel
+ */
+ Set listServices(Set patterns);
+
+ /**
+ * Returns a Set of all services matching the object name pattern
+ * @return a List of javax.management.ObjectName of matching services registered with this kernel
+ */
+ Set listServiceNames(ObjectName pattern);
+
+ /**
+ * Returns a Set of all services matching the set of object name pattern
+ * @return a List of javax.management.ObjectName of matching services registered with this kernel
+ */
+ Set listServiceNames(Set patterns);
+
+ /**
+ * Brings the kernel online
+ * @throws Exception if the kernel can not boot
+ */
+ void boot() throws Exception;
+
+ /**
+ * Returns the time this kernel was last booted.
+ * @return the time this kernel was last booted; null if the kernel has not been
+ */
+ Date getBootTime();
+
+ /**
+ * Registers a runnable to execute when the kernel is shutdown
+ * @param hook a runnable to execute when the kernel is shutdown
+ */
+ void registerShutdownHook(Runnable hook);
+
+ /**
+ * Unregisters a runnable from the list to execute when the kernel is shutdown
+ * @param hook the runnable that should be removed
+ */
+ void unregisterShutdownHook(Runnable hook);
+
+ /**
+ * Stops the kernel
+ */
+ void shutdown();
+
+ /**
+ * Has the kernel been booted
+ * @return true if the kernel has been booted; false otherwise
+ */
+ boolean isRunning();
+
+ /**
+ * Adds a listener for all lifecycle events any service matching the pattern
+ *
+ * This is equivalent to addLifecycleListener(lifecycleListener, Collections.singleton(pattern))
+ *
+ * @param lifecycleListener the listener instance
+ * @param pattern the pattern used to filter events
+ */
+ void addLifecycleListener(LifecycleListener lifecycleListener, ObjectName pattern);
+
+ /**
+ * Registers a listener to revieve life cycle events for a set of object name patterns.
+ * @param lifecycleListener the listener that will receive life cycle events
+ * @param patterns a set of ObjectName patterns
+ */
+ void addLifecycleListener(LifecycleListener lifecycleListener, Set patterns);
+
+ /**
+ * Removes the listener from all notifications.
+ * @param lifecycleListener the listener to unregister
+ */
+ void removeLifecycleListener(LifecycleListener lifecycleListener);
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelException.java b/kernel/src/java/org/gbean/kernel/KernelException.java
new file mode 100644
index 0000000..faa640c
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class KernelException extends Exception {
+ public KernelException() {
+ }
+
+ public KernelException(String message) {
+ super(message);
+ }
+
+ public KernelException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public KernelException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelFactory.java b/kernel/src/java/org/gbean/kernel/KernelFactory.java
new file mode 100644
index 0000000..fa8ccd4
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelFactory.java
@@ -0,0 +1,89 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.gbean.kernel.simple.SimpleKernelFactory;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public abstract class KernelFactory {
+ public static final String KERNEL_FACTORY_KEY = KernelFactory.class.getName();
+
+ public static KernelFactory newInstance() {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader = KernelFactory.class.getClassLoader();
+ }
+
+ // System property
+ try {
+ String kernelFactoryName = System.getProperty(KERNEL_FACTORY_KEY);
+ if (kernelFactoryName != null) {
+ return createKernelFactory(kernelFactoryName, classLoader);
+ }
+ } catch (SecurityException se) {
+ }
+
+ // Jar Service Specification - http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html
+ String serviceId = "META-INF/services/" + KERNEL_FACTORY_KEY;
+ InputStream inputStream = null;
+ try {
+ inputStream = classLoader.getResourceAsStream(serviceId);
+ if (inputStream != null) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
+ String kernelFactoryName = reader.readLine();
+ reader.close();
+
+ if (kernelFactoryName != null && kernelFactoryName.length() > 0) {
+ return createKernelFactory(kernelFactoryName, classLoader);
+ }
+ }
+ } catch (Exception ignored) {
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException ignored) {
+ }
+ inputStream = null;
+ }
+ }
+
+ // Default is the basic kernel
+ return new SimpleKernelFactory();
+ }
+
+ private static KernelFactory createKernelFactory(String className, ClassLoader classLoader) {
+ try {
+ return (KernelFactory) classLoader.loadClass(className).newInstance();
+ } catch (ClassCastException e) {
+ throw new KernelFactoryError("Kernel factory class does not implement KernelFactory: " + className);
+ } catch (ClassNotFoundException e) {
+ throw new KernelFactoryError("Kernel factory class not found: " + className);
+ } catch (Exception e) {
+ throw new KernelFactoryError("Unable to instantiate kernel factory class: " + className, e);
+ }
+ }
+
+ public abstract Kernel createKernel(String kernelName);
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelFactoryError.java b/kernel/src/java/org/gbean/kernel/KernelFactoryError.java
new file mode 100644
index 0000000..4ca3aa0
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelFactoryError.java
@@ -0,0 +1,38 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class KernelFactoryError extends Error {
+ public KernelFactoryError() {
+ super();
+ }
+
+ public KernelFactoryError(String message) {
+ super(message);
+ }
+
+ public KernelFactoryError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public KernelFactoryError(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelMain.java b/kernel/src/java/org/gbean/kernel/KernelMain.java
new file mode 100644
index 0000000..77d87d6
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelMain.java
@@ -0,0 +1,200 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.simple.SimpleServiceFactory;
+import org.gbean.loader.LoaderUtil;
+import org.gbean.spring.FatalStartupError;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class KernelMain implements Main {
+ private static final String DEFAULT_KERNEL_NAME = "gbean";
+
+ private Kernel kernel;
+ private ClassLoader classLoader;
+ private Map services = Collections.EMPTY_MAP;
+ private List locations = Collections.EMPTY_LIST;
+ private boolean daemon = true;
+ private Main next;
+
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ public void setKernel(Kernel kernel) {
+ this.kernel = kernel;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public void setClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+ public Map getServices() {
+ return services;
+ }
+
+ public void setServices(Map services) {
+ this.services = services;
+ }
+
+ public List getLocations() {
+ return locations;
+ }
+
+ public void setLocations(List locations) {
+ this.locations = locations;
+ }
+
+ public boolean isDaemon() {
+ return daemon;
+ }
+
+ public void setDaemon(boolean daemon) {
+ this.daemon = daemon;
+ }
+
+ public Main getNext() {
+ return next;
+ }
+
+ public void setNext(Main next) {
+ this.next = next;
+ }
+
+ public void main(String[] args) {
+ if (classLoader == null) {
+ classLoader = Thread.currentThread().getContextClassLoader();
+ }
+
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(classLoader);
+ try {
+ // create a default kernel if necessary
+ if (kernel == null) {
+ kernel = KernelFactory.newInstance().createKernel(DEFAULT_KERNEL_NAME);
+ }
+
+ // boot the kernel
+ try {
+ kernel.boot();
+ } catch (Exception e) {
+ throw new FatalStartupError("Unable to boot the kernel", e);
+ }
+
+ // add our shutdown hook
+ kernel.registerShutdownHook(new Runnable() {
+ public void run() {
+ // bind the bootstrap services
+ for (Iterator iterator = services.keySet().iterator(); iterator.hasNext();) {
+ String name = (String) iterator.next();
+ try {
+ ObjectName objectName = new ObjectName(name);
+ kernel.stopService(objectName);
+ kernel.unloadService(objectName);
+ } catch (Exception e) {
+ // igore -- a real exception will be logged by the kernel
+ }
+ }
+ }
+ });
+
+ boolean failed = false;
+ try {
+ // bind the bootstrap services
+ for (Iterator iterator = services.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String name = (String) entry.getKey();
+ Object service = entry.getValue();
+
+ try {
+ ObjectName objectName = new ObjectName(name);
+ kernel.loadService(objectName, new SimpleServiceFactory(service), classLoader);
+ kernel.startService(objectName);
+ } catch (Exception e) {
+ throw new FatalStartupError("Unable to bind bootstrap service '" + name + "' into the kernel", e);
+ }
+ }
+
+ // verify that all bootstrap services started successfully
+ LoaderUtil.verifyAllServicesRunning(kernel);
+
+
+ // load each location and verify that all services started successfully
+ for (Iterator iterator = locations.iterator(); iterator.hasNext();) {
+ String location = (String) iterator.next();
+ LoaderUtil.load(kernel, location);
+ LoaderUtil.verifyAllServicesRunning(kernel);
+ }
+
+ // if we have a child main class call it
+ if (next != null) {
+ next.main(args);
+ }
+
+ // if we are a daemon we wait here until the server stops
+ if (daemon) {
+ // add our shutdown hook
+ Runtime.getRuntime().addShutdownHook(new Thread("Shutdown Thread") {
+ public void run() {
+ kernel.shutdown();
+ }
+ });
+
+ while (kernel.isRunning()) {
+ try {
+ // wait for the kernel to be ready to exit
+ synchronized (kernel) {
+ kernel.wait();
+ }
+ } catch (InterruptedException e) {
+ // ignore - we check the variable above
+ }
+ }
+ }
+ } catch (RuntimeException e) {
+ failed = true;
+ throw e;
+ } catch (Error e) {
+ failed = true;
+ throw e;
+ } finally {
+ try {
+ kernel.shutdown();
+ } catch (Exception e) {
+ // if we are not alredy throwing an exception, throw a new exception
+ if (!failed) {
+ throw new FatalStartupError("Exception while shutting down kernel", e);
+ }
+ }
+ }
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelRegistry.java b/kernel/src/java/org/gbean/kernel/KernelRegistry.java
new file mode 100644
index 0000000..42895cf
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelRegistry.java
@@ -0,0 +1,124 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Collections;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public final class KernelRegistry {
+ /**
+ * Index of kernel references by kernel name
+ */
+ private static final Map kernels = new HashMap();
+
+ /**
+ * ReferenceQueue that watches the weak references to our kernels
+ */
+ private static final ReferenceQueue queue = new ReferenceQueue();
+
+ public static Set getKernelNames() {
+ synchronized(kernels) {
+ return Collections.unmodifiableSet(kernels.keySet());
+ }
+ }
+
+ /**
+ * Get a particular kernel indexed by a name
+ *
+ * @param name the name of the kernel to be obtained
+ * @return the kernel that was registered with that name
+ */
+ public static Kernel getKernel(String name) {
+ if (name == null) {
+ return getSingleKernel();
+ }
+ synchronized (kernels) {
+ processQueue();
+ KernelReference ref = (KernelReference) kernels.get(name);
+ if (ref != null) {
+ return (Kernel) ref.get();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Obtain the single kernel that's registered.
+ * <p/>
+ * <p>This method assumes that there is only one kernel registered and will throw an
+ * <code>IllegalStateException</code> if more than one has been registered.
+ *
+ * @return the single kernel that's registered
+ * @throws IllegalStateException if more than one
+ */
+ public static Kernel getSingleKernel() {
+ synchronized (kernels) {
+ processQueue();
+
+ int size = kernels.size();
+ if (size > 1) throw new IllegalStateException("More than one kernel has been registered.");
+ if (size < 1) return null;
+
+ Kernel result = (Kernel) ((KernelReference) kernels.values().iterator().next()).get();
+ if (result == null) {
+ kernels.clear();
+ }
+ return result;
+ }
+ }
+
+ public static void registerKernel(Kernel kernel) {
+ synchronized (kernels) {
+ String kernelName = kernel.getKernelName();
+ if (kernels.containsKey(kernelName)) {
+ throw new IllegalStateException("A kernel is already running this kernel name: " + kernelName);
+ }
+ kernels.put(kernelName, new KernelReference(kernelName, kernel));
+ }
+ }
+
+ public static void unregisterKernel(Kernel kernel) {
+ synchronized (kernels) {
+ kernels.remove(kernel.getKernelName());
+ }
+ }
+
+ private static void processQueue() {
+ KernelReference kernelRef;
+ while ((kernelRef = (KernelReference) queue.poll()) != null) {
+ synchronized (kernels) {
+ kernels.remove(kernelRef.key);
+ }
+ }
+ }
+
+ private static class KernelReference extends WeakReference {
+ private final Object key;
+
+ public KernelReference(Object key, Object kernel) {
+ super(kernel, queue);
+ this.key = key;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/KernelUtil.java b/kernel/src/java/org/gbean/kernel/KernelUtil.java
new file mode 100644
index 0000000..d29438c
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/KernelUtil.java
@@ -0,0 +1,62 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Collections;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.runtime.ServiceState;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class KernelUtil {
+ public static Set getRunningServiceNames(Kernel kernel, Set patterns) {
+ Set runningTargets = new HashSet();
+ Set services = kernel.listServiceNames(patterns);
+ for (Iterator iterator = services.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ if (isRunning(kernel, objectName)) {
+ runningTargets.add(objectName);
+ }
+ }
+ return runningTargets;
+ }
+
+ public static Set getRunningServiceNames(Kernel kernel, ObjectName pattern) {
+ return getRunningServiceNames(kernel, Collections.singleton(pattern));
+ }
+
+ /**
+ * Is the component in the Running state
+ *
+ * @param objectName name of the component to check
+ * @return true if the component is running; false otherwise
+ */
+ public static boolean isRunning(Kernel kernel, ObjectName objectName) {
+ try {
+ int state = kernel.getServiceState(objectName);
+ return state == ServiceState.RUNNING_INDEX;
+ } catch (ServiceNotFoundException e) {
+ // service is no longer registerd
+ return false;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/LifecycleAdapter.java b/kernel/src/java/org/gbean/kernel/LifecycleAdapter.java
new file mode 100644
index 0000000..63d3d23
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/LifecycleAdapter.java
@@ -0,0 +1,42 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import javax.management.ObjectName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class LifecycleAdapter implements LifecycleListener {
+ public void loaded(ObjectName objectName) {
+ }
+
+ public void starting(ObjectName objectName) {
+ }
+
+ public void running(ObjectName objectName) {
+ }
+
+ public void stopping(ObjectName objectName) {
+ }
+
+ public void stopped(ObjectName objectName) {
+ }
+
+ public void unloaded(ObjectName objectName) {
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/LifecycleListener.java b/kernel/src/java/org/gbean/kernel/LifecycleListener.java
new file mode 100644
index 0000000..93aa6d7
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/LifecycleListener.java
@@ -0,0 +1,32 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.EventListener;
+import javax.management.ObjectName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface LifecycleListener extends EventListener {
+ public void loaded(ObjectName objectName);
+ public void starting(ObjectName objectName);
+ public void running(ObjectName objectName);
+ public void stopping(ObjectName objectName);
+ public void stopped(ObjectName objectName);
+ public void unloaded(ObjectName objectName);
+}
diff --git a/kernel/src/java/org/gbean/kernel/Main.java b/kernel/src/java/org/gbean/kernel/Main.java
new file mode 100644
index 0000000..ffa92c9
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/Main.java
@@ -0,0 +1,24 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface Main {
+ void main(String[] args);
+}
diff --git a/kernel/src/java/org/gbean/kernel/MalformedServiceNameException.java b/kernel/src/java/org/gbean/kernel/MalformedServiceNameException.java
new file mode 100644
index 0000000..fc8dc05
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/MalformedServiceNameException.java
@@ -0,0 +1,33 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class MalformedServiceNameException extends RuntimeException {
+ private final String name;
+
+ public MalformedServiceNameException(String name) {
+ super (name);
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/NoSuchAttributeException.java b/kernel/src/java/org/gbean/kernel/NoSuchAttributeException.java
new file mode 100644
index 0000000..4679895
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/NoSuchAttributeException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class NoSuchAttributeException extends KernelException {
+ public NoSuchAttributeException() {
+ }
+
+ public NoSuchAttributeException(String message) {
+ super(message);
+ }
+
+ public NoSuchAttributeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public NoSuchAttributeException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/NoSuchOperationException.java b/kernel/src/java/org/gbean/kernel/NoSuchOperationException.java
new file mode 100644
index 0000000..52336ec
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/NoSuchOperationException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class NoSuchOperationException extends KernelException {
+ public NoSuchOperationException() {
+ }
+
+ public NoSuchOperationException(String message) {
+ super(message);
+ }
+
+ public NoSuchOperationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public NoSuchOperationException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/OperationSignature.java b/kernel/src/java/org/gbean/kernel/OperationSignature.java
new file mode 100644
index 0000000..efdf963
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/OperationSignature.java
@@ -0,0 +1,135 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * @version $Rev: 109957 $ $Date: 2004-12-05 23:52:06 -0800 (Sun, 05 Dec 2004) $
+ */
+public final class OperationSignature {
+ private final static String[] NO_TYPES = new String[0];
+ private final String name;
+ private final String[] parameterTypes;
+
+ public OperationSignature(Method method) {
+ name = method.getName();
+ Class[] parameters = method.getParameterTypes();
+ parameterTypes = new String[parameters.length];
+ for (int i = 0; i < parameters.length; i++) {
+ parameterTypes[i] = parameters[i].getName();
+ }
+ }
+
+ public OperationSignature(String name, String[] argumentTypes) {
+ this.name = name;
+ if (argumentTypes != null) {
+ this.parameterTypes = argumentTypes;
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public OperationSignature(String name, Class[] argumentTypes) {
+ this.name = name;
+ if (argumentTypes != null) {
+ this.parameterTypes = new String[argumentTypes.length];
+ for (int i = 0; i < argumentTypes.length; i++) {
+ this.parameterTypes[i] = argumentTypes[i].getName();
+ }
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public OperationSignature(String name, List argumentTypes) {
+ this.name = name;
+ if (argumentTypes != null) {
+ this.parameterTypes = new String[argumentTypes.size()];
+ for (int i = 0; i < argumentTypes.size(); i++) {
+ Object argumentType = argumentTypes.get(i);
+ if (argumentType instanceof Class) {
+ this.parameterTypes[i] = ((Class) argumentType).getName();
+ } else if (argumentType instanceof String) {
+ this.parameterTypes[i] = (String) argumentType;
+ } else {
+ throw new IllegalArgumentException("Argument type must be a String or a Class: index=" + i + ", type=" + argumentType.getClass());
+ }
+ }
+ } else {
+ this.parameterTypes = NO_TYPES;
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List getParameterTypes() {
+ return Collections.unmodifiableList(Arrays.asList(parameterTypes));
+ }
+
+ public boolean equals(Object object) {
+ if (!(object instanceof OperationSignature)) {
+ return false;
+ }
+
+ // match names
+ OperationSignature methodKey = (OperationSignature) object;
+ if (!methodKey.name.equals(name)) {
+ return false;
+ }
+
+ // match arg length
+ int length = methodKey.parameterTypes.length;
+ if (length != parameterTypes.length) {
+ return false;
+ }
+
+ // match each arg
+ for (int i = 0; i < length; i++) {
+ if (!methodKey.parameterTypes[i].equals(parameterTypes[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + name.hashCode();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ result = 37 * result + parameterTypes[i].hashCode();
+ }
+ return result;
+ }
+
+ public String toString() {
+ StringBuffer buffer = new StringBuffer(name).append("(");
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(parameterTypes[i]);
+ }
+ return buffer.append(")").toString();
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/ServiceAlreadyExistsException.java b/kernel/src/java/org/gbean/kernel/ServiceAlreadyExistsException.java
new file mode 100644
index 0000000..83efc0a
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/ServiceAlreadyExistsException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ServiceAlreadyExistsException extends KernelException {
+ public ServiceAlreadyExistsException() {
+ }
+
+ public ServiceAlreadyExistsException(String message) {
+ super(message);
+ }
+
+ public ServiceAlreadyExistsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ServiceAlreadyExistsException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/ServiceName.java b/kernel/src/java/org/gbean/kernel/ServiceName.java
new file mode 100644
index 0000000..20a06ce
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/ServiceName.java
@@ -0,0 +1,46 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+import java.util.Properties;
+import javax.management.ObjectName;
+import javax.management.MalformedObjectNameException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public final class ServiceName {
+ private ServiceName() {
+ }
+
+ public static ObjectName createName(String name) {
+ try {
+ return new ObjectName(name);
+ } catch (MalformedObjectNameException e) {
+ throw new MalformedServiceNameException(name);
+ }
+ }
+
+ public static ObjectName createName(String domainName, Properties properties) {
+ try {
+ return new ObjectName(domainName, properties);
+ } catch (MalformedObjectNameException e) {
+ // todo more descriptive message here
+ throw new MalformedServiceNameException("");
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/ServiceNotFoundException.java b/kernel/src/java/org/gbean/kernel/ServiceNotFoundException.java
new file mode 100644
index 0000000..73797a9
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/ServiceNotFoundException.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ServiceNotFoundException extends KernelException {
+ public ServiceNotFoundException() {
+ }
+
+ public ServiceNotFoundException(String message) {
+ super(message);
+ }
+
+ public ServiceNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ServiceNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/runtime/LifecycleBroadcaster.java b/kernel/src/java/org/gbean/kernel/runtime/LifecycleBroadcaster.java
new file mode 100644
index 0000000..a484b18
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/runtime/LifecycleBroadcaster.java
@@ -0,0 +1,31 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.runtime;
+
+
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface LifecycleBroadcaster {
+ public void fireLoadedEvent();
+ public void fireStartingEvent();
+ public void fireRunningEvent();
+ public void fireStoppingEvent();
+ public void fireStoppedEvent();
+ public void fireUnloadedEvent();
+}
diff --git a/kernel/src/java/org/gbean/kernel/runtime/ServiceDependency.java b/kernel/src/java/org/gbean/kernel/runtime/ServiceDependency.java
new file mode 100644
index 0000000..2b546e5
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/runtime/ServiceDependency.java
@@ -0,0 +1,217 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.runtime;
+
+import java.util.Iterator;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.DependencyManager;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.KernelUtil;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class ServiceDependency {
+ private static final Log log = LogFactory.getLog(ServiceDependency.class);
+
+ /**
+ * The ServiceInstance to which this reference belongs.
+ */
+ private final ServiceInstance serviceInstance;
+
+ /**
+ * The target objectName patterns to watch for a connection.
+ */
+ private final Set patterns;
+
+ /**
+ * Descriptive name of dependency
+ */
+ private final String name;
+
+ /**
+ * The kernel to which the reference is bound.
+ */
+ private final Kernel kernel;
+
+ /**
+ * The dependency manager of the kernel.
+ */
+ private final DependencyManager dependencyManager;
+
+ /**
+ * Is the ServiceInstance waitng for me to start?
+ */
+ private boolean waiting = false;
+
+ /**
+ * The object to which the proxy is bound
+ */
+ private ObjectName proxyTarget;
+
+ /**
+ * Our listener for lifecycle events
+ */
+ private LifecycleListener listener;
+
+ /**
+ * Why is the dependency in the current state
+ */
+ private String statusDescription;
+
+ public ServiceDependency(ServiceInstance serviceInstance, String name, Set patterns, Kernel kernel, DependencyManager dependencyManager) {
+ this.serviceInstance = serviceInstance;
+ this.name = name;
+ this.patterns = patterns;
+ this.kernel = kernel;
+ this.dependencyManager = dependencyManager;
+ statusDescription = "NOT STARTED: " + getDescription();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set getPatterns() {
+ return patterns;
+ }
+
+ public boolean isWaiting() {
+ return waiting;
+ }
+
+ public String getStatusDescription() {
+ return statusDescription;
+ }
+
+ public synchronized boolean start() {
+ // We only need to start if there are patterns and we don't already have a proxy
+ if (proxyTarget == null) {
+ if (listener == null) {
+ listener = new DependencyLifecycleListener();
+ try {
+ kernel.addLifecycleListener(listener, patterns);
+ } catch (Error e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ //
+ // We must have exactally one running target
+ //
+ ObjectName objectName = serviceInstance.getObjectName();
+ Set services = KernelUtil.getRunningServiceNames(kernel, patterns);
+ if (services.size() == 0) {
+ waiting = true;
+ statusDescription = "WAITING: no targest " + getDescription() + ", patterns=" + getPatternsText();
+ log.debug(statusDescription);
+ return false;
+ } else if (services.size() > 1) {
+ waiting = true;
+ statusDescription = "WAITING: to many targets " + getDescription() + ", patterns=" + getPatternsText();
+ log.debug(statusDescription);
+ return false;
+ }
+
+ //
+ // ready to start
+ //
+ waiting = false;
+
+ // stop all services that would match our patterns from starting
+ dependencyManager.addStartHolds(objectName, patterns);
+
+ // add a dependency on our target
+ proxyTarget = (ObjectName) services.iterator().next();
+ dependencyManager.addDependency(objectName, proxyTarget);
+
+ statusDescription = "READY: " + getDescription();
+ }
+
+ return true;
+ }
+
+ public synchronized void stop() {
+ waiting = false;
+ ObjectName objectName = serviceInstance.getObjectName();
+ dependencyManager.removeStartHolds(objectName, patterns);
+
+ if (proxyTarget != null) {
+ dependencyManager.removeDependency(objectName, proxyTarget);
+ proxyTarget = null;
+ }
+
+ if (listener != null) {
+ kernel.removeLifecycleListener(listener);
+ listener = null;
+ }
+
+ statusDescription = "STOPPED: " + getDescription();
+ }
+
+ private synchronized void checkStatus() {
+ Set services = KernelUtil.getRunningServiceNames(kernel, patterns);
+
+ // if we are running, and we now have two valid targets, which is an illegal state so we need to fail
+ // todo fix me
+ if (serviceInstance.getState() == ServiceState.RUNNING_INDEX && services.size() != 1) {
+ serviceInstance.stop();
+ } else if (waiting) {
+ if (services.size() == 1) {
+ // the service was waiting for me and not there is now just one target
+ waiting = false;
+ serviceInstance.start();
+ }
+ }
+ }
+
+ private String getPatternsText() {
+ StringBuffer buf = new StringBuffer();
+ for (Iterator iterator = patterns.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ buf.append(objectName.getCanonicalName()).append(" ");
+ }
+ return buf.toString();
+ }
+
+ private String getDescription() {
+ return "depependency=" + name + ", serviceInstance " + serviceInstance.getObjectName().getCanonicalName();
+ }
+
+ private class DependencyLifecycleListener extends LifecycleAdapter {
+ public void running(ObjectName objectName) {
+ checkStatus();
+ }
+
+ public void stopped(ObjectName objectName) {
+ checkStatus();
+ }
+
+ public void unloaded(ObjectName objectName) {
+ checkStatus();
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/runtime/ServiceInstance.java b/kernel/src/java/org/gbean/kernel/runtime/ServiceInstance.java
new file mode 100644
index 0000000..4f7b2a6
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/runtime/ServiceInstance.java
@@ -0,0 +1,432 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.runtime;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.DependencyManager;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.service.ServiceContext;
+import org.gbean.service.ServiceFactory;
+
+/**
+ * @version $Rev: 106387 $ $Date: 2004-11-23 22:16:54 -0800 (Tue, 23 Nov 2004) $
+ */
+public final class ServiceInstance {
+ private static final Log log = LogFactory.getLog(ServiceInstance.class);
+
+ private static final int DESTROYED = 0;
+ private static final int CREATING = 1;
+ private static final int RUNNING = 2;
+ private static final int DESTROYING = 3;
+
+ /**
+ * The kernel in which this server is registered.
+ */
+ private final Kernel kernel;
+
+ /**
+ * The factory used to create the actual object instance.
+ */
+ private ServiceFactory serviceFactory;
+
+ /**
+ * This handles all state transiitions for this instance.
+ */
+ private final ServiceInstanceState serviceInstanceState;
+
+ /**
+ * The single listener to which we broadcast lifecycle change events.
+ */
+ private final LifecycleBroadcaster lifecycleBroadcaster;
+
+ /**
+ * The context given to the instance
+ */
+ private final ServiceContext serviceContext;
+
+ /**
+ * The classloader used for all invocations and creating targets.
+ */
+ private final ClassLoader classLoader;
+
+ /**
+ * Has this instance been destroyed?
+ */
+ private boolean dead = false;
+
+ /**
+ * The state of the internal service instance that we are wrapping.
+ */
+ private int instanceState = DESTROYED;
+
+ /**
+ * Target instance of this service instance
+ */
+ private Object target;
+
+ /**
+ * The time this application started.
+ */
+ private long startTime;
+
+ private Set dependencies;
+ private final ObjectName objectName;
+
+ public ServiceInstance(ObjectName objectName,
+ ServiceFactory serviceFactory,
+ Kernel kernel,
+ DependencyManager dependencyManager,
+ LifecycleBroadcaster lifecycleBroadcaster,
+ ClassLoader classLoader) {
+
+ this.objectName = objectName;
+ this.serviceFactory = serviceFactory;
+
+ // add the dependencies
+ Set tempDependencies = new HashSet();
+ for (Iterator iterator = serviceFactory.getDependencies().entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String dependencyName = (String) entry.getKey();
+ Set patterns = (Set) entry.getValue();
+ tempDependencies.add(new ServiceDependency(this, dependencyName, patterns, kernel, dependencyManager));
+ }
+ this.dependencies = Collections.unmodifiableSet(tempDependencies);
+
+ this.kernel = kernel;
+ this.lifecycleBroadcaster = lifecycleBroadcaster;
+ this.serviceInstanceState = new ServiceInstanceState(objectName, kernel, dependencyManager, this, lifecycleBroadcaster);
+ this.classLoader = classLoader;
+
+ serviceContext = new ServiceInstanceContext(this);
+ }
+
+ public void init() {
+ lifecycleBroadcaster.fireLoadedEvent();
+ }
+
+ public void destroy() throws ServiceNotFoundException {
+ synchronized (this) {
+ if (dead) {
+ // someone beat us to the punch... this instance should have never been found in the first place
+ throw new ServiceNotFoundException(objectName.getCanonicalName());
+ }
+ dead = true;
+ }
+
+ // if the bean is already stopped or failed, this will do nothing; otherwise it will shutdown the bean
+ serviceInstanceState.stop();
+
+ // tell everyone we are done
+ lifecycleBroadcaster.fireUnloadedEvent();
+ }
+
+ /**
+ * The kernel in which this instance is mounted
+ * @return the kernel
+ */
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ /**
+ * The class loader used to build this service. This class loader is set into the thread context
+ * class loader before callint the target instace.
+ *
+ * @return the class loader used to build this service
+ */
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public synchronized Object getInstance() {
+ return target;
+ }
+
+ /**
+ * Has this service instance been destroyed. An destroyed service can no longer be used.
+ *
+ * @return true if the service has been destroyed
+ */
+ public synchronized boolean isDead() {
+ return dead;
+ }
+
+ public final ObjectName getObjectName() {
+ return objectName;
+ }
+
+ public ServiceFactory getServiceFactory() {
+ return serviceFactory;
+ }
+
+ /**
+ * Is this service enabled. A disabled service can not be started.
+ *
+ * @return true if the service is enabled and can be started
+ */
+ public synchronized final boolean isEnabled() {
+ return serviceFactory.isEnabled();
+ }
+
+ /**
+ * Changes the enabled status.
+ *
+ * @param enabled the new enabled flag
+ */
+ public synchronized final void setEnabled(boolean enabled) {
+ serviceFactory.setEnabled(enabled);
+ }
+
+ public synchronized final long getStartTime() {
+ return startTime;
+ }
+
+ public int getState() {
+ return serviceInstanceState.getState();
+ }
+
+
+ /**
+ * Moves this service to the starting state and then attempts to move this service immediately
+ * to the running state.
+ *
+ * @throws IllegalStateException If the service is disabled
+ */
+ public final void start() {
+ synchronized (this) {
+ if (dead) {
+ throw new IllegalStateException("A dead service can not be started: objectName=" + objectName);
+ }
+ if (!isEnabled()) {
+ throw new IllegalStateException("A disabled service can not be started: objectName=" + objectName);
+ }
+ }
+ serviceInstanceState.start();
+ }
+
+ /**
+ * Starts this ServiceInstance and then attempts to start all of its start dependent children.
+ *
+ * @throws IllegalStateException If the service is disabled
+ */
+ public final void startRecursive() {
+ synchronized (this) {
+ if (dead) {
+ throw new IllegalStateException("A dead service can not be started: objectName=" + objectName);
+ }
+ if (!isEnabled()) {
+ throw new IllegalStateException("A disabled service can not be started: objectName=" + objectName);
+ }
+ }
+ serviceInstanceState.startRecursive();
+ }
+
+ /**
+ * Moves this service to the STOPPING state, calls stop on all start dependent children, and then attempt
+ * to move this service to the STOPPED state.
+ */
+ public final void stop() {
+ serviceInstanceState.stop();
+ }
+
+ boolean createInstance() throws Exception {
+ synchronized (this) {
+ // first check we are still in the correct state to start
+ if (instanceState == CREATING || instanceState == RUNNING) {
+ // another thread already completed starting
+ return false;
+ } else if (instanceState == DESTROYING) {
+ // this should never ever happen... this method is protected by the ServiceInstanceState class which should
+ // prevent stuff like this happening, but check anyway
+ throw new IllegalStateException("A stopping instance can not be started until fully stopped");
+ }
+ assert instanceState == DESTROYED;
+
+ // Call all start on every reference. This way the dependecies are held until we can start
+ boolean allStarted = true;
+ for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
+ ServiceDependency dependency = (ServiceDependency) iterator.next();
+ allStarted = dependency.start() && allStarted;
+ }
+ if (!allStarted) {
+ return false;
+ }
+
+ // we are definately going to (try to) start... if this fails the must clean up these variables
+ instanceState = CREATING;
+ startTime = System.currentTimeMillis();
+ }
+
+ Object instance = null;
+ try {
+ instance = serviceFactory.createService(serviceContext);
+
+ // all done... we are now fully running
+ synchronized (this) {
+ target = instance;
+ instanceState = RUNNING;
+ this.notifyAll();
+ }
+
+ return true;
+ } catch (Throwable t) {
+ // something went wrong... we need to destroy this instance
+ synchronized (this) {
+ instanceState = DESTROYING;
+ }
+
+ serviceFactory.destroyService(serviceContext, instance);
+
+ // bean has been notified... drop our reference
+ synchronized (this) {
+ for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
+ ServiceDependency dependency = (ServiceDependency) iterator.next();
+ dependency.stop();
+ }
+ target = null;
+ instanceState = DESTROYED;
+ startTime = 0;
+ this.notifyAll();
+ }
+
+ if (t instanceof Exception) {
+ throw (Exception) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else {
+ throw new Error(t);
+ }
+ }
+ }
+
+ boolean destroyInstance() throws Exception {
+ Object instance;
+ synchronized (this) {
+ // if the instance is being created we need to wait
+ // for it to finish before we can try to stop it
+ while (instanceState == CREATING) {
+ // todo should we limit this wait? If so, how do we configure the wait time?
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ // clear the interrupted flag
+ Thread.interrupted();
+ // rethrow the interrupted exception.... someone was sick of us waiting
+ throw e;
+ }
+ }
+
+ if (instanceState == DESTROYING || instanceState == DESTROYED) {
+ // another thread is already stopping or has already stopped
+ return false;
+ }
+ assert instanceState == RUNNING;
+
+ // we are definately going to stop... if this fails we must clean up these variables
+ instanceState = DESTROYING;
+ instance = target;
+ }
+
+ try {
+ // we notify the bean before removing our dependencies so the dependencies can be called back while stopping
+ serviceFactory.destroyService(serviceContext, instance);
+ } finally {
+ // bean has been notified... drop the dependencies
+ synchronized (this) {
+ for (Iterator iterator = dependencies.iterator(); iterator.hasNext();) {
+ ServiceDependency dependency = (ServiceDependency) iterator.next();
+ dependency.stop();
+ }
+ target = null;
+ instanceState = DESTROYED;
+ startTime = 0;
+ }
+ }
+ return true;
+ }
+
+ private static final class ServiceInstanceContext implements ServiceContext {
+ /**
+ * The ServiceInstance which owns the target.
+ */
+ private final ServiceInstance serviceInstance;
+
+ /**
+ * Creates a new context for a target.
+ *
+ * @param serviceInstance the ServiceInstance
+ */
+ public ServiceInstanceContext(ServiceInstance serviceInstance) {
+ this.serviceInstance = serviceInstance;
+ }
+
+ public Kernel getKernel() {
+ return serviceInstance.getKernel();
+ }
+
+ public String getObjectName() {
+ return serviceInstance.getObjectName().getCanonicalName();
+ }
+
+ public ClassLoader getClassLoader() {
+ return serviceInstance.getClassLoader();
+ }
+
+ public int getState() {
+ return serviceInstance.getState();
+ }
+
+ public void stop() throws Exception {
+ synchronized (serviceInstance) {
+ if (serviceInstance.instanceState == CREATING) {
+ throw new IllegalStateException("Stop can not be called until instance is fully started");
+ } else if (serviceInstance.instanceState == DESTROYING) {
+ log.debug("Stop ignored. Service is already being stopped");
+ return;
+ } else if (serviceInstance.instanceState == DESTROYED) {
+ log.debug("Stop ignored. Service is already stopped");
+ return;
+ }
+ }
+ serviceInstance.stop();
+ }
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) return true;
+ if (obj instanceof ServiceInstance == false) return false;
+ return objectName.equals(((ServiceInstance) obj).objectName);
+ }
+
+ public int hashCode() {
+ return objectName.hashCode();
+ }
+
+ public String toString() {
+ return objectName.getCanonicalName();
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/runtime/ServiceInstanceState.java b/kernel/src/java/org/gbean/kernel/runtime/ServiceInstanceState.java
new file mode 100644
index 0000000..dcd3bed
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/runtime/ServiceInstanceState.java
@@ -0,0 +1,437 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.runtime;
+
+import java.util.Iterator;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.DependencyManager;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.LifecycleAdapter;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public final class ServiceInstanceState {
+ private static final Log log = LogFactory.getLog(ServiceInstanceState.class);
+
+ /**
+ * The ServiceInstance in which this server is registered.
+ */
+ private final ServiceInstance serviceInstance;
+
+ /**
+ * The kernel in which this server is registered.
+ */
+ private final Kernel kernel;
+
+ /**
+ * The unique name of this service.
+ */
+ private final ObjectName objectName;
+
+ /**
+ * The dependency manager
+ */
+ private final DependencyManager dependencyManager;
+
+ /**
+ * The broadcaster of lifecycle events
+ */
+ private final LifecycleBroadcaster lifecycleBroadcaster;
+
+ /**
+ * The listener for the of the object blocking the start of this service.
+ * When the blocker dies we attempt to start.
+ */
+ private LifecycleListener blockerListener;
+
+ // This must be volatile otherwise getState must be synchronized which will result in deadlock as dependent
+ // objects check if each other are in one state or another (i.e., classic A calls B while B calls A)
+ private volatile ServiceState state = ServiceState.STOPPED;
+
+ ServiceInstanceState(ObjectName objectName, Kernel kernel, DependencyManager dependencyManager, ServiceInstance serviceInstance, LifecycleBroadcaster lifecycleBroadcaster) {
+ this.objectName = objectName;
+ this.kernel = kernel;
+ this.dependencyManager = dependencyManager;
+ this.serviceInstance = serviceInstance;
+ this.lifecycleBroadcaster = lifecycleBroadcaster;
+ }
+
+ /**
+ * Moves this service to the starting state and then attempts to move this service immediately
+ * to the running state.
+ * <p/>
+ * Note: This method cannot be called while the current thread holds a synchronized lock on this service,
+ * because this method sends lifecycle notifications. Sending a general notification from a synchronized block
+ * is a bad idea and therefore not allowed.
+ */
+ public void start() {
+ assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
+
+ // Move to the starting state
+ ServiceState originalState;
+ synchronized (this) {
+ originalState = getStateInstance();
+ if (originalState == ServiceState.RUNNING) {
+ return;
+ }
+ // only try to change states if we are not already starting
+ if (originalState != ServiceState.STARTING) {
+ setStateInstance(ServiceState.STARTING);
+ }
+ }
+
+ // only fire a notification if we are not already starting
+ if (originalState != ServiceState.STARTING) {
+ lifecycleBroadcaster.fireStartingEvent();
+ }
+
+ attemptFullStart();
+ }
+
+ /**
+ * Starts this service and then attempts to start all of its start dependent children.
+ * <p/>
+ * Note: This method cannot be call while the current thread holds a synchronized lock on this service,
+ * because this method sends lifecycle notifications. Sending a general notification from a synchronized block
+ * is a bad idea and therefore not allowed.
+ */
+ public void startRecursive() {
+ assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
+
+ ServiceState state = getStateInstance();
+ if (state != ServiceState.STOPPED) {
+ // Cannot startRecursive while in the stopping state
+ // Dain: I don't think we can throw an exception here because there is no way for the caller
+ // to lock the instance and check the state before calling
+ return;
+ }
+
+ // get myself starting
+ start();
+
+ // startRecursive all of objects that depend on me
+ Set dependents = dependencyManager.getChildren(objectName);
+ for (Iterator iterator = dependents.iterator(); iterator.hasNext();) {
+ ObjectName dependent = (ObjectName) iterator.next();
+ try {
+ if (kernel.isServiceEnabled(dependent)) {
+ kernel.startRecursiveService(dependent);
+ }
+ } catch (ServiceNotFoundException e) {
+ // this is ok the service died before we could start it
+ continue;
+ } catch (Exception e) {
+ // the is something wrong with this service... skip it
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Moves this service to the STOPPING state, calls stop on all start dependent children, and then attempt
+ * to move this service to the STOPPED state.
+ * <p/>
+ * Note: This method can not be call while the current thread holds a syncronized lock on this service,
+ * because this method sends lifecycle notifications. Sending a general notification from a synchronized block
+ * is a bad idea and therefore not allowed.
+ */
+ public void stop() {
+ assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
+
+ // move to the stopping state
+ ServiceState originalState;
+ synchronized (this) {
+ originalState = getStateInstance();
+ if (originalState == ServiceState.STOPPED) {
+ return;
+ }
+
+ // only try to change states if we are not already stopping
+ if (originalState != ServiceState.STOPPING) {
+ setStateInstance(ServiceState.STOPPING);
+ }
+ }
+
+ // only fire a notification if we are not already stopping
+ if (originalState != ServiceState.STOPPING) {
+ lifecycleBroadcaster.fireStoppingEvent();
+ }
+
+ // Don't try to stop dependents from within a synchronized block... this should reduce deadlocks
+
+ // stop all of my dependent objects
+ Set dependents = dependencyManager.getChildren(objectName);
+ for (Iterator iterator = dependents.iterator(); iterator.hasNext();) {
+ ObjectName child = (ObjectName) iterator.next();
+ try {
+ log.trace("Checking if child is running: child=" + child);
+ if (kernel.getServiceState(child) == ServiceState.RUNNING_INDEX) {
+ log.trace("Stopping child: child=" + child);
+ kernel.stopService(child);
+ log.trace("Stopped child: child=" + child);
+ }
+ } catch (Exception ignore) {
+ // not a big deal... did my best
+ }
+ }
+
+ attemptFullStop();
+ }
+
+ /**
+ * Attempts to bring the component into running state. If an Exception occurs while
+ * starting the component, the component will be failed.
+ * <p/>
+ * <p/>
+ * Note: Do not call this from within a synchronized block as it makes may send a lifecycle notification
+ */
+ void attemptFullStart() {
+ assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
+
+ synchronized (this) {
+ // if we are still trying to start and can start now... start
+ if (getStateInstance() != ServiceState.STARTING) {
+ return;
+ }
+
+ if (blockerListener != null) {
+ log.trace("Cannot run because service is still being blocked");
+ return;
+ }
+
+ // check if an service is blocking us from starting
+ final ObjectName blocker = dependencyManager.checkBlocker(objectName);
+ if (blocker != null) {
+ blockerListener = new LifecycleAdapter() {
+
+ public void stopped(ObjectName objectName) {
+ checkBlocker(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ checkBlocker(objectName);
+ }
+
+ private void checkBlocker(ObjectName objectName) {
+ synchronized (ServiceInstanceState.this) {
+ if (!objectName.equals(blocker)) {
+ // it did not start so just exit this method
+ return;
+ }
+
+ // it started, so remove the blocker and attempt a full start
+ kernel.removeLifecycleListener(this);
+ ServiceInstanceState.this.blockerListener = null;
+ }
+
+ try {
+ attemptFullStart();
+ } catch (Exception e) {
+ log.warn("A problem occured while attempting to start", e);
+ }
+ }
+ };
+ // register the listener and return
+ kernel.addLifecycleListener(blockerListener, blocker);
+ return;
+ }
+
+ // check if all of the services we depend on are running
+ Set parents = dependencyManager.getParents(objectName);
+ for (Iterator i = parents.iterator(); i.hasNext();) {
+ ObjectName parent = (ObjectName) i.next();
+ if (!kernel.isLoaded(parent)) {
+ log.trace("Cannot run because parent is not registered: parent=" + parent);
+ return;
+ }
+ try {
+ log.trace("Checking if parent is running: parent=" + parent);
+ if (kernel.getServiceState(parent) != ServiceState.RUNNING_INDEX) {
+ log.trace("Cannot run because parent is not running: parent=" + parent);
+ return;
+ }
+ log.trace("Parent is running: parent=" + parent);
+ } catch (ServiceNotFoundException e) {
+ // depended on instance was removed bewteen the register check and the invoke
+ log.trace("Cannot run because parent is not registered: parent=" + parent);
+ return;
+ } catch (Exception e) {
+ // problem getting the attribute, parent has most likely failed
+ log.trace("Cannot run because an error occurred while checking if parent is running: parent=" + parent);
+ return;
+ }
+ }
+ }
+
+ try {
+ // try to create the instance
+ if (!serviceInstance.createInstance()) {
+ // instance is not ready to start... this is normally caused by references
+ // not being available, but could be because someone alreayd started the service.
+ // in another thread. The reference will log a debug message about why
+ // it could not start
+ return;
+ }
+ } catch (Throwable t) {
+ // oops there was a problem, stop the service
+ setStateInstance(ServiceState.STOPPING);
+ lifecycleBroadcaster.fireStoppingEvent();
+ setStateInstance(ServiceState.STOPPED);
+ lifecycleBroadcaster.fireStoppedEvent();
+
+ log.error("Error while starting; Service is now in the STOPPED state: objectName=\"" + objectName + "\"", t);
+ return;
+ }
+
+ // started successfully... notify everyone else
+ setStateInstance(ServiceState.RUNNING);
+ lifecycleBroadcaster.fireRunningEvent();
+ }
+
+ /**
+ * Attempt to bring the component into the fully stopped state.
+ * If an exception occurs while stopping the component, the component will be failed.
+ * <p/>
+ * <p/>
+ * Note: Do not call this from within a synchronized block as it may send a lifecycle notification
+ */
+ void attemptFullStop() {
+ assert !Thread.holdsLock(this): "This method cannot be called while holding a synchronized lock on this";
+
+ // check if we are able to stop
+ synchronized (this) {
+ // if we are still trying to stop...
+ if (getStateInstance() != ServiceState.STOPPING) {
+ return;
+ }
+
+ // check if all of the service depending on us are stopped
+ Set children = dependencyManager.getChildren(objectName);
+ for (Iterator i = children.iterator(); i.hasNext();) {
+ ObjectName child = (ObjectName) i.next();
+ if (kernel.isLoaded(child)) {
+ try {
+ log.trace("Checking if child is stopped: child=" + child);
+ int state = kernel.getServiceState(child);
+ if (state == ServiceState.RUNNING_INDEX) {
+ log.trace("Cannot stop because child is still running: child=" + child);
+ return;
+ }
+ } catch (ServiceNotFoundException e) {
+ // depended on instance was removed between the register check and the invoke
+ } catch (Exception e) {
+ // problem getting the attribute, depended on bean has most likely failed
+ log.trace("Cannot run because an error occurred while checking if child is stopped: child=" + child);
+ return;
+ }
+ }
+ }
+ }
+
+ // all is clear to stop... try to stop
+ try {
+ if (!serviceInstance.destroyInstance()) {
+ // instance is not ready to stop... this is because another thread has
+ // already stopped the service.
+ return;
+ }
+ } catch (Throwable t) {
+ log.error("Error while stopping; Service is now in the STOPPED state: objectName=\"" + objectName + "\"", t);
+ } finally {
+ // we are always stopped at this point
+ setStateInstance(ServiceState.STOPPED);
+ lifecycleBroadcaster.fireStoppedEvent();
+ }
+ }
+
+ public int getState() {
+ return state.getIndex();
+ }
+
+ public ServiceState getStateInstance() {
+ return state;
+ }
+
+ /**
+ * Set the Component state.
+ *
+ * @param newState the target state to transition
+ * @throws IllegalStateException Thrown if the transition is not supported by the lifecycle contract.
+ */
+ private synchronized void setStateInstance(ServiceState newState) throws IllegalStateException {
+ switch (state.getIndex()) {
+ case ServiceState.STOPPED_INDEX:
+ switch (newState.getIndex()) {
+ case ServiceState.STARTING_INDEX:
+ break;
+ case ServiceState.STOPPED_INDEX:
+ case ServiceState.RUNNING_INDEX:
+ case ServiceState.STOPPING_INDEX:
+ throw new IllegalStateException("Cannot transition to " + newState + " state from " + state);
+ }
+ break;
+
+ case ServiceState.STARTING_INDEX:
+ switch (newState.getIndex()) {
+ case ServiceState.RUNNING_INDEX:
+ case ServiceState.STOPPING_INDEX:
+ break;
+ case ServiceState.STOPPED_INDEX:
+ case ServiceState.STARTING_INDEX:
+ throw new IllegalStateException("Cannot transition to " + newState + " state from " + state);
+ }
+ break;
+
+ case ServiceState.RUNNING_INDEX:
+ switch (newState.getIndex()) {
+ case ServiceState.STOPPING_INDEX:
+ break;
+ case ServiceState.STOPPED_INDEX:
+ case ServiceState.STARTING_INDEX:
+ case ServiceState.RUNNING_INDEX:
+ throw new IllegalStateException("Cannot transition to " + newState + " state from " + state);
+ }
+ break;
+
+ case ServiceState.STOPPING_INDEX:
+ switch (newState.getIndex()) {
+ case ServiceState.STOPPED_INDEX:
+ break;
+ case ServiceState.STARTING_INDEX:
+ case ServiceState.RUNNING_INDEX:
+ case ServiceState.STOPPING_INDEX:
+ throw new IllegalStateException("Cannot transition to " + newState + " state from " + state);
+ }
+ break;
+
+ }
+ log.debug(toString() + " State changed from " + state + " to " + newState);
+ state = newState;
+ }
+
+ public String toString() {
+ return "ServiceInstanceState for: " + objectName;
+ }
+
+}
diff --git a/kernel/src/java/org/gbean/kernel/runtime/ServiceState.java b/kernel/src/java/org/gbean/kernel/runtime/ServiceState.java
new file mode 100644
index 0000000..ff04f06
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/runtime/ServiceState.java
@@ -0,0 +1,91 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.runtime;
+
+import java.io.Serializable;
+
+/**
+ * @version $Rev: 54804 $ $Date: 2004-10-14 14:09:29 -0700 (Thu, 14 Oct 2004) $
+ */
+public final class ServiceState implements Serializable {
+ public static final int STARTING_INDEX = 0;
+ public static final int RUNNING_INDEX = 1;
+ public static final int STOPPING_INDEX = 2;
+ public static final int STOPPED_INDEX = 3;
+
+ public static final ServiceState STARTING = new ServiceState("starting", STARTING_INDEX);
+ public static final ServiceState RUNNING = new ServiceState("running", RUNNING_INDEX);
+ public static final ServiceState STOPPING = new ServiceState("stopping", STOPPING_INDEX);
+ public static final ServiceState STOPPED = new ServiceState("stopped", STOPPED_INDEX);
+
+ private static final ServiceState[] fromInt = {STARTING, RUNNING, STOPPING, STOPPED};
+
+ /**
+ * Get a State from an int index
+ *
+ * @param index int index of the state
+ * @return The State instance or null if no such State.
+ */
+ public static ServiceState fromIndex(int index) {
+ if (index < 0 || index >= fromInt.length) {
+ return null;
+ }
+ return fromInt[index];
+ }
+
+ public static String toString(int state) {
+ if (state < 0 || state >= fromInt.length) {
+ throw new IllegalArgumentException("State must be between 0 and " + fromInt.length);
+ }
+ return fromInt[state].name;
+ }
+
+ /**
+ * The user readable name of this state.
+ */
+ private final String name;
+
+ /**
+ * The index of this state.
+ */
+ private final int index;
+
+ private ServiceState(String name, int index) {
+ this.name = name;
+ this.index = index;
+ }
+
+ /**
+ * Gets the integer index value of this state
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+ private Object readResolve() {
+ return fromInt[index];
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleDependencyManager.java b/kernel/src/java/org/gbean/kernel/simple/SimpleDependencyManager.java
new file mode 100644
index 0000000..32f9a91
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleDependencyManager.java
@@ -0,0 +1,278 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.DependencyManager;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.ServiceName;
+
+/**
+ * DependencyManager is the record keeper of the dependencies in the kernel. The DependencyManager
+ * does not enforce any dependencies, it is simply a place where components can register their intent
+ * to be dependent on another component. Since a service can pretty much do whatever it wants
+ * a service must watch the services it depends on to assure that they are following the
+ * lifecycle contract.
+ * <p/>
+ * The DependencyManager uses the nomenclature of parent-child where a child is dependent on a parent.
+ * The names parent and child have no other meaning are just a convience to make the code readable.
+ *
+ * @version $Rev: 124822 $ $Date: 2005-01-10 11:01:13 -0800 (Mon, 10 Jan 2005) $
+ */
+public class SimpleDependencyManager implements DependencyManager {
+ /**
+ * The lifecycleMonitor informs us when services go off line,
+ * so we can clean up the lingering dependencies.
+ */
+ private final Kernel kernel;
+
+ /**
+ * Listenes for services to unregister and removes all dependencies associated with the dependency
+ */
+ private final LifecycleListener lifecycleListener = new DependencyManagerLifecycleListener();
+
+ /**
+ * A map from child names to a list of parents.
+ */
+ private final Map childToParentMap = new HashMap();
+
+ /**
+ * A map from parent back to a list of its children.
+ */
+ private final Map parentToChildMap = new HashMap();
+
+ /**
+ * A map from a component's ObjectName to the list of ObjectPatterns that the component is blocking
+ * from starting.
+ */
+ private final Map startHoldsMap = new HashMap();
+
+ private static final ObjectName ALL = ServiceName.createName("*:*");
+
+ public SimpleDependencyManager(Kernel kernel) {
+ assert kernel != null;
+ this.kernel = kernel;
+ }
+
+ // todo throw illegal state from all methods when not started
+ public synchronized void start() {
+ this.kernel.addLifecycleListener(lifecycleListener, ALL);
+ }
+ public synchronized void stop() {
+ kernel.removeLifecycleListener(lifecycleListener);
+ childToParentMap.clear();
+ parentToChildMap.clear();
+ startHoldsMap.clear();
+ }
+
+ /**
+ * Declares a dependency from a child to a parent.
+ *
+ * @param child the dependent component
+ * @param parent the component the child is depending on
+ */
+ public synchronized void addDependency(ObjectName child, ObjectName parent) {
+ Set parents = (Set) childToParentMap.get(child);
+ if (parents == null) {
+ parents = new HashSet();
+ childToParentMap.put(child, parents);
+ }
+ parents.add(parent);
+
+ Set children = (Set) parentToChildMap.get(parent);
+ if (children == null) {
+ children = new HashSet();
+ parentToChildMap.put(parent, children);
+ }
+ children.add(child);
+ }
+
+ /**
+ * Removes a dependency from a child to a parent
+ *
+ * @param child the dependnet component
+ * @param parent the component that the child wil no longer depend on
+ */
+ public synchronized void removeDependency(ObjectName child, ObjectName parent) {
+ Set parents = (Set) childToParentMap.get(child);
+ if (parents != null) {
+ parents.remove(parent);
+ }
+
+ Set children = (Set) parentToChildMap.get(parent);
+ if (children != null) {
+ children.remove(child);
+ }
+ }
+
+ /**
+ * Removes all dependencies for a child
+ *
+ * @param child the component that will no longer depend on anything
+ */
+ public synchronized void removeAllDependencies(ObjectName child) {
+ Set parents = (Set) childToParentMap.remove(child);
+ if (parents == null) {
+ return;
+ }
+ for (Iterator iterator = parents.iterator(); iterator.hasNext();) {
+ ObjectName parent = (ObjectName) iterator.next();
+ Set children = (Set) parentToChildMap.get(parent);
+ if (children != null) {
+ children.remove(child);
+ }
+
+ }
+ }
+
+ /**
+ * Adds dependencies from the child to every parent in the parents set
+ *
+ * @param child the dependent component
+ * @param parents the set of components the child is depending on
+ */
+ public synchronized void addDependencies(ObjectName child, Set parents) {
+ Set existingParents = (Set) childToParentMap.get(child);
+ if (existingParents == null) {
+ existingParents = new HashSet(parents);
+ childToParentMap.put(child, existingParents);
+ } else {
+ existingParents.addAll(parents);
+ }
+
+ for (Iterator i = parents.iterator(); i.hasNext();) {
+ Object startParent = i.next();
+ Set children = (Set) parentToChildMap.get(startParent);
+ if (children == null) {
+ children = new HashSet();
+ parentToChildMap.put(startParent, children);
+ }
+ children.add(child);
+ }
+ }
+
+ /**
+ * Gets the set of parents that the child is depending on
+ *
+ * @param child the dependent component
+ * @return a collection containing all of the components the child depends on; will never be null
+ */
+ public synchronized Set getParents(ObjectName child) {
+ Set parents = (Set) childToParentMap.get(child);
+ if (parents == null) {
+ return Collections.EMPTY_SET;
+ }
+ return new HashSet(parents);
+ }
+
+ /**
+ * Gets all of the services that have a dependency on the specified startParent.
+ *
+ * @param parent the component the returned childen set depend on
+ * @return a collection containing all of the components that depend on the parent; will never be null
+ */
+ public synchronized Set getChildren(ObjectName parent) {
+ Set children = (Set) parentToChildMap.get(parent);
+ if (children == null) {
+ return Collections.EMPTY_SET;
+ }
+ return new HashSet(children);
+ }
+
+ /**
+ * Adds a hold on a collection of object name patterns. If the name of a component matches an object name
+ * pattern in the collection, the component should not start.
+ *
+ * @param objectName the name of the component placing the holds
+ * @param holds a collection of object name patterns which should not start
+ */
+ public synchronized void addStartHolds(ObjectName objectName, Collection holds) {
+ Collection currentHolds = (Collection) startHoldsMap.get(objectName);
+ if (currentHolds == null) {
+ currentHolds = new LinkedList(holds);
+ startHoldsMap.put(objectName, currentHolds);
+ } else {
+ currentHolds.addAll(holds);
+ }
+ }
+
+ /**
+ * Removes a collection of holds.
+ *
+ * @param objectName the object name of the components owning the holds
+ * @param holds a collection of the holds to remove
+ */
+ public synchronized void removeStartHolds(ObjectName objectName, Collection holds) {
+ Collection currentHolds = (Collection) startHoldsMap.get(objectName);
+ if (currentHolds != null) {
+ currentHolds.removeAll(holds);
+ }
+ }
+
+ /**
+ * Removes all of the holds owned by a component.
+ *
+ * @param objectName the object name of the component that will no longer have any holds
+ */
+ public synchronized void removeAllStartHolds(ObjectName objectName) {
+ startHoldsMap.remove(objectName);
+ }
+
+ /**
+ * Gets the object name of the service blocking the start specified service.
+ *
+ * @param objectName the service to check for blockers
+ * @return the service blocking the specified service, or null if there are no blockers
+ */
+ public synchronized ObjectName checkBlocker(ObjectName objectName) {
+ // check if objectName name is on one of the hold lists
+ for (Iterator iterator = startHoldsMap.keySet().iterator(); iterator.hasNext();) {
+ ObjectName blocker = (ObjectName) iterator.next();
+ List holds = (List) startHoldsMap.get(blocker);
+ for (Iterator holdsIterator = holds.iterator(); holdsIterator.hasNext();) {
+ ObjectName pattern = (ObjectName) holdsIterator.next();
+ if (pattern.apply(objectName)) {
+ return blocker;
+ }
+ }
+ }
+ return null;
+ }
+
+ private class DependencyManagerLifecycleListener extends LifecycleAdapter {
+ public void unloaded(ObjectName objectName) {
+ synchronized (SimpleDependencyManager.this) {
+ removeAllDependencies(objectName);
+ removeAllStartHolds(objectName);
+ }
+
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleKernel.java b/kernel/src/java/org/gbean/kernel/simple/SimpleKernel.java
new file mode 100644
index 0000000..f390560
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleKernel.java
@@ -0,0 +1,328 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.DependencyManager;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.KernelRegistry;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.ServiceAlreadyExistsException;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.runtime.ServiceInstance;
+import org.gbean.service.AbstractServiceFactory;
+import org.gbean.service.ServiceContext;
+import org.gbean.service.ServiceFactory;
+
+
+/**
+ * @version $Rev: 154947 $ $Date: 2005-02-22 20:10:45 -0800 (Tue, 22 Feb 2005) $
+ */
+public class SimpleKernel implements Kernel {
+ /**
+ * Name of this kernel
+ */
+ private final String kernelName;
+
+ /**
+ * The log
+ */
+ private Log log;
+
+ /**
+ * Is this kernel running?
+ */
+ private boolean running;
+
+ /**
+ * The timestamp when the kernel was started
+ */
+ private Date bootTime;
+
+ /**
+ * The simple registry
+ */
+ private final SimpleRegistry registry;
+
+ /**
+ * Listeners for when the kernel shutdown
+ */
+ private final LinkedList shutdownHooks = new LinkedList();
+
+ /**
+ * This manager is used by the kernel to manage dependencies between services
+ */
+ private final DependencyManager dependencyManager;
+
+ /**
+ * Monitors the lifecycle of all services.
+ */
+ private final SimpleLifecycleMonitor lifecycleMonitor;
+
+ /**
+ * Construct a Kernel with the specified name.
+ *
+ * @param kernelName the name of the kernel
+ */
+ public SimpleKernel(String kernelName) {
+ if (kernelName.indexOf(':') >= 0 || kernelName.indexOf('*') >= 0 || kernelName.indexOf('?') >= 0) {
+ throw new IllegalArgumentException("Kernel name may not contain a ':', '*' or '?' character");
+ }
+ this.kernelName = kernelName;
+ lifecycleMonitor = new SimpleLifecycleMonitor();
+ this.registry = new SimpleRegistry(kernelName);
+ dependencyManager = new SimpleDependencyManager(this);
+ }
+
+ public String getKernelName() {
+ return kernelName;
+ }
+
+ /**
+ * @deprecated Do not use. This is only here for the geronimo bridge and will go away as soon as possible.
+ */
+ public DependencyManager getDependencyManager() {
+ return dependencyManager;
+ }
+
+ public boolean isLoaded(ObjectName name) {
+ return registry.isRegistered(name);
+ }
+
+ public void loadService(ObjectName objectName, ServiceFactory serviceFactory, ClassLoader classLoader) throws ServiceAlreadyExistsException {
+ ServiceInstance serviceInstance = new ServiceInstance(objectName,
+ serviceFactory,
+ this,
+ dependencyManager,
+ lifecycleMonitor.createLifecycleBroadcaster(objectName),
+ classLoader);
+ registry.register(objectName, serviceInstance);
+ serviceInstance.init();
+ }
+
+ public void startService(ObjectName name) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ serviceInstance.start();
+ }
+
+ public void startRecursiveService(ObjectName name) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ serviceInstance.startRecursive();
+ }
+
+ public void stopService(ObjectName name) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ serviceInstance.stop();
+ }
+
+ public void unloadService(ObjectName name) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ serviceInstance.destroy();
+ registry.unregister(name);
+ }
+
+ public Object getService(ObjectName name) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ Object instance = serviceInstance.getInstance();
+ if (instance == null) {
+ throw new IllegalStateException("Service is not running: " + name);
+ }
+ return instance;
+ }
+
+ public ServiceFactory getServiceFactory(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ return serviceInstance.getServiceFactory();
+ }
+
+ public int getServiceState(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ return serviceInstance.getState();
+ }
+
+ public long getServiceStartTime(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ return serviceInstance.getStartTime();
+ }
+
+ public boolean isServiceEnabled(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ return serviceInstance.isEnabled();
+ }
+
+ public void setServiceEnabled(ObjectName name, boolean enabled) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ serviceInstance.setEnabled(enabled);
+ }
+
+ public Collection listServices(ObjectName pattern) {
+ Set serviceInstances = registry.listServiceInstances(pattern);
+ ArrayList services = new ArrayList(serviceInstances.size());
+ for (Iterator iterator = serviceInstances.iterator(); iterator.hasNext();) {
+ ServiceInstance serviceInstance = (ServiceInstance) iterator.next();
+ Object service = serviceInstance.getInstance();
+ if (service != null) {
+ services.add(service);
+ }
+ }
+ return services;
+ }
+
+ public Set listServices(Set patterns) {
+ Set services = new HashSet();
+ for (Iterator iterator = patterns.iterator(); iterator.hasNext();) {
+ ObjectName pattern = (ObjectName) iterator.next();
+ services.addAll(listServices(pattern));
+ }
+ return services;
+ }
+
+ public Set listServiceNames(ObjectName pattern) {
+ return registry.listServiceNames(pattern);
+ }
+
+ public Set listServiceNames(Set patterns) {
+ Set services = new HashSet();
+ for (Iterator iterator = patterns.iterator(); iterator.hasNext();) {
+ ObjectName pattern = (ObjectName) iterator.next();
+ services.addAll(listServiceNames(pattern));
+ }
+ return services;
+ }
+
+ public void addLifecycleListener(LifecycleListener lifecycleListener, ObjectName pattern) {
+ addLifecycleListener(lifecycleListener, Collections.singleton(pattern));
+ }
+
+ public void addLifecycleListener(LifecycleListener lifecycleListener, Set patterns) {
+ lifecycleMonitor.addLifecycleListener(lifecycleListener, patterns);
+ }
+
+ public void removeLifecycleListener(LifecycleListener lifecycleListener) {
+ lifecycleMonitor.removeLifecycleListener(lifecycleListener);
+ }
+
+ /**
+ * Boot this Kernel
+ *
+ * @throws Exception if the boot fails
+ */
+ public void boot() throws Exception {
+ if (running) {
+ return;
+ }
+ bootTime = new Date();
+ log = LogFactory.getLog(SimpleKernel.class.getName());
+ log.info("Starting boot");
+
+ lifecycleMonitor.start();
+ registry.start();
+ dependencyManager.start();
+
+ // mount the kernel into the kernel itself so it can be accessed just like
+ // any other service in the system
+ ServiceFactory kernelServiceFactory = new AbstractServiceFactory() {
+ public Object createService(ServiceContext serviceContext) throws Exception {
+ return SimpleKernel.this;
+ }
+ };
+ loadService(KERNEL, kernelServiceFactory, getClass().getClassLoader());
+ startService(KERNEL);
+
+ running = true;
+ log.info("Booted");
+
+ KernelRegistry.registerKernel(this);
+ }
+
+ public Date getBootTime() {
+ return bootTime;
+ }
+
+ public void registerShutdownHook(Runnable hook) {
+ assert hook != null : "Shutdown hook was null";
+ synchronized (shutdownHooks) {
+ shutdownHooks.add(hook);
+ }
+ }
+
+ public void unregisterShutdownHook(Runnable hook) {
+ synchronized (shutdownHooks) {
+ shutdownHooks.remove(hook);
+ }
+ }
+
+ /**
+ * Shutdown this kernel
+ */
+ public void shutdown() {
+ if (!running) {
+ return;
+ }
+ running = false;
+ log.info("Starting kernel shutdown");
+
+ notifyShutdownHooks();
+
+ dependencyManager.stop();
+ registry.stop();
+ lifecycleMonitor.stop();
+
+ synchronized (this) {
+ notify();
+ }
+
+ KernelRegistry.unregisterKernel(this);
+
+ log.info("Kernel shutdown complete");
+ }
+
+ private void notifyShutdownHooks() {
+ while (!shutdownHooks.isEmpty()) {
+ Runnable hook;
+ synchronized (shutdownHooks) {
+ hook = (Runnable) shutdownHooks.removeLast();
+ }
+ try {
+ hook.run();
+ } catch (Throwable e) {
+ log.warn("Error from kernel shutdown hook", e);
+ }
+ }
+ }
+
+ public boolean isRunning() {
+ return running;
+ }
+
+ public ClassLoader getClassLoaderFor(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance = registry.getServiceInstance(name);
+ return serviceInstance.getClassLoader();
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleKernelFactory.java b/kernel/src/java/org/gbean/kernel/simple/SimpleKernelFactory.java
new file mode 100644
index 0000000..e0d127d
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleKernelFactory.java
@@ -0,0 +1,29 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import org.gbean.kernel.KernelFactory;
+import org.gbean.kernel.Kernel;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleKernelFactory extends KernelFactory {
+ public Kernel createKernel(String kernelName) {
+ return new SimpleKernel(kernelName);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycle.java b/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycle.java
new file mode 100644
index 0000000..cbd0b63
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycle.java
@@ -0,0 +1,26 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface SimpleLifecycle {
+ void start() throws Exception;
+
+ void stop();
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycleMonitor.java b/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycleMonitor.java
new file mode 100644
index 0000000..8f12ad2
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleLifecycleMonitor.java
@@ -0,0 +1,241 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.LifecycleListener;
+import org.gbean.kernel.runtime.LifecycleBroadcaster;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class SimpleLifecycleMonitor {
+ private static final Log log = LogFactory.getLog(SimpleLifecycleMonitor.class);
+
+ private final Map boundListeners = new LinkedHashMap();
+ private final Map listenerPatterns = new LinkedHashMap();
+
+ public void start() {
+ }
+
+ /**
+ * Frees all resources associated with the monitor. No futher events will be processed.
+ */
+ public synchronized void stop() {
+ boundListeners.clear();
+ listenerPatterns.clear();
+ }
+
+ /**
+ * Create a lifecycle broadcaster for the specified bean. This is typically given to the
+ * instance manager to broadcast lifecycle changes
+ * @param objectName the name of the object for which a broadcaster should be created
+ * @return the lifecycle broadcaster
+ */
+ public LifecycleBroadcaster createLifecycleBroadcaster(ObjectName objectName) {
+ return new SimpleLifecycleBroadcaster(objectName);
+ }
+
+ /**
+ * Registers a listener to revieve life cycle events for a set of object name patterns.
+ * @param listener the listener that will receive life cycle events
+ * @param patterns a set of ObjectName patterns
+ */
+ public synchronized void addLifecycleListener(LifecycleListener listener, Set patterns) {
+ for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
+ ObjectName pattern = (ObjectName) patternIterator.next();
+ for (Iterator iterator = boundListeners.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ ObjectName source = (ObjectName) entry.getKey();
+ if (pattern.apply(source)) {
+ List listeners = (List) entry.getValue();
+ listeners.add(listener);
+ }
+ }
+ }
+ listenerPatterns.put(listener, patterns);
+ }
+
+ /**
+ * Removes the listener from all notifications.
+ * @param listener the listener to unregister
+ */
+ public synchronized void removeLifecycleListener(LifecycleListener listener) {
+ for (Iterator iterator = boundListeners.values().iterator(); iterator.hasNext();) {
+ List listeners = (List) iterator.next();
+ listeners.remove(listener);
+ }
+ listenerPatterns.remove(listener);
+ }
+
+ private synchronized void addSource(ObjectName source) {
+ if (boundListeners.containsKey(source)) {
+ // alreayd registered
+ return;
+ }
+
+ // find all listeners interested in events from this source
+ List listeners = new LinkedList();
+ for (Iterator listenerIterator = listenerPatterns.entrySet().iterator(); listenerIterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) listenerIterator.next();
+ Set patterns = (Set) entry.getValue();
+ for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
+ ObjectName pattern = (ObjectName) patternIterator.next();
+ if (pattern.apply(source)) {
+ LifecycleListener listener = (LifecycleListener) entry.getKey();
+ listeners.add(listener);
+ }
+ }
+ }
+
+ boundListeners.put(source, listeners);
+ }
+
+ private synchronized void removeSource(ObjectName source) {
+ boundListeners.remove(source);
+ }
+
+ private synchronized List getTargets(ObjectName source) {
+ List targets = (List) boundListeners.get(source);
+ if (targets == null) {
+ // no one is interested in this event
+ return Collections.EMPTY_LIST;
+ } else {
+ return new LinkedList(targets);
+ }
+ }
+
+ private void fireLoadedEvent(ObjectName objectName) {
+ List targets = getTargets(objectName);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.loaded(objectName);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private void fireStartingEvent(ObjectName source) {
+ List targets = getTargets(source);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.starting(source);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private void fireRunningEvent(ObjectName source) {
+ List targets = getTargets(source);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.running(source);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private void fireStoppingEvent(ObjectName source) {
+ List targets = getTargets(source);
+ Collections.reverse(targets);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.stopping(source);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private void fireStoppedEvent(ObjectName source) {
+ List targets = getTargets(source);
+ Collections.reverse(targets);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.stopped(source);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private void fireUnloadedEvent(ObjectName source) {
+ List targets = getTargets(source);
+ Collections.reverse(targets);
+ for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+ LifecycleListener listener = (LifecycleListener) iterator.next();
+ try {
+ listener.unloaded(source);
+ } catch (Throwable e) {
+ log.warn("Exception occured while notifying listener", e);
+ }
+ }
+ }
+
+ private class SimpleLifecycleBroadcaster implements LifecycleBroadcaster {
+ private final ObjectName objectName;
+
+ public SimpleLifecycleBroadcaster(ObjectName objectName) {
+ this.objectName = objectName;
+ }
+
+ public void fireLoadedEvent() {
+ addSource(objectName);
+ SimpleLifecycleMonitor.this.fireLoadedEvent(objectName);
+ }
+
+ public void fireStartingEvent() {
+ SimpleLifecycleMonitor.this.fireStartingEvent(objectName);
+ }
+
+ public void fireRunningEvent() {
+ SimpleLifecycleMonitor.this.fireRunningEvent(objectName);
+ }
+
+ public void fireStoppingEvent() {
+ SimpleLifecycleMonitor.this.fireStoppingEvent(objectName);
+ }
+
+ public void fireStoppedEvent() {
+ SimpleLifecycleMonitor.this.fireStoppedEvent(objectName);
+ }
+
+ public void fireUnloadedEvent() {
+ SimpleLifecycleMonitor.this.fireUnloadedEvent(objectName);
+ removeSource(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleRegistry.java b/kernel/src/java/org/gbean/kernel/simple/SimpleRegistry.java
new file mode 100644
index 0000000..5b155b1
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleRegistry.java
@@ -0,0 +1,249 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+import javax.management.ObjectName;
+
+import org.gbean.kernel.runtime.ServiceInstance;
+import org.gbean.kernel.ServiceAlreadyExistsException;
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class SimpleRegistry {
+ private final Map registry = new HashMap();
+ private final Map domainIndex = new HashMap();
+ private String defaultDomainName;
+
+ public SimpleRegistry(String defaultDomainName) {
+ this.defaultDomainName = defaultDomainName;
+ }
+
+ public void start() {
+ }
+
+ public void stop() {
+ synchronized (this) {
+ registry.clear();
+ domainIndex.clear();
+ }
+ }
+
+ public boolean isRegistered(ObjectName name) {
+ synchronized (this) {
+ return registry.containsKey(name);
+ }
+ }
+
+ public void register(ObjectName objectName, ServiceInstance serviceInstance) throws ServiceAlreadyExistsException {
+ // do as much work as possible outside of the synchronized block
+ ObjectName name = serviceInstance.getObjectName();
+ String domainName = name.getDomain();
+ if (domainName.length() == 0) {
+ domainName = defaultDomainName;
+ }
+
+ // convert properties list to a HashMap as it is more efficient then the synchronized Hashtable
+ Map properties = new HashMap(name.getKeyPropertyList());
+
+ synchronized (this) {
+ registry.put(name, serviceInstance);
+
+ Map nameToProperties = (Map) domainIndex.get(domainName);
+ if (nameToProperties == null) {
+ nameToProperties = new HashMap();
+ domainIndex.put(domainName, nameToProperties);
+ }
+ nameToProperties.put(name, properties);
+ }
+ }
+
+ public void unregister(ObjectName name) throws ServiceNotFoundException {
+ String domainName = name.getDomain();
+ synchronized (this) {
+ registry.remove(name);
+
+ // just leave the an empty nameToProperty map
+ Map nameToProperties = (Map) domainIndex.get(domainName);
+ if (nameToProperties != null) {
+ nameToProperties.remove(name);
+ }
+ }
+ }
+
+ public ServiceInstance getServiceInstance(ObjectName name) throws ServiceNotFoundException {
+ ServiceInstance serviceInstance;
+ synchronized (this) {
+ serviceInstance = (ServiceInstance) registry.get(name);
+ }
+ if (serviceInstance == null) {
+ throw new ServiceNotFoundException(name.getCanonicalName());
+ }
+ return serviceInstance;
+ }
+
+ public Set listServiceInstances(ObjectName pattern) {
+ Set serviceNames = listServiceNames(pattern);
+ HashSet serviceInstances = new HashSet(serviceNames.size());
+ synchronized (this) {
+ for (Iterator iterator = serviceNames.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ ServiceInstance serviceInstance = (ServiceInstance) registry.get(objectName);
+ if (serviceInstance != null) {
+ serviceInstances.add(serviceInstance);
+ }
+ }
+ }
+ return serviceInstances;
+ }
+
+ public Set listServiceNames(ObjectName pattern) {
+ if (pattern == null) {
+ synchronized (this) {
+ return new HashSet(registry.keySet());
+ }
+ }
+
+ String patternDomain = pattern.getDomain();
+ if (patternDomain.length() == 0) {
+ patternDomain = defaultDomainName;
+ }
+
+ // work with a copy of the registry key set
+ List nameToProperties;
+ if (!pattern.isDomainPattern()) {
+ synchronized (this) {
+ // create an array list big enough to match all names... extra space is better than resizing
+ nameToProperties = new ArrayList(registry.size());
+
+ // find we are only matching one specific domain, so
+ // just grab it directly from the index
+ Map map = (Map) domainIndex.get(patternDomain);
+ if (map != null) {
+ nameToProperties.addAll(map.entrySet());
+ }
+ }
+ } else if (patternDomain.equals("*")) {
+ // this
+ // is very commmon, so support it directly
+ synchronized (this) {
+ // create an array list big enough to match all names... extra space is better than resizing
+ nameToProperties = new ArrayList(registry.size());
+
+ // find we are matching all domain, so just grab all of them directly
+ for (Iterator iterator = domainIndex.values().iterator(); iterator.hasNext();) {
+ Map map = (Map) iterator.next();
+
+ // we can just copy the entry set directly into the list we don't
+ // have to worry about duplicates as the maps are mutually exclusive
+ nameToProperties.addAll(map.entrySet());
+ }
+ }
+ } else {
+ String perl5Pattern = domainPatternToPerl5(patternDomain);
+ Pattern domainPattern = Pattern.compile(perl5Pattern);
+
+ synchronized (this) {
+ // create an array list big enough to match all names... extra space is better than resizing
+ nameToProperties = new ArrayList(registry.size());
+
+ // find all of the matching domains
+ for (Iterator iterator = domainIndex.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String domain = (String) entry.getKey();
+ if (domainPattern.matcher(domain).matches()) {
+ // we can just copy the entry set directly into the list we don't
+ // have to worry about duplicates as the maps are mutually exclusive
+ Map map = (Map) entry.getValue();
+ nameToProperties.addAll(map.entrySet());
+ }
+ }
+ }
+ }
+
+ if (nameToProperties.isEmpty()) {
+ return Collections.EMPTY_SET;
+ }
+
+ // convert the pattern property list to a HashMap as it is not synchronized
+ Map patternProperties = new HashMap(pattern.getKeyPropertyList());
+ patternProperties.remove("*");
+ boolean isMatchAll = patternProperties.isEmpty();
+ boolean isPropertyPattern = pattern.isPropertyPattern();
+
+ Set matchingNames = new HashSet();
+ for (Iterator iterator = nameToProperties.iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ Map properties = (Map) entry.getValue();
+
+ if (isMatchAll) {
+ matchingNames.add(entry.getKey());
+ } else if (isPropertyPattern) {
+ if (properties.entrySet().containsAll(patternProperties.entrySet())) {
+ matchingNames.add(entry.getKey());
+ }
+ } else {
+ if (properties.entrySet().equals(patternProperties.entrySet())) {
+ matchingNames.add(entry.getKey());
+ }
+ }
+ }
+ return matchingNames;
+ }
+
+ private static String domainPatternToPerl5(String pattern) {
+ char[] patternCharacters = pattern.toCharArray();
+ StringBuffer buffer = new StringBuffer(2 * patternCharacters.length);
+ for (int position = 0; position < patternCharacters.length; position++) {
+ char character = patternCharacters[position];
+ switch (character) {
+ case '*':
+ // replace '*' with '.*'
+ buffer.append(".*");
+ break;
+ case '?':
+ // replace '?' with '.'
+ buffer.append('.');
+ break;
+ default:
+ // escape any perl5 characters with '\'
+ if (isPerl5MetaCharacter(character)) {
+ buffer.append('\\');
+ }
+ buffer.append(character);
+ break;
+ }
+ }
+
+ return buffer.toString();
+ }
+
+ private static boolean isPerl5MetaCharacter(char character) {
+ return ("'*?+[]()|^$.{}\\".indexOf(character) >= 0);
+ }
+}
diff --git a/kernel/src/java/org/gbean/kernel/simple/SimpleServiceFactory.java b/kernel/src/java/org/gbean/kernel/simple/SimpleServiceFactory.java
new file mode 100644
index 0000000..b12cabc
--- /dev/null
+++ b/kernel/src/java/org/gbean/kernel/simple/SimpleServiceFactory.java
@@ -0,0 +1,69 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.kernel.simple;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.gbean.service.ServiceContext;
+import org.gbean.service.ServiceFactory;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleServiceFactory implements ServiceFactory {
+ private final Object service;
+ private final Map dependencies = new HashMap();
+ private boolean enabled = true;
+
+ public SimpleServiceFactory(Object service) {
+ this.service = service;
+ }
+
+ public Map getDependencies() {
+ return dependencies;
+ }
+
+ public void addDependency(String name, Set patterns) {
+ dependencies.put(name, patterns);
+ }
+
+ public Object createService(ServiceContext serviceContext) throws Exception {
+ if (service instanceof SimpleLifecycle) {
+ ((SimpleLifecycle) service).start();
+ }
+ return service;
+ }
+
+ public void destroyService(ServiceContext serviceContext, Object service) {
+ if (service != this.service) {
+ throw new IllegalArgumentException("Wrong service instance");
+ }
+ if (service instanceof SimpleLifecycle) {
+ ((SimpleLifecycle) service).stop();
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+}
diff --git a/kernel/src/java/org/gbean/loader/LoadAllMain.java b/kernel/src/java/org/gbean/loader/LoadAllMain.java
new file mode 100644
index 0000000..e9783e7
--- /dev/null
+++ b/kernel/src/java/org/gbean/loader/LoadAllMain.java
@@ -0,0 +1,55 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.loader;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.Main;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LoadAllMain implements Main {
+ public Kernel kernel;
+ public Main next;
+
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ public void setKernel(Kernel kernel) {
+ this.kernel = kernel;
+ }
+
+ public Main getNext() {
+ return next;
+ }
+
+ public void setNext(Main next) {
+ this.next = next;
+ }
+
+ public void main(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ String location = args[i];
+ LoaderUtil.load(kernel, location);
+ LoaderUtil.verifyAllServicesRunning(kernel);
+ }
+ if (next != null) {
+ next.main(args);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/loader/Loader.java b/kernel/src/java/org/gbean/loader/Loader.java
new file mode 100644
index 0000000..1c504a4
--- /dev/null
+++ b/kernel/src/java/org/gbean/loader/Loader.java
@@ -0,0 +1,26 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.loader;
+
+import javax.management.ObjectName;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface Loader {
+ ObjectName load(String location);
+}
diff --git a/kernel/src/java/org/gbean/loader/LoaderUtil.java b/kernel/src/java/org/gbean/loader/LoaderUtil.java
new file mode 100644
index 0000000..208e1d8
--- /dev/null
+++ b/kernel/src/java/org/gbean/loader/LoaderUtil.java
@@ -0,0 +1,82 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.loader;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.ServiceName;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.runtime.ServiceState;
+import org.gbean.spring.FatalStartupError;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LoaderUtil {
+ private static final ObjectName LOADER_NAME_QUERY = ServiceName.createName("*:j2eeType=Loader,*");
+
+ private LoaderUtil() {
+ }
+
+ public static void load(Kernel kernel, String location) {
+ Collection loaders = kernel.listServices(LOADER_NAME_QUERY);
+ if (loaders.isEmpty()) {
+ throw new FatalStartupError("No loaders avalible in kernel");
+ }
+
+ for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
+ Loader loader = (Loader) iterator.next();
+ try {
+ ObjectName rootConfigurationName = loader.load(location);
+ if (rootConfigurationName != null) {
+ kernel.startRecursiveService(rootConfigurationName);
+ return;
+ }
+ } catch (Exception e) {
+ throw new FatalStartupError("Error loading '" + location + "' with " + loader, e);
+ }
+ }
+
+ String message = "No loaders were able to load '" + location + "' : Available loaders ";
+ for (Iterator iterator = loaders.iterator(); iterator.hasNext();) {
+ message += iterator.next();
+ if (iterator.hasNext()) {
+ message += ", ";
+ }
+ }
+ throw new FatalStartupError(message);
+ }
+
+ public static void verifyAllServicesRunning(Kernel kernel) {
+ Set allServices = kernel.listServiceNames(ServiceName.createName("*:*"));
+ for (Iterator iterator = allServices.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ try {
+ int state = kernel.getServiceState(objectName);
+ if (state != ServiceState.RUNNING_INDEX) {
+ throw new FatalStartupError("Service '" + objectName + "' failed to start");
+ }
+ } catch (ServiceNotFoundException e) {
+ throw new FatalStartupError("Service '" + objectName + "' was unloaded");
+ }
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/metadata/ClassMetadata.java b/kernel/src/java/org/gbean/metadata/ClassMetadata.java
new file mode 100644
index 0000000..ecb6d38
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/ClassMetadata.java
@@ -0,0 +1,53 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+import java.util.Set;
+import java.util.Map;
+import java.util.Collection;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+
+import org.gbean.kernel.OperationSignature;
+import org.gbean.kernel.ConstructorSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ClassMetadata {
+ Class getType();
+
+ Set getMethods();
+
+ MethodMetadata getMethod(OperationSignature signature);
+
+ MethodMetadata getMethod(Method method);
+
+ Set getConstructors();
+
+ ConstructorMetadata getConstructor(ConstructorSignature signature);
+
+ ConstructorMetadata getConstructor(Constructor constructor);
+
+ Map getProperties();
+
+ Object get(Object key);
+
+ Object put(Object key, Object value);
+
+ Object remove(Object key);
+}
diff --git a/kernel/src/java/org/gbean/metadata/ConstructorMetadata.java b/kernel/src/java/org/gbean/metadata/ConstructorMetadata.java
new file mode 100644
index 0000000..4345fbd
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/ConstructorMetadata.java
@@ -0,0 +1,44 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+import java.lang.reflect.Constructor;
+import java.util.List;
+import java.util.Map;
+
+import org.gbean.kernel.ConstructorSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ConstructorMetadata {
+ ConstructorSignature getSignature();
+
+ Constructor getConstructor();
+
+ List getParameters();
+
+ ParameterMetadata getParameter(int index);
+
+ Map getProperties();
+
+ Object get(Object key);
+
+ Object put(Object key, Object value);
+
+ Object remove(Object key);
+}
diff --git a/kernel/src/java/org/gbean/metadata/MetadataManager.java b/kernel/src/java/org/gbean/metadata/MetadataManager.java
new file mode 100644
index 0000000..291b37d
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/MetadataManager.java
@@ -0,0 +1,24 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface MetadataManager {
+ ClassMetadata getClassMetadata(Class type);
+}
diff --git a/kernel/src/java/org/gbean/metadata/MetadataProvider.java b/kernel/src/java/org/gbean/metadata/MetadataProvider.java
new file mode 100644
index 0000000..befe6ed
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/MetadataProvider.java
@@ -0,0 +1,24 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface MetadataProvider {
+ void addClassMetadata(ClassMetadata classMetadata);
+}
diff --git a/kernel/src/java/org/gbean/metadata/MethodMetadata.java b/kernel/src/java/org/gbean/metadata/MethodMetadata.java
new file mode 100644
index 0000000..e57f82b
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/MethodMetadata.java
@@ -0,0 +1,44 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+import java.util.Map;
+import java.util.List;
+import java.lang.reflect.Method;
+
+import org.gbean.kernel.OperationSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface MethodMetadata {
+ OperationSignature getSignature();
+
+ Method getMethod();
+
+ List getParameters();
+
+ ParameterMetadata getParameter(int index);
+
+ Map getProperties();
+
+ Object get(Object key);
+
+ Object put(Object key, Object value);
+
+ Object remove(Object key);
+}
diff --git a/kernel/src/java/org/gbean/metadata/ParameterMetadata.java b/kernel/src/java/org/gbean/metadata/ParameterMetadata.java
new file mode 100644
index 0000000..c3c4492
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/ParameterMetadata.java
@@ -0,0 +1,36 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata;
+
+import java.util.Map;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ParameterMetadata {
+ int getIndex();
+
+ Class getType();
+
+ Map getProperties();
+
+ Object get(Object key);
+
+ Object put(Object key, Object value);
+
+ Object remove(Object key);
+}
diff --git a/kernel/src/java/org/gbean/metadata/simple/PropertiesMetadataProvider.java b/kernel/src/java/org/gbean/metadata/simple/PropertiesMetadataProvider.java
new file mode 100644
index 0000000..69f32a8
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/PropertiesMetadataProvider.java
@@ -0,0 +1,216 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.ClassLoading;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.kernel.ConstructorSignature;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.MetadataProvider;
+import org.gbean.metadata.MethodMetadata;
+import org.gbean.metadata.ParameterMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class PropertiesMetadataProvider implements MetadataProvider {
+ private static final Log log = LogFactory.getLog(PropertiesMetadataProvider.class);
+
+ public void addClassMetadata(ClassMetadata classMetadata) {
+ try {
+ Properties properties = loadProperties(classMetadata.getType());
+ for (Iterator iterator = properties.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ String propertyName = (String) entry.getKey();
+ String propertyValue = (String) entry.getValue();
+ processProperty(classMetadata, propertyName, propertyValue);
+ }
+ } catch (Exception e) {
+ log.error("Error while loading properties based metadata for class " + classMetadata.getType().getName());
+ }
+ }
+
+ private Properties loadProperties(Class type) throws IOException {
+ InputStream in = null;
+ try {
+ Properties properties = new Properties();
+ in = type.getClassLoader().getResourceAsStream(type.getName().replace('.', '/') + ".properties");
+ if (in != null) {
+ LineNumberReader lineReader = new LineNumberReader(new InputStreamReader(in));
+
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ // todo allow line continuations with trailing '\'
+
+ String name = line;
+ String value = "";
+
+ // break the line only at an equal sign
+ int equals = line.indexOf('=');
+ if (equals > 0) {
+ name = line.substring(0, equals);
+ if (equals < line.length()) {
+ value = line.substring(equals + 1);
+ }
+ }
+
+ // todo remove standard escapes such at \t \r \n and \\
+
+ name = name.trim();
+ value = value.trim();
+
+ if (name.length() > 0 && name.charAt(0) != '#' && name.charAt(0) != '!') {
+ properties.setProperty(name, value);
+ }
+ }
+ }
+ return properties;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ log.error("Error while closing properties based metadata input stream for class " + type.getName());
+ }
+ }
+ }
+ }
+
+ private void processProperty(ClassMetadata classMetadata, String propertyName, String propertyValue) {
+ // try to parse the property name as a method property
+ if (parseMethodProperty(classMetadata, propertyName, propertyValue)) {
+ return;
+ }
+ classMetadata.put(propertyName, propertyValue);
+ }
+
+ private boolean parseMethodProperty(ClassMetadata classMetadata, String propertyName, String propertyValue) {
+ // if we don't have an open paren it is not a method property
+ int openParen = propertyName.indexOf('(');
+ if (openParen <= 0) {
+ return false;
+ }
+ // if we don't have a close paren followed by a period after the open paren it is not a method property
+ int closeParen = propertyName.indexOf(").", openParen);
+ if (closeParen < 0) {
+ return false;
+ }
+
+ // we must have some characters after the paren period
+ if (propertyName.length() <= closeParen + 2) {
+ return false;
+ }
+
+ // the method name is the characters before the openparen
+ String methodName = propertyName.substring(0, openParen).trim();
+
+ // parse the parameters
+ List params = parseMethodParameters(classMetadata.getType().getClassLoader(), propertyName.substring(openParen+1, closeParen));
+ if (params == null) {
+ return false;
+ }
+
+ // the property name of the method metadata is the stuff after the ")."
+ String methodPropertyName = propertyName.substring(closeParen + 2).trim();
+ if (methodPropertyName.length() == 0) {
+ return false;
+ }
+
+ // get the parameter index number if one is present
+ int parameterIndex = -1;
+ String parameterPropertyName = null;
+ try {
+ // if the property name does not include a period it is not metadata
+ int period = methodPropertyName.indexOf('.');
+ if (period > 0) {
+ // we must have some characters after the period
+ if (methodPropertyName.length() > period) {
+ String indexString = methodPropertyName.substring(0, period);
+ parameterIndex = Integer.parseInt(indexString);
+ parameterPropertyName = methodPropertyName.substring(period + 1);
+ }
+ }
+ } catch (NumberFormatException e) {
+ }
+
+
+ // now that we know the method name and parameters lets try to get the method metadata for it
+ String className = classMetadata.getType().getName();
+ if (methodName.equals(className.substring(className.lastIndexOf(".") + 1))) {
+ ConstructorSignature signature = new ConstructorSignature(params);
+ ConstructorMetadata constructorMetadata = classMetadata.getConstructor(signature);
+ if (constructorMetadata == null) {
+ return false;
+ }
+
+ if (0 <= parameterIndex && parameterIndex < constructorMetadata.getSignature().getParameterTypes().size()) {
+ // this is parameter metadata
+ ParameterMetadata parameterMetadata = constructorMetadata.getParameter(parameterIndex);
+ parameterMetadata.put(parameterPropertyName, propertyValue);
+ } else {
+ // this is constructor metadata
+ constructorMetadata.put(methodPropertyName, propertyValue);
+ }
+ } else {
+ OperationSignature signature = new OperationSignature(methodName, params);
+ MethodMetadata methodMetadata = classMetadata.getMethod(signature);
+ if (methodMetadata == null) {
+ return false;
+ }
+
+ if (0 <= parameterIndex && parameterIndex < methodMetadata.getSignature().getParameterTypes().size()) {
+ // this is parameter metadata
+ ParameterMetadata parameterMetadata = methodMetadata.getParameter(parameterIndex);
+ parameterMetadata.put(parameterPropertyName, propertyValue);
+ } else {
+ // this is constructor metadata
+ methodMetadata.put(methodPropertyName, propertyValue);
+ }
+ }
+ return true;
+ }
+
+ private List parseMethodParameters(ClassLoader classLoader, String paramsString) {
+ try {
+ List parameters = new LinkedList();
+ for (StringTokenizer stringTokenizer = new StringTokenizer(paramsString, ", \t\n"); stringTokenizer.hasMoreTokens();) {
+ String parameter = stringTokenizer.nextToken();
+ Class parameterType = ClassLoading.loadClass(parameter, classLoader);
+ parameters.add(parameterType.getName());
+ }
+
+ return parameters;
+ } catch (ClassNotFoundException e) {
+ log.error("Unable to load method parameter class" + e);
+ return null;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/metadata/simple/SimpleClassMetadata.java b/kernel/src/java/org/gbean/metadata/simple/SimpleClassMetadata.java
new file mode 100644
index 0000000..2218ca0
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/SimpleClassMetadata.java
@@ -0,0 +1,106 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.gbean.kernel.ConstructorSignature;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MethodMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleClassMetadata implements ClassMetadata {
+ private final Map properties = new LinkedHashMap();
+ private final Class type;
+ private final Map methodMetadata = new HashMap();
+ private final Map constructorMetadata = new HashMap();
+
+ public SimpleClassMetadata(Class type) {
+ this.type = type;
+
+ Constructor[] constructors = type.getConstructors();
+ for (int i = 0; i < constructors.length; i++) {
+ Constructor constructor = constructors[i];
+ ConstructorSignature signature = new ConstructorSignature(constructor);
+ SimpleConstructorMetadata data = new SimpleConstructorMetadata(constructor);
+ constructorMetadata.put(signature, data);
+ }
+
+ Method[] methods = type.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ OperationSignature signature = new OperationSignature(method);
+ MethodMetadata data = new SimpleMethodMetadata(method);
+ methodMetadata.put(signature, data);
+ }
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public Set getConstructors() {
+ return new HashSet(constructorMetadata.values());
+ }
+
+ public ConstructorMetadata getConstructor(ConstructorSignature signature) {
+ return (ConstructorMetadata) constructorMetadata.get(signature);
+ }
+
+ public ConstructorMetadata getConstructor(Constructor constructor) {
+ return (ConstructorMetadata) constructorMetadata.get(new ConstructorSignature(constructor));
+ }
+
+ public Set getMethods() {
+ return new HashSet(methodMetadata.values());
+ }
+
+ public MethodMetadata getMethod(OperationSignature signature) {
+ return (MethodMetadata) methodMetadata.get(signature);
+ }
+
+ public MethodMetadata getMethod(Method method) {
+ OperationSignature signature = new OperationSignature(method);
+ return (MethodMetadata) methodMetadata.get(signature);
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public Object get(Object key) {
+ return properties.get(key);
+ }
+
+ public Object put(Object key, Object value) {
+ return properties.put(key, value);
+ }
+
+ public Object remove(Object key) {
+ return properties.remove(key);
+ }
+}
diff --git a/kernel/src/java/org/gbean/metadata/simple/SimpleConstructorMetadata.java b/kernel/src/java/org/gbean/metadata/simple/SimpleConstructorMetadata.java
new file mode 100644
index 0000000..2beff7f
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/SimpleConstructorMetadata.java
@@ -0,0 +1,82 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gbean.kernel.ConstructorSignature;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.ParameterMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleConstructorMetadata implements ConstructorMetadata {
+ private final Map properties = new LinkedHashMap();
+ private final Constructor constructor;
+ private final ConstructorSignature signature;
+ private final List parameterMetadata;
+
+ public SimpleConstructorMetadata(Constructor constructor) {
+ this.constructor = constructor;
+ this.signature = new ConstructorSignature(constructor);
+ Class[] parameterTypes = constructor.getParameterTypes();
+ List parameters = new ArrayList(parameterTypes.length);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class parameterType = constructor.getParameterTypes()[i];
+ parameters.add(new SimpleParameterMetadata(i, parameterType));
+ }
+ parameterMetadata = Collections.unmodifiableList(parameters);
+ }
+
+ public Constructor getConstructor() {
+ return constructor;
+ }
+
+ public ConstructorSignature getSignature() {
+ return signature;
+ }
+
+ public List getParameters() {
+ return parameterMetadata;
+ }
+
+ public ParameterMetadata getParameter(int index) {
+ return (ParameterMetadata) parameterMetadata.get(index);
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public Object get(Object key) {
+ return properties.get(key);
+ }
+
+ public Object put(Object key, Object value) {
+ return properties.put(key, value);
+ }
+
+ public Object remove(Object key) {
+ return properties.remove(key);
+ }
+}
diff --git a/kernel/src/java/org/gbean/metadata/simple/SimpleMetadataManager.java b/kernel/src/java/org/gbean/metadata/simple/SimpleMetadataManager.java
new file mode 100644
index 0000000..c670445
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/SimpleMetadataManager.java
@@ -0,0 +1,61 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.HashSet;
+
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.metadata.MetadataProvider;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleMetadataManager implements MetadataManager {
+ private Collection metadataProviders;
+
+ public SimpleMetadataManager() {
+ metadataProviders = new HashSet();
+ }
+
+ public SimpleMetadataManager(Collection metadataProviders) {
+ this.metadataProviders = metadataProviders;
+ }
+
+ public Collection getMetadataProviders() {
+ return metadataProviders;
+ }
+
+ public void setMetadataProviders(Collection metadataProviders) {
+ this.metadataProviders = metadataProviders;
+ }
+
+ public void addMetadataProvider(MetadataProvider metadataProvider) {
+ metadataProviders.add(metadataProvider);
+ }
+
+ public ClassMetadata getClassMetadata(Class type) {
+ ClassMetadata classMetadata = new SimpleClassMetadata(type);
+ for (Iterator iterator = metadataProviders.iterator(); iterator.hasNext();) {
+ MetadataProvider metadataProvider = (MetadataProvider) iterator.next();
+ metadataProvider.addClassMetadata(classMetadata);
+ }
+ return classMetadata;
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/metadata/simple/SimpleMethodMetadata.java b/kernel/src/java/org/gbean/metadata/simple/SimpleMethodMetadata.java
new file mode 100644
index 0000000..a1b7b0e
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/SimpleMethodMetadata.java
@@ -0,0 +1,82 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.gbean.kernel.OperationSignature;
+import org.gbean.metadata.MethodMetadata;
+import org.gbean.metadata.ParameterMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleMethodMetadata implements MethodMetadata {
+ private final Map properties = new LinkedHashMap();
+ private final Method method;
+ private final OperationSignature signature;
+ private final List parameterMetadata;
+
+ public SimpleMethodMetadata(Method method) {
+ this.method = method;
+ this.signature = new OperationSignature(method);
+ Class[] parameterTypes = method.getParameterTypes();
+ List parameters = new ArrayList(parameterTypes.length);
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class parameterType = method.getParameterTypes()[i];
+ parameters.add(new SimpleParameterMetadata(i, parameterType));
+ }
+ parameterMetadata = Collections.unmodifiableList(parameters);
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public OperationSignature getSignature() {
+ return signature;
+ }
+
+ public List getParameters() {
+ return parameterMetadata;
+ }
+
+ public ParameterMetadata getParameter(int index) {
+ return (ParameterMetadata) parameterMetadata.get(index);
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public Object get(Object key) {
+ return properties.get(key);
+ }
+
+ public Object put(Object key, Object value) {
+ return properties.put(key, value);
+ }
+
+ public Object remove(Object key) {
+ return properties.remove(key);
+ }
+}
diff --git a/kernel/src/java/org/gbean/metadata/simple/SimpleParameterMetadata.java b/kernel/src/java/org/gbean/metadata/simple/SimpleParameterMetadata.java
new file mode 100644
index 0000000..3fb961f
--- /dev/null
+++ b/kernel/src/java/org/gbean/metadata/simple/SimpleParameterMetadata.java
@@ -0,0 +1,60 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.gbean.metadata.ParameterMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SimpleParameterMetadata implements ParameterMetadata {
+ private final Map properties = new LinkedHashMap();
+ private final int index;
+ private final Class type;
+
+ public SimpleParameterMetadata(int index, Class type) {
+ this.index = index;
+ this.type = type;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public Object get(Object key) {
+ return properties.get(key);
+ }
+
+ public Object put(Object key, Object value) {
+ return properties.put(key, value);
+ }
+
+ public Object remove(Object key) {
+ return properties.remove(key);
+ }
+}
diff --git a/kernel/src/java/org/gbean/propertyeditor/InetAddressEditor.java b/kernel/src/java/org/gbean/propertyeditor/InetAddressEditor.java
new file mode 100644
index 0000000..3219d96
--- /dev/null
+++ b/kernel/src/java/org/gbean/propertyeditor/InetAddressEditor.java
@@ -0,0 +1,40 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.propertyeditor;
+
+import java.beans.PropertyEditorSupport;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class InetAddressEditor extends PropertyEditorSupport {
+ public void setAsText(String value) throws IllegalArgumentException {
+ try {
+ setValue(InetAddress.getByName(value));
+ } catch (UnknownHostException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);
+ }
+ }
+
+ public String getAsText() {
+ InetAddress inetAddress = ((InetAddress) getValue());
+ String text = inetAddress.toString();
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/propertyeditor/ObjectNameEditor.java b/kernel/src/java/org/gbean/propertyeditor/ObjectNameEditor.java
new file mode 100644
index 0000000..bfffe96
--- /dev/null
+++ b/kernel/src/java/org/gbean/propertyeditor/ObjectNameEditor.java
@@ -0,0 +1,40 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.propertyeditor;
+
+import java.beans.PropertyEditorSupport;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ObjectNameEditor extends PropertyEditorSupport {
+ public void setAsText(String value) throws IllegalArgumentException {
+ try {
+ setValue(new ObjectName(value));
+ } catch (MalformedObjectNameException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);
+ }
+ }
+
+ public String getAsText() {
+ ObjectName objectName = ((ObjectName) getValue());
+ String text = objectName.getCanonicalName();
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/propertyeditor/URIEditor.java b/kernel/src/java/org/gbean/propertyeditor/URIEditor.java
new file mode 100644
index 0000000..5395022
--- /dev/null
+++ b/kernel/src/java/org/gbean/propertyeditor/URIEditor.java
@@ -0,0 +1,40 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.propertyeditor;
+
+import java.beans.PropertyEditorSupport;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class URIEditor extends PropertyEditorSupport {
+ public void setAsText(String value) throws IllegalArgumentException {
+ try {
+ setValue(new URI(value));
+ } catch (URISyntaxException e) {
+ throw (IllegalArgumentException) new IllegalArgumentException().initCause(e);
+ }
+ }
+
+ public String getAsText() {
+ URI uri = ((URI) getValue());
+ String text = uri.toString();
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/proxy/ProxyFactory.java b/kernel/src/java/org/gbean/proxy/ProxyFactory.java
new file mode 100644
index 0000000..d6cb392
--- /dev/null
+++ b/kernel/src/java/org/gbean/proxy/ProxyFactory.java
@@ -0,0 +1,30 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.proxy;
+
+import javax.management.ObjectName;
+
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ProxyFactory {
+ Object createProxy(ObjectName target) throws ServiceNotFoundException;
+
+ Object createProxy(ObjectName target, Object data) throws ServiceNotFoundException;
+}
diff --git a/kernel/src/java/org/gbean/proxy/ProxyManager.java b/kernel/src/java/org/gbean/proxy/ProxyManager.java
new file mode 100644
index 0000000..45b1476
--- /dev/null
+++ b/kernel/src/java/org/gbean/proxy/ProxyManager.java
@@ -0,0 +1,138 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.proxy;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import javax.management.ObjectName;
+
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.CallbackFilter;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.NoOp;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.ServiceName;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.reflect.ServiceInvoker;
+import org.gbean.reflect.ServiceInvokerManager;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ProxyManager {
+ private static ObjectName PROXY_MANAGER_QUERY = ServiceName.createName("*:j2eeType=ProxyManager,*");
+ public static ProxyManager findProxyManager(Kernel kernel) throws ServiceNotFoundException {
+ Set names = kernel.listServiceNames(PROXY_MANAGER_QUERY);
+ if (names.isEmpty()) {
+ throw new IllegalStateException("Proxy mananger could not be found in kernel: " + PROXY_MANAGER_QUERY);
+ }
+ if (names.size() > 1) {
+ throw new IllegalStateException("More then one proxy manangers were found in kernel: " + PROXY_MANAGER_QUERY);
+ }
+ ObjectName proxyManagerName = (ObjectName) names.iterator().next();
+ return (ProxyManager) kernel.getService(proxyManagerName);
+ }
+
+ private final ServiceInvokerManager serviceInvokerManager;
+ private final Map interceptors = new WeakHashMap();
+
+ public ProxyManager(ServiceInvokerManager serviceInvokerManager) {
+ this.serviceInvokerManager = serviceInvokerManager;
+ }
+
+ public synchronized ProxyFactory createProxyFactory(Class type) {
+ assert type != null: "type is null";
+ return new FastProxyFactory(type);
+ }
+
+ public synchronized Object createProxy(ObjectName target, Class type) throws ServiceNotFoundException {
+ return createProxy(target, type, null);
+ }
+
+ public synchronized Object createProxy(ObjectName target, Class type, Object data) throws ServiceNotFoundException {
+ assert type != null: "type is null";
+ assert target != null: "target is null";
+
+ return new FastProxyFactory(type).createProxy(target, data);
+ }
+
+ public boolean isProxy(Object proxy) {
+ return interceptors.containsKey(proxy);
+ }
+
+ public synchronized ObjectName getProxyTarget(Object proxy) {
+ ProxyMethodInterceptor methodInterceptor = (ProxyMethodInterceptor) interceptors.get(proxy);
+ if (methodInterceptor == null) {
+ return null;
+ }
+ return methodInterceptor.getObjectName();
+ }
+
+ public synchronized Object getProxyData(Object proxy) {
+ ProxyMethodInterceptor methodInterceptor = (ProxyMethodInterceptor) interceptors.get(proxy);
+ if (methodInterceptor == null) {
+ return null;
+ }
+ return methodInterceptor.getData();
+ }
+
+ private class FastProxyFactory implements ProxyFactory {
+ private final Class type;
+ private final Enhancer enhancer;
+
+ public FastProxyFactory(Class type) {
+ enhancer = new Enhancer();
+ enhancer.setSuperclass(type);
+ enhancer.setCallbackTypes(new Class[]{NoOp.class, MethodInterceptor.class});
+ enhancer.setCallbackFilter(FILTER);
+ enhancer.setUseFactory(false);
+ this.type = enhancer.createClass();
+ }
+
+ public synchronized Object createProxy(ObjectName target) throws ServiceNotFoundException {
+ return createProxy(target, null);
+ }
+
+ public synchronized Object createProxy(ObjectName target, Object data) throws ServiceNotFoundException {
+ assert target != null: "target is null";
+
+ ServiceInvoker serviceInvoker = serviceInvokerManager.getServiceInvoker(target);
+ ProxyMethodInterceptor interceptor = new ProxyMethodInterceptor(type, serviceInvoker, target, data);
+
+ // @todo trap CodeGenerationException indicating missing no-arg ctr
+ enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, interceptor});
+ Object proxy = enhancer.create();
+
+ interceptors.put(proxy, interceptor);
+ return proxy;
+ }
+ }
+
+ private static final CallbackFilter FILTER = new CallbackFilter() {
+ public int accept(Method method) {
+ if (method.getName().equals("finalize") &&
+ method.getParameterTypes().length == 0 &&
+ method.getReturnType() == Void.TYPE) {
+ return 0;
+ }
+ return 1;
+ }
+ };
+}
diff --git a/kernel/src/java/org/gbean/proxy/ProxyMethodInterceptor.java b/kernel/src/java/org/gbean/proxy/ProxyMethodInterceptor.java
new file mode 100644
index 0000000..38829a3
--- /dev/null
+++ b/kernel/src/java/org/gbean/proxy/ProxyMethodInterceptor.java
@@ -0,0 +1,185 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.proxy;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Iterator;
+import javax.management.ObjectName;
+
+import net.sf.cglib.asm.Type;
+import net.sf.cglib.core.Signature;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+import net.sf.cglib.reflect.FastClass;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.reflect.OperationInvoker;
+import org.gbean.reflect.ServiceInvoker;
+
+/**
+ * @version $Rev: 106345 $ $Date: 2004-11-23 12:37:03 -0800 (Tue, 23 Nov 2004) $
+ */
+public class ProxyMethodInterceptor implements MethodInterceptor {
+ /**
+ * Type of the proxy interface
+ */
+ private final Class proxyType;
+
+ /**
+ * The object name to which we are connected.
+ */
+ private final ObjectName objectName;
+
+ /**
+ * OperationInvokers indexed by interface method id
+ */
+ private final OperationInvoker[] operationIndex;
+
+ /**
+ * The service invoker used by this proxy
+ */
+ private final ServiceInvoker serviceInvoker;
+
+ private final Object data;
+
+ public ProxyMethodInterceptor(Class proxyType, ServiceInvoker serviceInvoker, ObjectName objectName, Object data) {
+ assert proxyType != null;
+ assert serviceInvoker != null;
+ assert objectName != null;
+
+ this.proxyType = proxyType;
+ this.serviceInvoker = serviceInvoker;
+ this.objectName = objectName;
+ this.data = data;
+
+ operationIndex = createOperationIndex();
+ }
+
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
+ int interfaceIndex = proxy.getSuperIndex();
+ OperationInvoker operationInvoker = this.operationIndex[interfaceIndex];
+ if (operationInvoker == null) {
+ throw new UnsupportedOperationException("No implementation method: objectName=" + objectName + ", method=" + method);
+ }
+
+ return operationInvoker.invoke(args);
+ }
+
+ private OperationInvoker[] createOperationIndex() {
+ List operationIndex = serviceInvoker.getOperationIndex();
+ Map operations = new HashMap(operationIndex.size());
+ for (Iterator iterator = operationIndex.iterator(); iterator.hasNext();) {
+ OperationInvoker operationInvoker = (OperationInvoker) iterator.next();
+ operations.put(operationInvoker.getSignature(), operationInvoker);
+ }
+
+ // build the method lookup table
+ FastClass fastClass = FastClass.create(proxyType);
+ OperationInvoker[] operationInvokers = new OperationInvoker[fastClass.getMaxIndex() + 1];
+ Method[] methods = proxyType.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ int interfaceIndex = getSuperIndex(proxyType, method);
+ if (interfaceIndex >= 0) {
+ operationInvokers[interfaceIndex] = (OperationInvoker) operations.get(new OperationSignature(method));
+ }
+ }
+
+ // handle equals, hashCode and toString directly here
+ try {
+ operationInvokers[getSuperIndex(proxyType, proxyType.getMethod("equals", new Class[]{Object.class}))] = new EqualsInvoke(this);
+ operationInvokers[getSuperIndex(proxyType, proxyType.getMethod("hashCode", null))] = new HashCodeInvoke(this);
+ operationInvokers[getSuperIndex(proxyType, proxyType.getMethod("toString", null))] = new ToStringInvoke(objectName, proxyType.getName());
+ } catch (Exception e) {
+ // this can not happen... all classes must implement equals, hashCode and toString
+ throw new AssertionError(e);
+ }
+
+ return operationInvokers;
+ }
+
+ private static int getSuperIndex(Class proxyType, Method method) {
+ Signature signature = new Signature(method.getName(), Type.getReturnType(method), Type.getArgumentTypes(method));
+ MethodProxy methodProxy = MethodProxy.find(proxyType, signature);
+ if (methodProxy != null) {
+ return methodProxy.getSuperIndex();
+ }
+ return -1;
+ }
+
+ static final class HashCodeInvoke implements OperationInvoker {
+ private final MethodInterceptor methodInterceptor;
+
+ public HashCodeInvoke(MethodInterceptor methodInterceptor) {
+ this.methodInterceptor = methodInterceptor;
+ }
+
+ public OperationSignature getSignature() {
+ return new OperationSignature("hashCode", new String[] {});
+ }
+
+ // todo this should be hashcode of objectname
+ public Object invoke(Object[] arguments) {
+ return new Integer(methodInterceptor.hashCode());
+ }
+ }
+
+ static final class EqualsInvoke implements OperationInvoker {
+ private final MethodInterceptor methodInterceptor;
+
+ public EqualsInvoke(MethodInterceptor methodInterceptor) {
+ this.methodInterceptor = methodInterceptor;
+ }
+
+ public OperationSignature getSignature() {
+ return new OperationSignature("equals", new String[] {Object.class.getName()});
+ }
+
+ // todo this should do isProxy and compare the target objectname
+ public Object invoke(Object[] arguments) {
+ return Boolean.valueOf(methodInterceptor.equals(arguments[0]));
+ }
+ }
+
+ static final class ToStringInvoke implements OperationInvoker {
+ private final String interfaceName;
+ private final ObjectName objectName;
+
+ public ToStringInvoke(ObjectName objectName, String interfaceName) {
+ this.objectName = objectName;
+ this.interfaceName = "[" + interfaceName + ": ";
+ }
+
+ public OperationSignature getSignature() {
+ return new OperationSignature("toString", new String[] {});
+ }
+
+ public Object invoke(Object[] arguments) {
+ return interfaceName + objectName + "]";
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/reflect/OperationInvoker.java b/kernel/src/java/org/gbean/reflect/OperationInvoker.java
new file mode 100644
index 0000000..1f7f182
--- /dev/null
+++ b/kernel/src/java/org/gbean/reflect/OperationInvoker.java
@@ -0,0 +1,27 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.reflect;
+
+import org.gbean.kernel.OperationSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface OperationInvoker {
+ OperationSignature getSignature();
+ Object invoke(Object[] arguments) throws Exception;
+}
diff --git a/kernel/src/java/org/gbean/reflect/PropertyInvoker.java b/kernel/src/java/org/gbean/reflect/PropertyInvoker.java
new file mode 100644
index 0000000..1e8c2da
--- /dev/null
+++ b/kernel/src/java/org/gbean/reflect/PropertyInvoker.java
@@ -0,0 +1,33 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.reflect;
+
+import org.gbean.kernel.OperationSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface PropertyInvoker {
+ String getPropertyName();
+ Class getType();
+ boolean isReadable();
+ OperationSignature getGetterSignature();
+ Object invokeGetter() throws Exception;
+ boolean isWritable();
+ OperationSignature getSetterSignature();
+ void invokeSetter(Object value) throws Exception;
+}
diff --git a/kernel/src/java/org/gbean/reflect/ServiceInvoker.java b/kernel/src/java/org/gbean/reflect/ServiceInvoker.java
new file mode 100644
index 0000000..188f88c
--- /dev/null
+++ b/kernel/src/java/org/gbean/reflect/ServiceInvoker.java
@@ -0,0 +1,716 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+import javax.management.ObjectName;
+
+import net.sf.cglib.reflect.FastClass;
+import net.sf.cglib.reflect.FastMethod;
+import org.apache.geronimo.gbean.DynamicGBean;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.NoSuchAttributeException;
+import org.gbean.kernel.NoSuchOperationException;
+import org.gbean.kernel.runtime.ServiceState;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ServiceInvoker {
+ /**
+ * Our log stream
+ */
+ private static final Log log = LogFactory.getLog(ServiceInvoker.class);
+
+ /**
+ * The kernel in which the service is loaded
+ */
+ private final Kernel kernel;
+
+ /**
+ * The name of the service in the kernel
+ */
+ private final ObjectName name;
+
+ /**
+ * The listener that is notified when the service goes offline.
+ */
+ private final ServiceInvokerLifecycleListener lifecycleListener;
+
+ /**
+ * The actual target service
+ */
+ private Object serviceInstance;
+
+ /**
+ * Is the service currently running?
+ */
+ private boolean serviceRunning;
+
+ /**
+ * Property invokers
+ */
+ private PropertyInvokerImpl[] properties;
+
+ /**
+ * Property name to index number
+ */
+ private final Map propertyIndex = new HashMap();
+
+ /**
+ * Operations lookup table
+ */
+ private OperationInvokerImpl[] operations;
+
+ /**
+ * Operations supported by the service by OperationSignature
+ */
+ private final Map operationIndex = new HashMap();
+
+ /**
+ * Has the ServiceInvoker itself been started?
+ */
+ private boolean serviceInvokerStarted = false;
+
+ public ServiceInvoker(Kernel kernel, ObjectName name) {
+ this.kernel = kernel;
+ this.name = name;
+ lifecycleListener = new ServiceInvokerLifecycleListener();
+ }
+
+ public synchronized void start() throws ServiceNotFoundException {
+ if (serviceRunning) {
+ return;
+ }
+
+ kernel.addLifecycleListener(lifecycleListener, name);
+ serviceInvokerStarted = true;
+ assureRunning();
+ }
+
+ public synchronized void stop() {
+ kernel.removeLifecycleListener(lifecycleListener);
+ properties = null;
+ propertyIndex.clear();
+ operations = null;
+ operationIndex.clear();
+ serviceInstance = null;
+ serviceRunning = false;
+ serviceInvokerStarted = false;
+ }
+
+ public synchronized ObjectName getServiceName() {
+ return name;
+ }
+
+ public synchronized Class getServiceType() {
+ assureRunning();
+ return serviceInstance.getClass();
+ }
+
+ public synchronized List getPropertyIndex() {
+ assureRunning();
+ return Collections.unmodifiableList(Arrays.asList(properties));
+ }
+
+ public synchronized List getOperationIndex() {
+ assureRunning();
+ return Collections.unmodifiableList(Arrays.asList(operations));
+ }
+
+ /**
+ * Gets the attribute value using the attribute index. This is the most efficient way to get
+ * an attribute as it avoids a HashMap lookup.
+ *
+ * @param index the index of the attribute
+ * @return the attribute value
+ * @throws Exception if a target instance throws and exception
+ * @throws IndexOutOfBoundsException if the index is invalid
+ */
+ public Object getAttribute(int index) throws Exception {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ PropertyInvokerImpl property;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+ property = properties[index];
+ }
+
+ if (!property.isReadable()) {
+ throw new IllegalArgumentException("Property " + property.getPropertyName() + " is not readable");
+ }
+ try {
+ Object value = property.getterFastMethod.invoke(instance, null);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ /**
+ * Gets an attribute's value by name. This get style is less efficient becuse the attribute must
+ * first be looked up in a HashMap.
+ *
+ * @param name the name of the property to retrieve
+ * @return the property value
+ * @throws Exception if a problem occurs while getting the value
+ * @throws NoSuchAttributeException if the attribute name is not found in the map
+ */
+ public Object getAttribute(String name) throws NoSuchAttributeException, Exception {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ PropertyInvokerImpl property = null;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+ Integer index = (Integer) propertyIndex.get(name);
+ if (index != null) {
+ property = properties[index.intValue()];
+ }
+ }
+
+ if (property != null) {
+ if (!property.isReadable()) {
+ throw new IllegalArgumentException("Property " + property.getPropertyName() + " is not readable");
+ }
+ try {
+ Object value = property.getterFastMethod.invoke(instance, null);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ } else if (instance instanceof DynamicGBean) {
+ Object value = ((DynamicGBean) instance).getAttribute(name);
+ return value;
+ }
+ throw new NoSuchAttributeException("Unknown property '" + name + "' in service " + name);
+ }
+
+ /**
+ * Sets the attribute value using the attribute index. This is the most efficient way to set
+ * an attribute as it avoids a HashMap lookup.
+ *
+ * @param index the index of the attribute
+ * @param value the new value of attribute value
+ * @throws Exception if a target instance throws and exception
+ * @throws IndexOutOfBoundsException if the index is invalid
+ */
+ public void setAttribute(int index, Object value) throws Exception, IndexOutOfBoundsException {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ PropertyInvokerImpl property;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+ property = properties[index];
+ }
+
+ if (!property.isWritable()) {
+ throw new IllegalArgumentException("Property " + property.getPropertyName() + " is not writable");
+ }
+ try {
+ property.setterFastMethod.invoke(instance, new Object[] {value});
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ /**
+ * Sets an attribute's value by name. This set style is less efficient becuse the attribute must
+ * first be looked up in a HashMap.
+ *
+ * @param attributeName the name of the attribute to retrieve
+ * @param attributeValue the new attribute value
+ * @throws Exception if a target instance throws and exception
+ * @throws NoSuchAttributeException if the attribute name is not found in the map
+ */
+ public void setAttribute(String attributeName, Object attributeValue) throws Exception, NoSuchAttributeException {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ PropertyInvokerImpl property = null;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+ Integer index = (Integer) propertyIndex.get(attributeName);
+ if (index != null) {
+ property = properties[index.intValue()];
+ }
+ }
+
+ if (property != null) {
+ if (!property.isWritable()) {
+ throw new IllegalArgumentException("Property " + property.getPropertyName() + " is not writable");
+ }
+ try {
+ property.setterFastMethod.invoke(instance, new Object[] {attributeValue});
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ } else if (instance instanceof DynamicGBean) {
+ ((DynamicGBean) instance).setAttribute(attributeName, attributeValue);
+ } else {
+ throw new NoSuchAttributeException("Unknown attribute '" + attributeName + "' in service " + name);
+ }
+ }
+
+ /**
+ * Invokes an opreation using the operation index. This is the most efficient way to invoke
+ * an operation as it avoids a HashMap lookup.
+ *
+ * @param index the index of the attribute
+ * @param arguments the arguments to the operation
+ * @return the result of the operation
+ * @throws Exception if a target instance throws and exception
+ * @throws IndexOutOfBoundsException if the index is invalid
+ * @throws IllegalStateException if the service has been destroyed
+ */
+ public Object invoke(int index, Object[] arguments) throws Exception {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ OperationInvokerImpl operation;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+ operation = operations[index];
+ }
+
+ try {
+ Object value = operation.fastMethod.invoke(instance, arguments);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ /**
+ * Invokes an operation on the service by method signature. This style if invocation is
+ * inefficient, because the target method must be looked up in a hashmap using a freshly constructed
+ * OperationSignature object.
+ *
+ * @param operationName the name of the operation to invoke
+ * @param arguments arguments to the operation
+ * @param types types of the operation arguemtns
+ * @return the result of the operation
+ * @throws Exception if a target instance throws and exception
+ * @throws NoSuchOperationException if the operation signature is not found in the map
+ * @throws IllegalStateException if the service has been destroyed
+ */
+ public Object invoke(String operationName, Object[] arguments, String[] types) throws Exception, NoSuchOperationException {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ OperationInvokerImpl operation;
+ synchronized (this) {
+ assureRunning();
+ instance = serviceInstance;
+
+ OperationSignature signature = new OperationSignature(operationName, types);
+ Integer index = (Integer) operationIndex.get(signature);
+ if (index == null) {
+ throw new NoSuchOperationException("Unknown operation " + signature);
+ }
+ operation = operations[index.intValue()];
+ }
+
+ try {
+ Object value = operation.fastMethod.invoke(instance, arguments);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ public synchronized void assureRunning() {
+ if (!serviceRunning) {
+ try {
+ updateState();
+ if (!serviceRunning) {
+ throw new IllegalStateException("Service must be in the running or stopping state: name=" + name + ", state=" + ServiceState.fromIndex(kernel.getServiceState(name)));
+ }
+ } catch (ServiceNotFoundException e) {
+ throw new IllegalStateException("Service is not loaded: " + name);
+ }
+ }
+ }
+
+ private synchronized void updateState() throws ServiceNotFoundException {
+ if (!serviceInvokerStarted) {
+ throw new IllegalStateException("Service invoker has not been started: name=" + name);
+ }
+ try {
+ serviceRunning = false;
+
+ // get the current state
+ int serviceState = kernel.getServiceState(name);
+
+ // we must be in a running state
+ boolean running = serviceState == ServiceState.RUNNING_INDEX || serviceState == ServiceState.STOPPING_INDEX;
+ if (running) {
+ if (serviceInstance == null) {
+ serviceInstance = kernel.getService(name);
+
+ // if we don't have a service instance something is wrong
+ if (serviceInstance == null) {
+ throw new IllegalStateException("Could not get service instance: name=" + name);
+ }
+ createIndex(serviceInstance.getClass());
+ }
+ serviceRunning = true;
+ }
+ } finally {
+ if (!serviceRunning) {
+ kernel.removeLifecycleListener(lifecycleListener);
+ serviceInvokerStarted = false;
+ properties = null;
+ propertyIndex.clear();
+ operations = null;
+ operationIndex.clear();
+ serviceInstance = null;
+ }
+ }
+ }
+
+ private class ServiceInvokerLifecycleListener extends LifecycleAdapter {
+ public void stopped(ObjectName objectName) {
+ try {
+ updateState();
+ } catch (Exception e) {
+ log.info("Unable to update service invoker for service " + name, e);
+ }
+ }
+
+ public void unloaded(ObjectName objectName) {
+ try {
+ updateState();
+ } catch (Exception e) {
+ log.info("Unable to update service invoker for service " + name, e);
+ }
+ }
+ }
+
+ private void createIndex(Class type) {
+ // attributes
+ Method[] methods = type.getMethods();
+
+ // map the getters
+ Map getterMap = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+ if (Modifier.isPublic(method.getModifiers()) &&
+ !Modifier.isStatic(method.getModifiers()) &&
+ method.getParameterTypes().length == 0 &&
+ method.getReturnType() != Void.TYPE) {
+ if (methodName.length() > 3 && methodName.startsWith("get") && !methodName.equals("getClass")) {
+ String attributeName = fixAttributeName(methodName.substring(3));
+
+ // if this attribute also has an "is" accessor make sure the return type is boolean
+ Method isAccessor = (Method) getterMap.get(attributeName);
+ if (isAccessor != null && method.getReturnType() != Boolean.TYPE) {
+ throw new IllegalArgumentException("Getter has both a get<name> and is<name> accessor but the getter return type is not boolean:" +
+ " class=" + type.getName() +
+ ", attribute=" + attributeName +
+ ", getAccessorType=" + method.getReturnType().getName());
+ }
+
+ // add it
+ getterMap.put(attributeName, method);
+ } else if (methodName.length() > 2 && methodName.startsWith("is")) {
+ String attributeName = fixAttributeName(methodName.substring(2));
+
+ // an is accessor must return boolean
+ if (method.getReturnType() != Boolean.TYPE) {
+ throw new IllegalArgumentException("An is<name> accessor must return boolean:" +
+ " class=" + type.getName() +
+ ", attribute=" + attributeName +
+ ", attributeType=" + method.getReturnType().getName());
+ }
+
+ // if this attribute also has a "get" accessor make sure the getter return type is boolean
+ Method getAccessor = (Method) getterMap.get(attributeName);
+ if (getAccessor != null && method.getReturnType() != Boolean.TYPE) {
+ throw new IllegalArgumentException("Getter has both a get<name> and is<name> accessor but the getter return type is not boolean:" +
+ " class=" + type.getName() +
+ ", attribute=" + attributeName +
+ ", getAccessorType=" + getAccessor.getReturnType().getName());
+ }
+
+ // add it
+ getterMap.put(attributeName, method);
+ }
+ }
+ }
+
+ // map the setters
+ Map setterMap = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+ if (Modifier.isPublic(method.getModifiers()) &&
+ !Modifier.isStatic(method.getModifiers()) &&
+ method.getParameterTypes().length == 1 &&
+ method.getReturnType() == Void.TYPE &&
+ methodName.length() > 3 &&
+ methodName.startsWith("set")) {
+
+ String attributeName = fixAttributeName(methodName.substring(3));
+ if (setterMap.containsKey(attributeName)) {
+ // this bean attributte has multiple setters with different types, so treat only as operations
+ setterMap.put(attributeName, null);
+ } else {
+ setterMap.put(attributeName, method);
+ }
+
+ // the getter and setter types must match
+ Method getterMethod = (Method) getterMap.get(attributeName);
+ if (getterMethod != null && !getterMethod.getReturnType().equals(method.getParameterTypes()[0])) {
+ throw new IllegalArgumentException("Getter and setter types do not match:" +
+ " class=" + type.getName() +
+ ", attribute=" + attributeName +
+ ", getAccessorType=" + getterMethod.getReturnType().getName() +
+ ", setAccessorType=" + method.getParameterTypes()[0].getName());
+ }
+ }
+ }
+ // remove any setter with a null method (these setters have multiple methods with different types)
+ for (Iterator iterator = setterMap.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ Method setter = (Method) entry.getValue();
+ if (setter == null) {
+ iterator.remove();
+ }
+ }
+
+ TreeSet propertyNames = new TreeSet();
+ propertyNames.addAll(getterMap.keySet());
+ propertyNames.addAll(setterMap.keySet());
+
+ List propertyList = new ArrayList(getterMap.size());
+ for (Iterator iterator = propertyNames.iterator(); iterator.hasNext();) {
+ String propertyName = (String) iterator.next();
+ Method getter = (Method) getterMap.get(propertyName);
+ Method setter = (Method) setterMap.get(propertyName);
+ propertyIndex.put(propertyName, new Integer(propertyList.size()));
+ propertyList.add(new PropertyInvokerImpl(propertyName, getter, setter));
+ }
+ properties = (PropertyInvokerImpl[]) propertyList.toArray(new PropertyInvokerImpl[propertyList.size()]);
+
+ // operations
+ List operationList = new ArrayList(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
+ operationIndex.put(new OperationSignature(method), new Integer(operationList.size()));
+ operationList.add(new OperationInvokerImpl(method));
+ }
+ }
+ operations = (OperationInvokerImpl[]) operationList.toArray(new OperationInvokerImpl[operationList.size()]);
+ }
+
+ private static Exception unwrap(InvocationTargetException e) throws Exception {
+ Throwable cause = e.getTargetException();
+ if (cause instanceof Exception) {
+ return (Exception) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ }
+ return e;
+ }
+
+ private static String fixAttributeName(String attributeName) {
+ if (Character.isUpperCase(attributeName.charAt(0))) {
+ return Character.toLowerCase(attributeName.charAt(0)) + attributeName.substring(1);
+ }
+ return attributeName;
+ }
+
+ private final class OperationInvokerImpl implements OperationInvoker {
+ private final OperationSignature signature;
+ private final FastMethod fastMethod;
+
+ public OperationInvokerImpl(Method method) {
+ assert method != null: "method is null";
+ this.signature = new OperationSignature(method);
+ this.fastMethod = FastClass.create(method.getDeclaringClass()).getMethod(method);
+ }
+
+ public OperationSignature getSignature() {
+ return signature;
+ }
+
+ public Object invoke(Object[] arguments) throws Exception {
+ Object instance;
+ synchronized (ServiceInvoker.this) {
+ assureRunning();
+ instance = serviceInstance;
+ }
+
+ try {
+ Object value = fastMethod.invoke(instance, arguments);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ public int hashCode() {
+ return signature.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof OperationInvokerImpl)) {
+ return false;
+ }
+ OperationInvokerImpl operationInvoker = (OperationInvokerImpl)obj;
+ return signature.equals(operationInvoker.signature);
+ }
+
+ public String toString() {
+ return "[MethodInvoker: " + getSignature().toString() + "]";
+ }
+ }
+
+ public class PropertyInvokerImpl implements PropertyInvoker {
+ private final String propertyName;
+ private final Class type;
+ private final OperationSignature getterSignature;
+ private final FastMethod getterFastMethod;
+ private final OperationSignature setterSignature;
+ private final FastMethod setterFastMethod;
+
+ public PropertyInvokerImpl(String propertyName, Method getter, Method setter) {
+ assert propertyName != null: "propertyName is null";
+ assert getter != null || setter != null: "getter and setter are null";
+
+ this.propertyName = propertyName;
+
+ if (getter != null) {
+ type = getter.getReturnType();
+ } else {
+ type = setter.getParameterTypes()[0];
+ }
+
+ if (getter != null) {
+ getterSignature = new OperationSignature(getter);
+ getterFastMethod = FastClass.create(getter.getDeclaringClass()).getMethod(getter);
+ } else {
+ getterSignature = null;
+ getterFastMethod = null;
+ }
+
+ if (setter != null) {
+ setterSignature = new OperationSignature(setter);
+ setterFastMethod = FastClass.create(setter.getDeclaringClass()).getMethod(setter);
+ } else {
+ setterSignature = null;
+ setterFastMethod = null;
+ }
+ }
+
+ public String getPropertyName() {
+ return propertyName;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public boolean isReadable() {
+ return getterFastMethod != null;
+ }
+
+ public OperationSignature getGetterSignature() {
+ return getterSignature;
+ }
+
+ public Object invokeGetter() throws Exception {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ synchronized (ServiceInvoker.this) {
+ assureRunning();
+ instance = serviceInstance;
+ }
+
+ if (!isReadable()) {
+ throw new IllegalArgumentException("Property " + propertyName + " is not readable");
+ }
+ try {
+ Object value = getterFastMethod.invoke(instance, null);
+ return value;
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ public boolean isWritable() {
+ return setterFastMethod != null;
+ }
+
+ public OperationSignature getSetterSignature() {
+ return setterSignature;
+ }
+
+ public void invokeSetter(Object value) throws Exception {
+ // copy target into local variables from within a synchronized block to gaurentee a consistent read
+ Object instance;
+ synchronized (ServiceInvoker.this) {
+ assureRunning();
+ instance = serviceInstance;
+ }
+
+ if (!isWritable()) {
+ throw new IllegalArgumentException("Property " + propertyName + " is not writable");
+ }
+ try {
+ setterFastMethod.invoke(instance, new Object[] {value});
+ } catch (InvocationTargetException e) {
+ throw unwrap(e);
+ }
+ }
+
+ public int hashCode() {
+ return propertyName.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof PropertyInvokerImpl)) {
+ return false;
+ }
+ PropertyInvokerImpl fastPropertyInvoker = (PropertyInvokerImpl)obj;
+ return propertyName.equals(fastPropertyInvoker.propertyName);
+ }
+
+ public String toString() {
+ return "[PropertySetter: name=" + propertyName + ", getter=" + getterSignature + ", setter=" + setterSignature + "]";
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/reflect/ServiceInvokerManager.java b/kernel/src/java/org/gbean/reflect/ServiceInvokerManager.java
new file mode 100644
index 0000000..48ebf6d
--- /dev/null
+++ b/kernel/src/java/org/gbean/reflect/ServiceInvokerManager.java
@@ -0,0 +1,118 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.reflect;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.LifecycleAdapter;
+import org.gbean.kernel.ServiceName;
+import org.gbean.kernel.ServiceNotFoundException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ServiceInvokerManager {
+ private static final Log log = LogFactory.getLog(ServiceInvokerManager.class);
+ private static final ObjectName ALL = ServiceName.createName("*:*");
+ private final Kernel kernel;
+ private final Map registry = new HashMap();
+ private final ServiceRegistrationListener lifecycleListener;
+
+ public ServiceInvokerManager(Kernel kernel) {
+ this.kernel = kernel;
+ lifecycleListener = new ServiceRegistrationListener();
+ }
+
+ public synchronized void start() {
+ kernel.addLifecycleListener(lifecycleListener, ALL);
+ Set allNames = kernel.listServiceNames(ALL);
+ for (Iterator iterator = allNames.iterator(); iterator.hasNext();) {
+ ObjectName objectName = (ObjectName) iterator.next();
+ try {
+ register(objectName);
+ } catch (Exception e) {
+ log.info("Unable to create service invoker for " + objectName, e);
+ }
+ }
+ }
+
+ public synchronized ServiceInvoker getServiceInvoker(ObjectName objectName) throws ServiceNotFoundException, IllegalStateException {
+ ServiceInvoker serviceInvoker = (ServiceInvoker) registry.get(objectName);
+ if (serviceInvoker != null) {
+ serviceInvoker.assureRunning();
+ } else {
+ register(objectName);
+ serviceInvoker = (ServiceInvoker) registry.get(objectName);
+ }
+
+ if (serviceInvoker == null) {
+ throw new ServiceNotFoundException(objectName.getCanonicalName());
+ }
+ return serviceInvoker;
+ }
+
+ public synchronized void stop() {
+ kernel.removeLifecycleListener(lifecycleListener);
+ registry.clear();
+ }
+
+ private void register(ObjectName objectName) throws ServiceNotFoundException, IllegalStateException {
+ synchronized (this) {
+ if (registry.containsKey(objectName)) {
+ return;
+ }
+
+ ServiceInvoker serviceInvoker = new ServiceInvoker(kernel, objectName);
+ serviceInvoker.start();
+ registry.put(objectName, serviceInvoker);
+ }
+ }
+
+ private void unregister(ObjectName objectName) {
+ synchronized (this) {
+ ServiceInvoker serviceInvoker = (ServiceInvoker) registry.remove(objectName);
+ if (serviceInvoker != null) {
+ serviceInvoker.stop();
+ }
+ }
+ }
+
+ private class ServiceRegistrationListener extends LifecycleAdapter {
+ public void running(ObjectName objectName) {
+ try {
+ register(objectName);
+ } catch (Exception e) {
+ log.info("Unable to create service invoker for " + objectName, e);
+ }
+ }
+
+ public void stopped(ObjectName objectName) {
+ unregister(objectName);
+ }
+
+ public void unloaded(ObjectName objectName) {
+ unregister(objectName);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/repository/FileSystemRepository.java b/kernel/src/java/org/gbean/repository/FileSystemRepository.java
new file mode 100644
index 0000000..7ea0d50
--- /dev/null
+++ b/kernel/src/java/org/gbean/repository/FileSystemRepository.java
@@ -0,0 +1,60 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.repository;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class FileSystemRepository implements Repository {
+ private File root;
+
+ public FileSystemRepository() {
+ }
+
+ public FileSystemRepository(File root) {
+ this.root = root;
+ }
+
+ public File getRoot() {
+ return root;
+ }
+
+ public void setRoot(File root) {
+ this.root = root;
+ }
+
+ public boolean containsResource(URI uri) {
+ uri = root.toURI().resolve(uri);
+ File file = new File(uri);
+ return file.canRead();
+ }
+
+ public URL getResource(URI uri) {
+ uri = root.toURI().resolve(uri);
+ File file = new File(uri);
+ try {
+ return file.toURL();
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Malformed resource " + uri);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/repository/Repository.java b/kernel/src/java/org/gbean/repository/Repository.java
new file mode 100644
index 0000000..ea0bff9
--- /dev/null
+++ b/kernel/src/java/org/gbean/repository/Repository.java
@@ -0,0 +1,29 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.repository;
+
+import java.net.URI;
+import java.net.URL;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface Repository {
+ boolean containsResource(URI uri);
+
+ URL getResource(URI uri);
+}
diff --git a/kernel/src/java/org/gbean/service/AbstractServiceFactory.java b/kernel/src/java/org/gbean/service/AbstractServiceFactory.java
new file mode 100644
index 0000000..12d91fb
--- /dev/null
+++ b/kernel/src/java/org/gbean/service/AbstractServiceFactory.java
@@ -0,0 +1,72 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.service;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public abstract class AbstractServiceFactory implements ServiceFactory {
+ private boolean enabled = true;
+ private Map dependencies = new HashMap();
+
+ public Map getDependencies() {
+ return dependencies;
+ }
+
+ public void addDependency(String name, Set patterns) {
+ dependencies.put(name, patterns);
+ }
+
+ public void destroyService(ServiceContext serviceContext, Object service) {
+ }
+
+ public Set getPropertyNames() {
+ return Collections.EMPTY_SET;
+ }
+
+ public Map getProperties() {
+ return Collections.EMPTY_MAP;
+ }
+
+ public void setProperties(Map properties) {
+ assert properties != null;
+ if (properties.size() > 0) {
+ throw new IllegalArgumentException("This service factory does not have any properties");
+ }
+ }
+
+ public Object getProperty(String name) {
+ throw new IllegalArgumentException("This service factory does not have any properties");
+ }
+
+ public void setProperty(String name, Object value) {
+ throw new IllegalArgumentException("This service factory does not have any properties");
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+}
diff --git a/kernel/src/java/org/gbean/service/ConfigurableServiceFactory.java b/kernel/src/java/org/gbean/service/ConfigurableServiceFactory.java
new file mode 100644
index 0000000..cdba60b
--- /dev/null
+++ b/kernel/src/java/org/gbean/service/ConfigurableServiceFactory.java
@@ -0,0 +1,30 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.service;
+
+import java.util.Set;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ConfigurableServiceFactory extends ServiceFactory {
+ Set getPropertyNames();
+
+ Object getProperty(String name);
+
+ void setProperty(String name, Object value);
+}
diff --git a/kernel/src/java/org/gbean/service/DynamicService.java b/kernel/src/java/org/gbean/service/DynamicService.java
new file mode 100644
index 0000000..270858b
--- /dev/null
+++ b/kernel/src/java/org/gbean/service/DynamicService.java
@@ -0,0 +1,25 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.service;
+
+public interface DynamicService {
+ Object getAttribute(String s) throws Exception;
+
+ void setAttribute(String s, Object o) throws Exception;
+
+ Object invoke(String s, Object[] objects, String[] strings) throws Exception;
+}
\ No newline at end of file
diff --git a/kernel/src/java/org/gbean/service/ServiceContext.java b/kernel/src/java/org/gbean/service/ServiceContext.java
new file mode 100644
index 0000000..77b0201
--- /dev/null
+++ b/kernel/src/java/org/gbean/service/ServiceContext.java
@@ -0,0 +1,60 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.service;
+
+import org.gbean.kernel.Kernel;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ServiceContext {
+ /**
+ * Gets the object name under which this bean is registered
+ * @return the object name of this bean
+ */
+ String getObjectName();
+
+ /**
+ * Gets the kernel in which this bean is registered
+ * @return the kernel in which this bean is register
+ */
+ Kernel getKernel();
+
+ /**
+ * Gets the class loader used to construct this bean
+ * @return thhe class loader in which this bean was constructed
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Gets the state of this component as an int.
+ * The int return is required by the JSR77 specification.
+ *
+ * @return the current state of this component
+ */
+ int getState();
+
+ /**
+ * Attempt to bring the component into the fully stopped state. If an exception occurs while
+ * stopping the component, the component is automaticaly failed.
+ * <p/>
+ * There is no guarantee that the service will be stopped when the method returns.
+ *
+ * @throws Exception if a problem occurs while stopping the component
+ */
+ void stop() throws Exception;
+}
diff --git a/kernel/src/java/org/gbean/service/ServiceFactory.java b/kernel/src/java/org/gbean/service/ServiceFactory.java
new file mode 100644
index 0000000..98b50f4
--- /dev/null
+++ b/kernel/src/java/org/gbean/service/ServiceFactory.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.service;
+
+import java.util.Set;
+import java.util.Map;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface ServiceFactory {
+ Map getDependencies();
+
+ void addDependency(String name, Set patterns);
+
+ Object createService(ServiceContext serviceContext) throws Exception;
+
+ void destroyService(ServiceContext serviceContext, Object service);
+
+ boolean isEnabled();
+
+ void setEnabled(boolean enabled);
+}
diff --git a/kernel/src/java/org/gbean/spring/AbstractSpringVisitor.java b/kernel/src/java/org/gbean/spring/AbstractSpringVisitor.java
new file mode 100644
index 0000000..e69657d
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/AbstractSpringVisitor.java
@@ -0,0 +1,134 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public abstract class AbstractSpringVisitor implements SpringVisitor {
+ public void visitBeanFactory(ConfigurableListableBeanFactory beanRegistry, Object data) throws BeansException {
+ String[] beanNames = beanRegistry.getBeanDefinitionNames();
+ for (int i = 0; i < beanNames.length; i++) {
+ String beanName = beanNames[i];
+ visitBeanDefinition(beanName, beanRegistry.getBeanDefinition(beanName), data);
+ }
+ }
+
+ public void visitBeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder, Object data) throws BeansException {
+ visitBeanDefinition(beanDefinitionHolder.getBeanName(), beanDefinitionHolder.getBeanDefinition(), data);
+ }
+
+ public void visitBeanDefinition(String beanName, BeanDefinition beanDefinition, Object data) throws BeansException {
+ visitBeanDefinition(beanDefinition, data);
+ }
+
+ public void visitBeanDefinition(BeanDefinition beanDefinition, Object data) throws BeansException {
+ visitConstructorArgumentValues(beanDefinition.getConstructorArgumentValues(), data);
+ visitMutablePropertyValues(beanDefinition.getPropertyValues(), data);
+ }
+
+ public void visitMutablePropertyValues(MutablePropertyValues propertyValues, Object data) throws BeansException {
+ PropertyValue[] values = propertyValues.getPropertyValues();
+ for (int i = 0; i < values.length; i++) {
+ visitPropertyValue(values[i], data);
+ }
+ }
+
+ public void visitConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues, Object data) throws BeansException {
+ Map indexedArgumentValues = constructorArgumentValues.getIndexedArgumentValues();
+ for (Iterator iterator = indexedArgumentValues.values().iterator(); iterator.hasNext();) {
+ visitConstructorArgumentValue((ConstructorArgumentValues.ValueHolder) iterator.next(), data);
+ }
+ List genericArgumentValues = constructorArgumentValues.getGenericArgumentValues();
+ for (Iterator iterator = genericArgumentValues.iterator(); iterator.hasNext();) {
+ visitConstructorArgumentValue((ConstructorArgumentValues.ValueHolder) iterator.next(), data);
+ }
+ }
+
+ public void visitConstructorArgumentValue(ConstructorArgumentValues.ValueHolder valueHolder, Object data) throws BeansException {
+ visitNext(valueHolder.getValue(), data);
+ }
+
+ public void visitPropertyValue(PropertyValue propertyValue, Object data) throws BeansException {
+ visitNext(propertyValue.getValue(), data);
+ }
+
+ public void visitRuntimeBeanReference(RuntimeBeanReference beanReference, Object data) throws BeansException {
+ }
+
+ public void visitCollection(Collection collection, Object data) throws BeansException {
+ for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
+ visitNext(iterator.next(), data);
+ }
+ }
+
+ public void visitMap(Map map, Object data) throws BeansException {
+ for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ visitNext(entry.getKey(), data);
+ visitNext(entry.getValue(), data);
+ }
+ }
+
+ public void visitObject(Object value, Object data) throws BeansException {
+ }
+
+ protected void visitNext(Object value, Object data) throws BeansException {
+ if (value == null) {
+ return;
+ }
+
+ if (value instanceof ConfigurableListableBeanFactory) {
+ visitBeanFactory((ConfigurableListableBeanFactory) value, data);
+ } else if (value instanceof BeanDefinitionHolder) {
+ visitBeanDefinitionHolder((BeanDefinitionHolder) value, data);
+ } else if (value instanceof BeanDefinition) {
+ visitBeanDefinition((BeanDefinition) value, data);
+ } else if (value instanceof ConstructorArgumentValues) {
+ visitConstructorArgumentValues((ConstructorArgumentValues) value, data);
+ } else if (value instanceof ConstructorArgumentValues.ValueHolder) {
+ visitConstructorArgumentValue((ConstructorArgumentValues.ValueHolder) value, data);
+ } else if (value instanceof MutablePropertyValues) {
+ visitMutablePropertyValues((MutablePropertyValues) value, data);
+ } else if (value instanceof PropertyValue) {
+ visitPropertyValue((PropertyValue) value, data);
+ } else if (value instanceof RuntimeBeanReference) {
+ visitRuntimeBeanReference((RuntimeBeanReference) value, data);
+ } else if (value instanceof Map) {
+ visitMap((Map) value, data);
+ } else if (value instanceof Collection) {
+ visitCollection((Collection) value, data);
+ } else {
+ visitObject(value, data);
+ }
+ }
+
+}
diff --git a/kernel/src/java/org/gbean/spring/ClassLoaderReference.java b/kernel/src/java/org/gbean/spring/ClassLoaderReference.java
new file mode 100644
index 0000000..6a67e44
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/ClassLoaderReference.java
@@ -0,0 +1,51 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class ClassLoaderReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(ClassLoaderReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, ClassLoaderReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return ClassLoader.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ return serviceContext.getClassLoader();
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/DefaultProperty.java b/kernel/src/java/org/gbean/spring/DefaultProperty.java
new file mode 100644
index 0000000..a620d76
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/DefaultProperty.java
@@ -0,0 +1,63 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class DefaultProperty {
+ private String name;
+ private Class type;
+ private Object value;
+
+ public DefaultProperty() {
+ }
+
+ public DefaultProperty(String name, Class type, Object value) {
+ this.name = name;
+ this.type = type;
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ return "[" + name + ", " + type + ", " + value + "]";
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/DependencyProvider.java b/kernel/src/java/org/gbean/spring/DependencyProvider.java
new file mode 100644
index 0000000..4b32409
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/DependencyProvider.java
@@ -0,0 +1,26 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Map;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface DependencyProvider {
+ Map getDependencies();
+}
diff --git a/kernel/src/java/org/gbean/spring/FatalStartupError.java b/kernel/src/java/org/gbean/spring/FatalStartupError.java
new file mode 100644
index 0000000..d65c11e
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/FatalStartupError.java
@@ -0,0 +1,47 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class FatalStartupError extends Error {
+ private final int exitCode;
+ private static final int DEFAULT_EXIT_CODE = 3;
+
+ public FatalStartupError(String message) {
+ this(message, DEFAULT_EXIT_CODE);
+ }
+
+ public FatalStartupError(String message, int exitCode) {
+ super(message);
+ this.exitCode = exitCode;
+ }
+
+ public FatalStartupError(String message, Throwable cause) {
+ this(message, DEFAULT_EXIT_CODE, cause);
+ }
+
+ public FatalStartupError(String message, int exitCode, Throwable cause) {
+ super(message, cause);
+ this.exitCode = exitCode;
+ }
+
+ public int getExitCode() {
+ return exitCode;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/KernelReference.java b/kernel/src/java/org/gbean/spring/KernelReference.java
new file mode 100644
index 0000000..93e846c
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/KernelReference.java
@@ -0,0 +1,52 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+
+import org.gbean.kernel.Kernel;
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class KernelReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(KernelReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, KernelReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return Kernel.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ return serviceContext.getKernel();
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/LifecycleDetector.java b/kernel/src/java/org/gbean/spring/LifecycleDetector.java
new file mode 100644
index 0000000..8dce222
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/LifecycleDetector.java
@@ -0,0 +1,104 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LifecycleDetector implements BeanFactoryPostProcessor {
+ private final Map lifecycleMap = new LinkedHashMap();
+
+ public List getLifecycleInterfaces() {
+ List lifecycleInterfaces = new LinkedList();
+ for (Iterator iterator = lifecycleMap.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ Class type = (Class) entry.getKey();
+ LifecycleMethods lifecycleMethods = (LifecycleMethods) entry.getValue();
+ lifecycleInterfaces.add(new LifecycleInfo(type, lifecycleMethods.initMethodName, lifecycleMethods.destroyMethodName));
+ }
+ return lifecycleInterfaces;
+ }
+
+ public void setLifecycleInterfaces(List lifecycleInterfaces) {
+ lifecycleMap.clear();
+ for (Iterator iterator = lifecycleInterfaces.iterator(); iterator.hasNext();) {
+ addLifecycleInterface((LifecycleInfo) iterator.next());
+ }
+ }
+
+ public void addLifecycleInterface(Class type, String initMethodName, String destroyMethodName) {
+ lifecycleMap.put(type, new LifecycleMethods(initMethodName, destroyMethodName));
+ }
+
+ public void addLifecycleInterface(LifecycleInfo lifecycleInfo) {
+ lifecycleMap.put(lifecycleInfo.getType(),
+ new LifecycleMethods(lifecycleInfo.getInitMethodName(), lifecycleInfo.getDestroyMethodName()));
+ }
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ SpringVisitor visitor = new AbstractSpringVisitor() {
+ public void visitBeanDefinition(BeanDefinition beanDefinition, Object data) throws BeansException {
+ super.visitBeanDefinition(beanDefinition, data);
+
+ if (!(beanDefinition instanceof RootBeanDefinition)) {
+ return;
+ }
+ RootBeanDefinition rootBeanDefinition = ((RootBeanDefinition) beanDefinition);
+ Class beanType = rootBeanDefinition.getBeanClass();
+ for (Iterator iterator = lifecycleMap.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ Class lifecycleInterface = (Class) entry.getKey();
+ LifecycleMethods value = (LifecycleMethods) entry.getValue();
+ if (lifecycleInterface.isAssignableFrom(beanType)) {
+ if (rootBeanDefinition.getInitMethodName() == null) {
+ rootBeanDefinition.setInitMethodName(value.initMethodName);
+ }
+ if (rootBeanDefinition.getDestroyMethodName() == null) {
+ rootBeanDefinition.setDestroyMethodName(value.destroyMethodName);
+ }
+ if (rootBeanDefinition.getInitMethodName() != null && rootBeanDefinition.getDestroyMethodName() != null) {
+ return;
+ }
+ }
+ }
+ }
+ };
+ visitor.visitBeanFactory(beanFactory, null);
+ }
+
+ private static class LifecycleMethods {
+ private String initMethodName;
+ private String destroyMethodName;
+
+ public LifecycleMethods(String initMethodName, String destroyMethodName) {
+ this.initMethodName = initMethodName;
+ this.destroyMethodName = destroyMethodName;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/LifecycleInfo.java b/kernel/src/java/org/gbean/spring/LifecycleInfo.java
new file mode 100644
index 0000000..e80eaf2
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/LifecycleInfo.java
@@ -0,0 +1,59 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LifecycleInfo {
+ private Class type;
+ private String initMethodName;
+ private String destroyMethodName;
+
+ public LifecycleInfo() {
+ }
+
+ public LifecycleInfo(Class type, String initMethodName, String destroyMethodName) {
+ this.type = type;
+ this.initMethodName = initMethodName;
+ this.destroyMethodName = destroyMethodName;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public String getInitMethodName() {
+ return initMethodName;
+ }
+
+ public void setInitMethodName(String initMethodName) {
+ this.initMethodName = initMethodName;
+ }
+
+ public String getDestroyMethodName() {
+ return destroyMethodName;
+ }
+
+ public void setDestroyMethodName(String destroyMethodName) {
+ this.destroyMethodName = destroyMethodName;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/LiveHashSetReference.java b/kernel/src/java/org/gbean/spring/LiveHashSetReference.java
new file mode 100644
index 0000000..ba48d49
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/LiveHashSetReference.java
@@ -0,0 +1,91 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.beans.LiveHashSet;
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class LiveHashSetReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition(String name, Set patterns) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(LiveHashSetReference.class, 0);
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ propertyValues.addPropertyValue("name", name);
+ propertyValues.addPropertyValue("patterns", patterns);
+ return new BeanDefinitionHolder(beanDefinition, LiveHashSetReference.class.getName());
+ }
+
+ /**
+ * Name of this reference.
+ */
+ private String name;
+
+ /**
+ * The target objectName patterns to watch for a connection.
+ */
+ private Set patterns;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getPatterns() {
+ return patterns;
+ }
+
+ public void setPatterns(Set patterns) {
+ this.patterns = patterns;
+ }
+
+ public void setPattern(ObjectName pattern) {
+ this.patterns = Collections.singleton(pattern);
+ }
+
+ public final Class getObjectType() {
+ return Set.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ LiveHashSet liveHashSet = new LiveHashSet(serviceContext.getKernel(), name, patterns);
+ liveHashSet.start();
+ return liveHashSet;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/LiveProxyHashSetReference.java b/kernel/src/java/org/gbean/spring/LiveProxyHashSetReference.java
new file mode 100644
index 0000000..9c03e68
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/LiveProxyHashSetReference.java
@@ -0,0 +1,107 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.gbean.beans.LiveProxyHashSet;
+import org.gbean.kernel.ClassLoading;
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class LiveProxyHashSetReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition(String name, Set patterns, String type) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(LiveHashSetReference.class, 0);
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ propertyValues.addPropertyValue("name", name);
+ propertyValues.addPropertyValue("patterns", patterns);
+ propertyValues.addPropertyValue("type", type);
+ return new BeanDefinitionHolder(beanDefinition, LiveHashSetReference.class.getName());
+ }
+
+ /**
+ * Name of this reference.
+ */
+ private String name;
+
+ /**
+ * Proxy type which is injected into the service.
+ */
+ private String type;
+
+ /**
+ * The target objectName patterns to watch for a connection.
+ */
+ private Set patterns;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public Set getPatterns() {
+ return patterns;
+ }
+
+ public void setPatterns(Set patterns) {
+ this.patterns = patterns;
+ }
+
+ public void setPattern(ObjectName pattern) {
+ this.patterns = Collections.singleton(pattern);
+ }
+
+ public final Class getObjectType() {
+ return Set.class;
+ }
+
+ public synchronized final Object getObject() throws ClassNotFoundException {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ Class proxyType = ClassLoading.loadClass(type, serviceContext.getClassLoader());
+ LiveProxyHashSet liveProxyHashSet = new LiveProxyHashSet(serviceContext.getKernel(), name, patterns, proxyType);
+ liveProxyHashSet.start();
+ return liveProxyHashSet;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/NamedConstructorArgs.java b/kernel/src/java/org/gbean/spring/NamedConstructorArgs.java
new file mode 100644
index 0000000..38436b4
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/NamedConstructorArgs.java
@@ -0,0 +1,290 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.LinkedList;
+
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.metadata.ParameterMetadata;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.FactoryBean;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class NamedConstructorArgs implements BeanFactoryPostProcessor {
+ private MetadataManager metadataManager;
+ private Map defaultValues = new HashMap();
+
+ public NamedConstructorArgs() {
+ }
+
+ public NamedConstructorArgs(MetadataManager metadataManager) {
+ this.metadataManager = metadataManager;
+ }
+
+ public MetadataManager getMetadataManager() {
+ return metadataManager;
+ }
+
+ public void setMetadataManager(MetadataManager metadataManager) {
+ this.metadataManager = metadataManager;
+ }
+
+ public List getDefaultValues() {
+ List values = new LinkedList();
+ for (Iterator iterator = defaultValues.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ PropertyKey key = (PropertyKey) entry.getKey();
+ Object value = entry.getValue();
+ values.add(new DefaultProperty(key.name, key.type, value));
+ }
+ return values;
+ }
+
+ public void setDefaultValues(List defaultValues) {
+ this.defaultValues.clear();
+ for (Iterator iterator = defaultValues.iterator(); iterator.hasNext();) {
+ addDefaultValue((DefaultProperty) iterator.next());
+ }
+ }
+
+ public void addDefaultValue(String name, Class type, Object value) {
+ defaultValues.put(new PropertyKey(name, type), value);
+ }
+
+ private void addDefaultValue(DefaultProperty defaultProperty) {
+ defaultValues.put(new PropertyKey(defaultProperty.getName(), defaultProperty.getType()), defaultProperty.getValue());
+ }
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ SpringVisitor visitor = new AbstractSpringVisitor() {
+ public void visitBeanDefinition(BeanDefinition beanDefinition, Object data) throws BeansException {
+ super.visitBeanDefinition(beanDefinition, data);
+
+ if (!(beanDefinition instanceof RootBeanDefinition)) {
+ return;
+ }
+
+ RootBeanDefinition rootBeanDefinition = ((RootBeanDefinition) beanDefinition);
+ processParameters(rootBeanDefinition);
+
+ }
+ };
+ visitor.visitBeanFactory(beanFactory, null);
+ }
+
+ private void processParameters(RootBeanDefinition rootBeanDefinition) throws BeansException {
+ ConstructorArgumentValues constructorArgumentValues = rootBeanDefinition.getConstructorArgumentValues();
+
+ // if this bean already has constructor arguments defined, don't mess with them
+ if (constructorArgumentValues.getArgumentCount() > 0) {
+ return;
+ }
+
+ // try to get a list of constructor arg names to use
+ ConstructorMetadata constructorMetadata = getConstructor(rootBeanDefinition);
+ if (constructorMetadata == null) {
+ return;
+ }
+
+ // remove each named property and add an indexed constructor arg
+ MutablePropertyValues propertyValues = rootBeanDefinition.getPropertyValues();
+ List parameters = constructorMetadata.getParameters();
+ for (ListIterator iterator = parameters.listIterator(); iterator.hasNext();) {
+ ParameterMetadata parameterMetadata = (ParameterMetadata) iterator.next();
+ String name = (String) parameterMetadata.get("name");
+
+ Class parameterType = parameterMetadata.getType();
+ PropertyValue propertyValue = propertyValues.getPropertyValue(name);
+ if (propertyValue != null) {
+ propertyValues.removePropertyValue(name);
+ constructorArgumentValues.addIndexedArgumentValue(iterator.previousIndex(), propertyValue.getValue(), parameterType.getName());
+ } else {
+ Object defaultValue = defaultValues.get(new PropertyKey(name, parameterType));
+ if (defaultValue == null) {
+ defaultValue = DEFAULT_VALUE.get(parameterType);
+ }
+ if (defaultValue instanceof FactoryBean) {
+ try {
+ defaultValue = ((FactoryBean)defaultValue).getObject();
+ } catch (Exception e) {
+ throw new FatalBeanException("Unable to get object value from bean factory", e);
+ }
+ }
+ constructorArgumentValues.addIndexedArgumentValue(iterator.previousIndex(), defaultValue, parameterType.getName());
+ }
+ }
+
+ // todo set any usable default values on the bean definition
+ }
+
+ private ConstructorMetadata getConstructor(RootBeanDefinition rootBeanDefinition) {
+ Class beanType = rootBeanDefinition.getBeanClass();
+
+ // try to get the class metadata
+ ClassMetadata classMetadata = metadataManager.getClassMetadata(beanType);
+
+ // get a set containing the names of the defined properties
+ Set propertyNames = new HashSet();
+ PropertyValue[] values = rootBeanDefinition.getPropertyValues().getPropertyValues();
+ for (int i = 0; i < values.length; i++) {
+ propertyNames.add(values[i].getName());
+ }
+
+ // get the constructors sorted by longest arg length first
+ List constructors = new ArrayList(classMetadata.getConstructors());
+ Collections.sort(constructors, new ArgLengthComparator());
+
+ // try to find a constructor for which we have all of the properties defined
+ for (Iterator iterator = constructors.iterator(); iterator.hasNext();) {
+ ConstructorMetadata constructorMetadata = (ConstructorMetadata) iterator.next();
+ if (isUsableConstructor(constructorMetadata, propertyNames)) {
+ return constructorMetadata;
+ }
+ }
+ return null;
+ }
+
+ private boolean isUsableConstructor(ConstructorMetadata constructorMetadata, Set propertyNames) {
+ if (constructorMetadata.getProperties().containsKey("always-use")) {
+ return true;
+ }
+
+ LinkedHashMap constructorArgs = getConstructorArgs(constructorMetadata);
+ if (constructorArgs == null) {
+ return false;
+ }
+
+ for (Iterator argIterator = constructorArgs.entrySet().iterator(); argIterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) argIterator.next();
+ String parameterName = (String) entry.getKey();
+ Class parameterType = (Class) entry.getValue();
+ // can we satify this property using a definde proeprty or default property
+ if (!propertyNames.contains(parameterName) && !defaultValues.containsKey(new PropertyKey(parameterName, parameterType))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private LinkedHashMap getConstructorArgs(ConstructorMetadata constructor) {
+ LinkedHashMap constructorArgs = new LinkedHashMap();
+
+ List parameterMetadata = constructor.getParameters();
+ for (Iterator iterator = parameterMetadata.iterator(); iterator.hasNext();) {
+ ParameterMetadata parameter = (ParameterMetadata) iterator.next();
+ String name = (String) parameter.get("name");
+ if (name == null) {
+ return null;
+ }
+ constructorArgs.put(name, parameter.getType());
+ }
+ return constructorArgs;
+ }
+
+ private static class ArgLengthComparator implements Comparator {
+ public int compare(Object o1, Object o2) {
+ ConstructorMetadata constructor1 = (ConstructorMetadata) o1;
+ ConstructorMetadata constructor2 = (ConstructorMetadata) o2;
+ return constructor2.getParameters().size() - constructor1.getParameters().size();
+ }
+ }
+
+ private static class PropertyKey {
+ private String name;
+ private Class type;
+
+ public PropertyKey(String name, Class type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Class getType() {
+ return type;
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public boolean equals(Object object) {
+ if (!(object instanceof PropertyKey)) {
+ return false;
+ }
+
+ PropertyKey defaultProperty = (PropertyKey) object;
+ return name.equals(defaultProperty.name) && type.equals(type);
+ }
+
+ public int hashCode() {
+ int result = 17;
+ result = 37 * result + name.hashCode();
+ result = 37 * result + type.hashCode();
+ return result;
+ }
+
+ public String toString() {
+ return "[" + name + " " + type + "]";
+ }
+ }
+
+ private static final Map DEFAULT_VALUE;
+ static {
+ Map temp = new HashMap();
+ temp.put(Boolean.TYPE, Boolean.FALSE);
+ temp.put(Byte.TYPE, new Byte((byte) 0));
+ temp.put(Character.TYPE, new Character((char) 0));
+ temp.put(Short.TYPE, new Short((short) 0));
+ temp.put(Integer.TYPE, new Integer(0));
+ temp.put(Long.TYPE, new Long(0));
+ temp.put(Float.TYPE, new Float(0));
+ temp.put(Double.TYPE, new Double(0));
+
+ DEFAULT_VALUE = Collections.unmodifiableMap(temp);
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/ObjectNameBuilder.java b/kernel/src/java/org/gbean/spring/ObjectNameBuilder.java
new file mode 100644
index 0000000..5a18b55
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/ObjectNameBuilder.java
@@ -0,0 +1,102 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import javax.management.ObjectName;
+
+import org.gbean.kernel.ServiceName;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.MetadataManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ObjectNameBuilder implements BeanFactoryPostProcessor {
+ private static final String OBJECT_NAME_PROPERTY = "gbean-object-name";
+ private final MetadataManager metadataManager;
+ private final String domainName;
+ private final String serverName;
+ private final String moduleName;
+ private final Map objectNameMap = new HashMap();
+
+ public ObjectNameBuilder(MetadataManager metadataManager, String domainName, String serverName, String moduleName) {
+ this.metadataManager = metadataManager;
+ this.domainName = domainName;
+ this.serverName = serverName;
+ this.moduleName = moduleName;
+ }
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ String[] beanNames = beanFactory.getBeanDefinitionNames();
+ if (beanNames == null) {
+ return;
+ }
+ for (int i = 0; i < beanNames.length; i++) {
+ String beanName = beanNames[i];
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ if (beanDefinition instanceof RootBeanDefinition) {
+ ObjectName objectName = buildObjectName(beanName, (RootBeanDefinition) beanDefinition);
+ objectNameMap.put(beanName, objectName);
+ }
+ }
+ }
+
+ private ObjectName buildObjectName(String beanName, RootBeanDefinition beanDefinition) {
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ if (propertyValues.contains(OBJECT_NAME_PROPERTY)) {
+ String objectNameString = (String) propertyValues.getPropertyValue(OBJECT_NAME_PROPERTY).getValue();
+ propertyValues.removePropertyValue(OBJECT_NAME_PROPERTY);
+ return ServiceName.createName(objectNameString);
+ } else {
+ ClassMetadata classMetadata = metadataManager.getClassMetadata(beanDefinition.getBeanClass());
+
+ String type = (String) classMetadata.get("j2eeType");
+ return createObjectName(beanName, type);
+ }
+ }
+
+ public Map getObjectNameMap() {
+ return objectNameMap;
+ }
+
+ public ObjectName getObjectName(String beanName) {
+ return (ObjectName) objectNameMap.get(beanName);
+ }
+
+ private ObjectName createObjectName(String name, String type) {
+ Properties props = new Properties();
+ if (type != null) {
+ props.put("j2eeType", type);
+ }
+ props.put("name", name);
+ props.put("J2EEApplication", "null");
+ props.put("J2EEModule", moduleName);
+ props.put("J2EEServer", serverName);
+
+ return ServiceName.createName(domainName, props);
+ }
+
+}
diff --git a/kernel/src/java/org/gbean/spring/ObjectNameReference.java b/kernel/src/java/org/gbean/spring/ObjectNameReference.java
new file mode 100644
index 0000000..fa65008
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/ObjectNameReference.java
@@ -0,0 +1,53 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class ObjectNameReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(ObjectNameReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, ObjectNameReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return ObjectName.class;
+ }
+
+ public synchronized final Object getObject() throws MalformedObjectNameException {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ return new ObjectName(serviceContext.getObjectName());
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/ObjectNameStringReference.java b/kernel/src/java/org/gbean/spring/ObjectNameStringReference.java
new file mode 100644
index 0000000..a692745
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/ObjectNameStringReference.java
@@ -0,0 +1,51 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.Serializable;
+
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class ObjectNameStringReference implements FactoryBean, Serializable {
+ public static BeanDefinitionHolder createBeanDefinition() {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(ObjectNameStringReference.class, 0);
+ return new BeanDefinitionHolder(beanDefinition, ObjectNameStringReference.class.getName());
+ }
+
+ public final Class getObjectType() {
+ return String.class;
+ }
+
+ public synchronized final Object getObject() {
+ ServiceContext serviceContext = ServiceContextThreadLocal.get();
+ if (serviceContext == null) {
+ throw new IllegalStateException("Service context has not been set");
+ }
+ return serviceContext.getObjectName();
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/ServiceContextThreadLocal.java b/kernel/src/java/org/gbean/spring/ServiceContextThreadLocal.java
new file mode 100644
index 0000000..d0d4110
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/ServiceContextThreadLocal.java
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import org.gbean.service.ServiceContext;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public final class ServiceContextThreadLocal {
+ private ServiceContextThreadLocal() {
+ }
+
+ private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
+
+ public static ServiceContext get() {
+ return (ServiceContext) THREAD_LOCAL.get();
+ }
+
+ public static void set(ServiceContext serviceContext) {
+ THREAD_LOCAL.set(serviceContext);
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringBootstrap.java b/kernel/src/java/org/gbean/spring/SpringBootstrap.java
new file mode 100644
index 0000000..e4a1a4a
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringBootstrap.java
@@ -0,0 +1,161 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.beans.PropertyEditorManager;
+import java.io.File;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.gbean.kernel.Main;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.FatalBeanException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SpringBootstrap {
+ private static final String GBEAN_BOOTSTRAP_MANIFEST = "GBean-Bootstrap";
+ private static final String BOOTSTRAP_FLAG = "--bootstrap";
+ private static final String DEFAULT_BOOTSTRAP = "META-INF/gbean-bootstrap.xml";
+
+ public static void main(String[] args) {
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(SpringBootstrap.class.getClassLoader());
+ try {
+ // lame hard coded log initialization
+ Logger root = Logger.getRootLogger();
+ root.addAppender(new ConsoleAppender(new PatternLayout("%d{ABSOLUTE} %-5p [%c{1}] %m%n")));
+ root.setLevel(Level.INFO);
+
+ // add our property editors into the system
+ List editorSearchPath = new LinkedList(Arrays.asList(PropertyEditorManager.getEditorSearchPath()));
+ editorSearchPath.add("org.gbean.propertyeditor");
+ PropertyEditorManager.setEditorSearchPath((String[]) editorSearchPath.toArray(new String[editorSearchPath.size()]));
+
+ // check if bootstrap configuration was specified on the command line
+ String gbeanBootstrap = null;
+ if (args.length > 1 && BOOTSTRAP_FLAG.equals(args[0])) {
+ gbeanBootstrap = args[1];
+ }
+
+ // Determine the gbean installation directory
+ // guess from the location of the jar
+ File baseDirectory;
+ URL url = SpringBootstrap.class.getClassLoader().getResource("META-INF/startup-jar");
+ if (url != null) {
+ try {
+ JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
+ url = jarConnection.getJarFileURL();
+
+ URI baseURI = new URI(url.toString()).resolve("..");
+ baseDirectory = new File(baseURI);
+
+ Manifest manifest;
+ manifest = jarConnection.getManifest();
+ Attributes mainAttributes = manifest.getMainAttributes();
+ if (gbeanBootstrap == null) {
+ gbeanBootstrap = mainAttributes.getValue(GBEAN_BOOTSTRAP_MANIFEST);
+ }
+ } catch (Exception e) {
+ System.err.println("Could not determine gbean installation directory");
+ e.printStackTrace();
+ System.exit(9);
+ return;
+ }
+ } else {
+ String dir = System.getProperty("gbean.base.dir", System.getProperty("user.dir"));
+ baseDirectory = new File(dir);
+ }
+ System.setProperty("gbean.base.dir", baseDirectory.getAbsolutePath());
+
+ if (gbeanBootstrap == null) {
+ gbeanBootstrap = DEFAULT_BOOTSTRAP;
+ }
+
+ // check if bootstrap is a file
+ BeanFactory factory = createBeanFactory(baseDirectory, gbeanBootstrap);
+ Main main = (Main) factory.getBean("Main");
+
+ // start it up
+ try {
+ main.main(args);
+ } catch (FatalStartupError e) {
+ System.err.println(e.getMessage());
+ if (e.getCause() != null) {
+ e.getCause().printStackTrace();
+ }
+ System.exit(e.getExitCode());
+ } catch (Throwable e) {
+ System.err.println("Unknown error");
+ e.printStackTrace();
+ System.exit(9);
+ }
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+ }
+
+ private static BeanFactory createBeanFactory(File baseDirectory, String gbeanBootstrap) {
+ // check if bootstrap file is on the local file system first
+ URI uri = baseDirectory.toURI().resolve(gbeanBootstrap);
+ File bootstrapFile = new File(uri);
+ if (bootstrapFile.canRead()) {
+ try {
+ return new GBeanXmlApplicationContext(bootstrapFile.toURL().toString());
+ } catch (MalformedURLException e) {
+ throw new FatalBeanException("Error creating url for bootstrap file", e);
+ }
+ }
+
+ // assume it is a classpath resource
+ return new GBeanXmlApplicationContext("classpath:" + gbeanBootstrap);
+ }
+
+ public static class GBeanXmlApplicationContext extends AbstractXmlApplicationContext {
+ private String[] configLocations;
+
+ public GBeanXmlApplicationContext(String configLocation) throws BeansException {
+ this.configLocations = new String[]{configLocation};
+ refresh();
+ }
+
+ public GBeanXmlApplicationContext(String configLocation, ApplicationContext parent) throws BeansException {
+ super(parent);
+ this.configLocations = new String[]{configLocation};
+ refresh();
+ }
+
+ protected String[] getConfigLocations() {
+ return this.configLocations;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringConfiguration.java b/kernel/src/java/org/gbean/spring/SpringConfiguration.java
new file mode 100644
index 0000000..19f75e6
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringConfiguration.java
@@ -0,0 +1,150 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.configuration.Configuration;
+import org.gbean.configuration.ConfigurationInfo;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.runtime.ServiceState;
+import org.gbean.kernel.simple.SimpleLifecycle;
+import org.gbean.service.ServiceFactory;
+import org.gbean.classloader.DestroyableClassLoader;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SpringConfiguration implements Configuration, SimpleLifecycle {
+ private static final Log log = LogFactory.getLog(SpringConfiguration.class);
+
+ public static ObjectName getConfigurationObjectName(URI configId) throws MalformedObjectNameException {
+ // todo geronimo insists on have the configurations in a domain named geronimo.config
+ return new ObjectName("geronimo.config:name=" + ObjectName.quote(configId.toString()));
+ }
+
+ private final Kernel kernel;
+
+ private final ObjectName objectName;
+
+ private final URI configurationId;
+
+ private final String domain;
+
+ private final String server;
+
+ private final Map serviceFactories;
+
+ private final ClassLoader classLoader;
+
+ public SpringConfiguration(Kernel kernel,
+ ConfigurationInfo configurationInfo,
+ Map serviceFactories,
+ ClassLoader classLoader) throws Exception {
+
+ this.kernel = kernel;
+ this.configurationId = configurationInfo.getConfigurationId();
+ this.objectName = getConfigurationObjectName(configurationId);
+
+ this.domain = configurationInfo.getDomain();
+ this.server = configurationInfo.getServer();
+
+ this.serviceFactories = serviceFactories;
+
+ this.classLoader = classLoader;
+ }
+
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ public URI getConfigurationId() {
+ return configurationId;
+ }
+
+ public URI getParentId() {
+ return null;
+ }
+
+ public String getDomain() {
+ return domain;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ // here for compatability with geronimo
+ public ClassLoader getConfigurationClassLoader() {
+ return classLoader;
+ }
+
+ public Set getServiceNames() {
+ return new HashSet(serviceFactories.keySet());
+ }
+
+ public void start() throws Exception {
+ for (Iterator iterator = serviceFactories.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ ObjectName serviceName = (ObjectName) entry.getKey();
+ ServiceFactory serviceFactory = (ServiceFactory) entry.getValue();
+ serviceFactory.addDependency("SpringConfiguration", Collections.singleton(objectName));
+
+ kernel.loadService(serviceName, serviceFactory, classLoader);
+ kernel.startService(serviceName);
+ int serviceState = kernel.getServiceState(serviceName);
+ String msg = serviceName.getCanonicalName() + " - " + ServiceState.fromIndex(serviceState);
+ log.info(msg);
+ }
+
+ log.info("Started configuration " + configurationId);
+ }
+
+ public void stop() {
+ log.info("Stopping configuration " + configurationId);
+
+ // unregister all services
+ for (Iterator i = serviceFactories.keySet().iterator(); i.hasNext();) {
+ ObjectName serviceName = (ObjectName) i.next();
+ try {
+ log.trace("Unload service " + serviceName);
+ kernel.unloadService(serviceName);
+ } catch (Exception e) {
+ // ignore
+ log.warn("Could not unload service " + serviceName, e);
+ }
+ }
+
+ if (classLoader instanceof DestroyableClassLoader) {
+ DestroyableClassLoader destroyableClassLoader = (DestroyableClassLoader) classLoader;
+ destroyableClassLoader.destroy();
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringLoader.java b/kernel/src/java/org/gbean/spring/SpringLoader.java
new file mode 100644
index 0000000..8a6e9df
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringLoader.java
@@ -0,0 +1,293 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.management.ObjectName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.gbean.configuration.ConfigurationInfo;
+import org.gbean.configuration.ConfigurationUtil;
+import org.gbean.configuration.InvalidConfigurationException;
+import org.gbean.kernel.Kernel;
+import org.gbean.kernel.simple.SimpleServiceFactory;
+import org.gbean.loader.Loader;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.service.ServiceFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SpringLoader implements Loader {
+ private static final Log log = LogFactory.getLog(SpringLoader.class);
+ private static final String CONFIG_ID_NAME = "configId";
+ private static final String PARENT_ID_NAME = "parentId";
+ private static final String DOMAIN_NAME = "domain";
+ private static final String SERVER_NAME = "server";
+
+ private Kernel kernel;
+ private Collection repositories;
+ private MetadataManager metadataManager;
+ private List beanFactoryPostProcessors;
+ private File baseDir;
+
+ public SpringLoader() {
+ }
+
+ public Kernel getKernel() {
+ return kernel;
+ }
+
+ public void setKernel(Kernel kernel) {
+ this.kernel = kernel;
+ }
+
+ public Collection getRepositories() {
+ return repositories;
+ }
+
+ public void setRepositories(Collection repositories) {
+ this.repositories = repositories;
+ }
+
+ public MetadataManager getMetadataManager() {
+ return metadataManager;
+ }
+
+ public void setMetadataManager(MetadataManager metadataManager) {
+ this.metadataManager = metadataManager;
+ }
+
+ public List getBeanFactoryPostProcessors() {
+ return beanFactoryPostProcessors;
+ }
+
+ public void setBeanFactoryPostProcessors(List beanFactoryPostProcessors) {
+ this.beanFactoryPostProcessors = beanFactoryPostProcessors;
+ }
+
+ public File getBaseDir() {
+ return baseDir;
+ }
+
+ public void setBaseDir(File baseDir) {
+ this.baseDir = baseDir;
+ }
+
+ public ObjectName load(String location) {
+ String resolvedLocation = resolveLocation(location);
+ try {
+ ConfigurationInfo configurationInfo = loadConfigurationInfo(resolvedLocation);
+ final ClassLoader classLoader = ConfigurationUtil.createClassLoader(configurationInfo.getConfigurationId().toString(),
+ configurationInfo.getDependencies(),
+ getClass().getClassLoader(),
+ repositories);
+
+ DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
+ try {
+ Resource resource = new FileSystemResource(new File(resolvedLocation + ".xml"));
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory) {
+ public ClassLoader getBeanClassLoader() {
+ return classLoader;
+ }
+ };
+ reader.loadBeanDefinitions(resource);
+ } catch (BeansException e) {
+ // not a spring file
+ return null;
+ }
+
+ // create object names for all of the beans
+ ObjectNameBuilder objectNameBuilder = new ObjectNameBuilder(metadataManager,
+ configurationInfo.getDomain(),
+ configurationInfo.getServer(),
+ configurationInfo.getConfigurationId().toString());
+ objectNameBuilder.postProcessBeanFactory(factory);
+
+ Map serviceFactories = new LinkedHashMap();
+ String[] beanDefinitionNames = factory.getBeanDefinitionNames();
+ if (beanDefinitionNames != null) {
+ for (int i = 0; i < beanDefinitionNames.length; i++) {
+ String beanName = beanDefinitionNames[i];
+ BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
+ ServiceFactory serviceFactory = new SpringServiceFactory((RootBeanDefinition) beanDefinition, objectNameBuilder.getObjectNameMap(), beanFactoryPostProcessors);
+
+ ObjectName objectName = objectNameBuilder.getObjectName(beanName);
+ serviceFactories.put(objectName, serviceFactory);
+ }
+ }
+ SpringConfiguration springConfiguration = new SpringConfiguration(kernel, configurationInfo, serviceFactories, classLoader);
+ SimpleServiceFactory springServiceFactory = new SimpleServiceFactory(springConfiguration);
+ ObjectName configurationObjectName = springConfiguration.getObjectName();
+ kernel.loadService(configurationObjectName, springServiceFactory, classLoader);
+ return configurationObjectName;
+ } catch (InvalidConfigurationException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvalidConfigurationException("Unable to load configuration: " + location, e);
+ }
+ }
+
+ private String resolveLocation(String location) {
+ location = location.replace('/', '.');
+ return baseDir.toURI().resolve(location).getPath();
+ }
+
+ private ConfigurationInfo loadConfigurationInfo(String location) {
+ ConfigurationInfo configurationInfo = new ConfigurationInfo();
+
+ String gbeanLocation = location + "-gbean.xml";
+
+ File file = new File(gbeanLocation);
+ if (!file.canRead()) {
+ configurationInfo.setConfigurationId(createURI(CONFIG_ID_NAME, location));
+ return configurationInfo;
+ }
+
+ InputStream in = null;
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ builder.setErrorHandler(new SimpleSaxErrorHandler(log));
+ in = new FileInputStream(file);
+ Document document = builder.parse(in);
+ loadGBeanConfiguration(configurationInfo, location, document);
+ } catch (ParserConfigurationException e) {
+ throw new InvalidConfigurationException("Parser configuration exception parsing XML from " + gbeanLocation, e);
+ } catch (SAXParseException e) {
+ throw new InvalidConfigurationException("Line " + e.getLineNumber() + " in XML document from " + gbeanLocation + " is invalid", e);
+ } catch (SAXException e) {
+ throw new InvalidConfigurationException("XML document from " + gbeanLocation + " is invalid", e);
+ } catch (IOException ex) {
+ throw new InvalidConfigurationException("IOException parsing XML document from " + gbeanLocation, ex);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException ex) {
+ log.warn("Could not close InputStream", ex);
+ }
+ }
+ }
+ return configurationInfo;
+ }
+
+ private void loadGBeanConfiguration(ConfigurationInfo configurationInfo, String location, Document document) {
+ Element root = document.getDocumentElement();
+
+ // get the configuration id... if not specified use the location name
+ String configurationIdString = root.getAttribute(CONFIG_ID_NAME);
+ URI configurationId;
+ if (configurationIdString.length() > 0) {
+ configurationId = createURI(CONFIG_ID_NAME, configurationIdString);
+ } else {
+ configurationId = createURI(CONFIG_ID_NAME, location);
+ }
+ configurationInfo.setConfigurationId(configurationId);
+
+ // set the parent id if specified
+ String parentIdString = root.getAttribute(PARENT_ID_NAME);
+ URI parentId;
+ if (parentIdString.length() > 0) {
+ parentId = createURI(PARENT_ID_NAME, parentIdString);
+ configurationInfo.setParentId(parentId);
+ }
+
+ // set domain name if specifiec
+ String domain = root.getAttribute(DOMAIN_NAME);
+ if (domain.length() > 0) {
+ configurationInfo.setDomain(domain);
+ }
+
+ // set server name if specified
+ String server = root.getAttribute(SERVER_NAME);
+ if (server.length() > 0) {
+ configurationInfo.setServer(server);
+ }
+
+ // add the dependencies
+ // todo add support for more complex maven style dependencies
+ NodeList dependencies = root.getElementsByTagName("dependency");
+ for (int i = 0; i < dependencies.getLength(); i++) {
+ Element dependencyElement = (Element) dependencies.item(i);
+
+ Element uriElement = (Element) dependencyElement.getElementsByTagName("uri").item(0);
+ if (uriElement == null) {
+ throw new RuntimeException("Excpected one uri element in dependency");
+ }
+
+ String uriString = ((Text) uriElement.getFirstChild()).getData().trim();
+ URI dependency = createURI("dependency uri", uriString);
+ configurationInfo.addDependency(dependency);
+ }
+ }
+
+ private static URI createURI(String name, String uri) {
+ try {
+ return new URI(uri);
+ } catch (URISyntaxException e) {
+ throw new InvalidConfigurationException("Unvalid uri specified for " + name, e);
+ }
+ }
+
+ private static class SimpleSaxErrorHandler implements ErrorHandler {
+ private final Log log;
+
+ public SimpleSaxErrorHandler(Log logger) {
+ this.log = logger;
+ }
+
+ public void warning(SAXParseException e) throws SAXException {
+ log.warn("Ignored XML validation warning: " + e.getMessage(), e);
+ }
+
+ public void error(SAXParseException e) throws SAXException {
+ throw e;
+ }
+
+ public void fatalError(SAXParseException e) throws SAXException {
+ throw e;
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringServiceFactory.java b/kernel/src/java/org/gbean/spring/SpringServiceFactory.java
new file mode 100644
index 0000000..add3525
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringServiceFactory.java
@@ -0,0 +1,263 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.gbean.service.ConfigurableServiceFactory;
+import org.gbean.service.ServiceContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.context.NoSuchMessageException;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.core.io.Resource;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class SpringServiceFactory implements ConfigurableServiceFactory {
+ private static final String ROOT_BEAN_DEFINITION = "RootBeanDefinition";
+ private final Map dependencies;
+ private final Map objectNameMap;
+ private final List beanFactoryPostProcessors;
+ private RootBeanDefinition beanDefinition;
+ private GenericApplicationContext applicationContext;
+ private boolean enabled = true;
+
+ public SpringServiceFactory(RootBeanDefinition beanDefinition, Map objectNameMap, List beanFactoryPostProcessors) throws Exception {
+ this.beanDefinition = beanDefinition;
+ this.objectNameMap = objectNameMap;
+ this.beanFactoryPostProcessors = beanFactoryPostProcessors;
+ dependencies = SpringUtil.extractDependencies(beanDefinition, objectNameMap);
+ }
+
+ public RootBeanDefinition getBeanDefinition() {
+ return beanDefinition;
+ }
+
+ public void setBeanDefinition(RootBeanDefinition beanDefinition) {
+ this.beanDefinition = beanDefinition;
+ }
+
+ public Map getDependencies() {
+ return dependencies;
+ }
+
+ public void addDependency(String name, Set patterns) {
+ dependencies.put(name, patterns);
+ }
+
+ public Object createService(final ServiceContext serviceContext) throws Exception {
+ Object service = null;
+ try {
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ ServiceContext oldServiceContext = ServiceContextThreadLocal.get();
+ try {
+ Thread.currentThread().setContextClassLoader(serviceContext.getClassLoader());
+ ServiceContextThreadLocal.set(serviceContext);
+
+ ApplicationContext parent = new ApplicationContext() {
+ public ApplicationContext getParent() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getDisplayName() {
+ throw new UnsupportedOperationException();
+ }
+
+ public long getStartupDate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void publishEvent(ApplicationEvent event) {
+// throw new UnsupportedOperationException();
+ }
+
+ public boolean containsBeanDefinition(String beanName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getBeanDefinitionCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getBeanDefinitionNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getBeanDefinitionNames(Class type) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getBeanNamesForType(Class type) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getBeanNamesForType(Class type, boolean includePrototypes, boolean includeFactoryBeans) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Map getBeansOfType(Class type) throws BeansException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Map getBeansOfType(Class type, boolean includePrototypes, boolean includeFactoryBeans) throws BeansException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getBean(String name) throws BeansException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getBean(String name, Class requiredType) throws BeansException {
+ ObjectName objectName = null;
+ try {
+ objectName = SpringUtil.getObjectName(objectNameMap, name);
+ } catch (MalformedObjectNameException e) {
+ throw (NoSuchBeanDefinitionException) new NoSuchBeanDefinitionException(name, "Could not create an objectname for the specified name").initCause(e);
+ }
+
+ try {
+ Object service = serviceContext.getKernel().getService(objectName);
+ return service;
+ } catch (Exception e) {
+ throw (NoSuchBeanDefinitionException) new NoSuchBeanDefinitionException(name, "Kernel threw an exception").initCause(e);
+ }
+ }
+
+ public boolean containsBean(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Class getType(String name) throws NoSuchBeanDefinitionException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getAliases(String name) throws NoSuchBeanDefinitionException {
+ throw new UnsupportedOperationException();
+ }
+
+ public BeanFactory getParentBeanFactory() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
+ throw new UnsupportedOperationException();
+ }
+
+ public Resource[] getResources(String locationPattern) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Resource getResource(String location) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
+ // initializae the application context
+ applicationContext = new GenericApplicationContext(parent);
+ for (Iterator iterator = beanFactoryPostProcessors.iterator(); iterator.hasNext();) {
+ BeanFactoryPostProcessor beanFactoryPostProcessor = (BeanFactoryPostProcessor) iterator.next();
+ applicationContext.addBeanFactoryPostProcessor(beanFactoryPostProcessor);
+ }
+
+ // copy the bean definition, so we don't modify the original value
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(this.beanDefinition);
+
+ applicationContext.registerBeanDefinition(serviceContext.getObjectName(), beanDefinition);
+ applicationContext.refresh();
+ service = applicationContext.getBean(serviceContext.getObjectName());
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ ServiceContextThreadLocal.set(oldServiceContext);
+ }
+
+ } catch (Throwable t) {
+ applicationContext = null;
+
+ if (t instanceof Exception) {
+ throw (Exception) t;
+ } else if (t instanceof Error) {
+ throw (Error) t;
+ } else {
+ throw new Error(t);
+ }
+ }
+
+ return service;
+ }
+
+ public void destroyService(ServiceContext serviceContext, Object service) {
+ if (applicationContext != null) {
+ applicationContext.close();
+ applicationContext = null;
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Set getPropertyNames() {
+ return Collections.singleton(ROOT_BEAN_DEFINITION);
+ }
+
+ public Object getProperty(String propertyName) {
+ if (ROOT_BEAN_DEFINITION.equals(propertyName)) {
+ return beanDefinition;
+ }
+
+ throw new IllegalArgumentException("Unknown property: " + propertyName);
+ }
+
+ public void setProperty(String propertyName, Object persistentValue) {
+ if (ROOT_BEAN_DEFINITION.equals(propertyName)) {
+ beanDefinition = (RootBeanDefinition) persistentValue;
+ }
+
+ throw new IllegalArgumentException("Unknown property: " + propertyName);
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringUtil.java b/kernel/src/java/org/gbean/spring/SpringUtil.java
new file mode 100644
index 0000000..a4c5339
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringUtil.java
@@ -0,0 +1,113 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.BeanDefinitionValidationException;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public final class SpringUtil {
+ private SpringUtil() {
+ }
+
+ public static Map extractDependencies(RootBeanDefinition beanDefinition, final Map objectNameMap) throws Exception {
+ final Map dependencies = new LinkedHashMap();
+ SpringVisitor springVisitor = new AbstractSpringVisitor() {
+ public void visitBeanDefinition(BeanDefinition beanDefinition, Object data) throws BeansException {
+ Map dependencies = (Map) data;
+ super.visitBeanDefinition(beanDefinition, data);
+ if (beanDefinition instanceof RootBeanDefinition) {
+ RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinition;
+ String[] dependsOn = rootBeanDefinition.getDependsOn();
+ if (dependsOn != null) {
+ for (int i = 0; i < dependsOn.length; i++) {
+ String dependency = dependsOn[i];
+ try {
+ dependencies.put(dependency, Collections.singleton(getObjectName(objectNameMap, dependency)));
+ } catch (MalformedObjectNameException e) {
+ throw new BeanDefinitionValidationException("Depends on name could not be converted to an objectName: dependency=" + dependency, e);
+ }
+ }
+ }
+
+ Class beanClass = rootBeanDefinition.getBeanClass();
+ Method method = null;
+ try {
+ method = beanClass.getDeclaredMethod("getDependencies", new Class[]{RootBeanDefinition.class});
+ } catch (NoSuchMethodException e) {
+ // ignored mehtod doesn't exist most of the time
+ }
+ if (method != null) {
+ try {
+ dependencies.putAll((Map) method.invoke(beanClass, new Object[]{rootBeanDefinition}));
+ } catch (Exception e) {
+ throw new BeanDefinitionValidationException("Unable to get dependencies from root bean definition: " + rootBeanDefinition, e);
+ }
+ }
+ }
+ }
+
+ public void visitRuntimeBeanReference(RuntimeBeanReference beanReference, Object data) throws BeansException {
+ super.visitRuntimeBeanReference(beanReference, data);
+ String dependency = beanReference.getBeanName();
+ try {
+ Map dependencies = (Map) data;
+ dependencies.put(dependency, Collections.singleton(getObjectName(objectNameMap, dependency)));
+ } catch (MalformedObjectNameException e) {
+ throw new BeanDefinitionValidationException("Bean ref name could not be converted to an objectName: refName=" + dependency, e);
+ }
+ }
+
+ public void visitObject(Object value, Object data) throws BeansException {
+ Map dependencies = (Map) data;
+ super.visitObject(value, data);
+ if (value instanceof DependencyProvider) {
+ DependencyProvider dependencyProvider = (DependencyProvider) value;
+ dependencies.putAll(dependencyProvider.getDependencies());
+ }
+ }
+ };
+ springVisitor.visitBeanDefinition(beanDefinition, dependencies);
+ return dependencies;
+ }
+
+ public static ObjectName getObjectName(Map objectNameMap, String name) throws MalformedObjectNameException {
+ if (name.indexOf(":") < 0) {
+ ObjectName objectName = (ObjectName) objectNameMap.get(name);
+ if (objectName == null) {
+ throw new NoSuchBeanDefinitionException(name, "No object name definded for service");
+ }
+
+ return objectName;
+ } else {
+ return new ObjectName(name);
+ }
+ }
+}
diff --git a/kernel/src/java/org/gbean/spring/SpringVisitor.java b/kernel/src/java/org/gbean/spring/SpringVisitor.java
new file mode 100644
index 0000000..5791e3f
--- /dev/null
+++ b/kernel/src/java/org/gbean/spring/SpringVisitor.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface SpringVisitor {
+ void visitBeanFactory(ConfigurableListableBeanFactory beanRegistry, Object data) throws BeansException;
+
+ void visitBeanDefinition(String beanName, BeanDefinition beanDefinition, Object data) throws BeansException;
+
+ void visitBeanDefinition(BeanDefinition beanDefinition, Object data) throws BeansException;
+
+ void visitMutablePropertyValues(MutablePropertyValues propertyValues, Object data) throws BeansException;
+
+ void visitConstructorArgumentValues(ConstructorArgumentValues constructorArgumentValues, Object data) throws BeansException;
+
+ void visitConstructorArgumentValue(ConstructorArgumentValues.ValueHolder valueHolder, Object data) throws BeansException;
+
+ void visitPropertyValue(PropertyValue propertyValue, Object data) throws BeansException;
+
+ void visitRuntimeBeanReference(RuntimeBeanReference beanReference, Object data) throws BeansException;
+
+ void visitCollection(Collection collection, Object data) throws BeansException;
+
+ void visitMap(Map map, Object data) throws BeansException;
+
+ void visitObject(Object value, Object data) throws BeansException;
+
+ void visitBeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder, Object data) throws BeansException;
+}
diff --git a/kernel/src/resources/META-INF/gbean-bootstrap.xml b/kernel/src/resources/META-INF/gbean-bootstrap.xml
new file mode 100644
index 0000000..9894225
--- /dev/null
+++ b/kernel/src/resources/META-INF/gbean-bootstrap.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<beans>
+ <bean id="PropertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
+
+ <bean name="Main" class="org.gbean.kernel.KernelMain" >
+ <property name="kernel" ref="Kernel"/>
+ <property name="services">
+ <map>
+ <entry key=":j2eeType=MetadataManager" value-ref="MetadataManager"/>
+ <entry key=":j2eeType=ServiceInvokerManager,name=default" value-ref="ServiceInvokerManager"/>
+ <entry key=":j2eeType=ProxyManager,name=default" value-ref="ProxyManager"/>
+ <entry key=":j2eeType=Repository,name=FileSystemRepository" value-ref="FileSystemRepository"/>
+ <entry key=":j2eeType=Loader,name=spring" value-ref="SpringLoader"/>
+ </map>
+ </property>
+ <property name="next">
+ <bean class="org.gbean.loader.LoadAllMain">
+ <property name="kernel" ref="Kernel"/>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="KernelFactory" class="org.gbean.kernel.KernelFactory" factory-method="newInstance"/>
+ <bean name="Kernel" factory-bean="KernelFactory" factory-method="createKernel">
+ <constructor-arg index="0" value="gbean"/>
+ </bean>
+
+ <bean name="FileSystemRepository" class="org.gbean.repository.FileSystemRepository">
+ <property name="root" value="${gbean.base.dir}/repository"/>
+ </bean>
+
+ <bean name="MetadataManager" class="org.gbean.metadata.simple.SimpleMetadataManager">
+ <property name="metadataProviders">
+ <list>
+ <bean class="org.gbean.metadata.simple.PropertiesMetadataProvider"/>
+ </list>
+ </property>
+ </bean>
+
+ <bean name="ServiceInvokerManager" class="org.gbean.reflect.ServiceInvokerManager" init-method="start" destroy-method="stop">
+ <constructor-arg index="0" ref="Kernel"/>
+ </bean>
+
+ <bean name="ProxyManager" class="org.gbean.proxy.ProxyManager">
+ <constructor-arg index="0" ref="ServiceInvokerManager"/>
+ </bean>
+
+ <bean name="SpringLoader" class="org.gbean.spring.SpringLoader">
+ <property name="kernel" ref="Kernel"/>
+ <property name="repositories"><set><ref bean="FileSystemRepository"/></set></property>
+ <property name="metadataManager" ref="MetadataManager"/>
+ <property name="baseDir" value="${gbean.base.dir}/conf"/>
+ <property name="beanFactoryPostProcessors">
+ <list>
+ <bean class="org.gbean.spring.NamedConstructorArgs">
+ <property name="metadataManager" ref="MetadataManager"/>
+ <property name="defaultValues">
+ <list>
+ <bean class="org.gbean.spring.DefaultProperty">
+ <property name="name" value="objectName"/>
+ <property name="type" value="java.lang.String"/>
+ <property name="value">
+ <bean class="org.gbean.spring.ObjectNameStringReference" factory-method="createBeanDefinition"/>
+ </property>
+ </bean>
+ <bean class="org.gbean.spring.DefaultProperty">
+ <property name="name" value="objectName"/>
+ <property name="type" value="javax.management.ObjectName"/>
+ <property name="value">
+ <bean class="org.gbean.spring.ObjectNameReference" factory-method="createBeanDefinition"/>
+ </property>
+ </bean>
+ <bean class="org.gbean.spring.DefaultProperty">
+ <property name="name" value="classLoader"/>
+ <property name="type" value="java.lang.ClassLoader"/>
+ <property name="value">
+ <bean class="org.gbean.spring.ClassLoaderReference" factory-method="createBeanDefinition"/>
+ </property>
+ </bean>
+ <bean class="org.gbean.spring.DefaultProperty">
+ <property name="name" value="kernel"/>
+ <property name="type" value="org.gbean.kernel.Kernel"/>
+ <property name="value">
+ <bean class="org.gbean.spring.KernelReference" factory-method="createBeanDefinition"/>
+ </property>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ <bean class="org.gbean.spring.LifecycleDetector">
+ <property name="lifecycleInterfaces">
+ <list>
+ <bean class="org.gbean.spring.LifecycleInfo">
+ <property name="type" value="org.gbean.kernel.simple.SimpleLifecycle"/>
+ <property name="initMethodName" value="start"/>
+ <property name="destroyMethodName" value="stop"/>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ </list>
+ </property>
+ </bean>
+</beans>
diff --git a/kernel/src/resources/META-INF/services/org.apache.geronimo.kernel.KernelFactory b/kernel/src/resources/META-INF/services/org.apache.geronimo.kernel.KernelFactory
new file mode 100644
index 0000000..b713bd2
--- /dev/null
+++ b/kernel/src/resources/META-INF/services/org.apache.geronimo.kernel.KernelFactory
@@ -0,0 +1 @@
+org.gbean.geronimo.KernelBridgeFactory
\ No newline at end of file
diff --git a/kernel/src/test-data/NamedConstructorArgsTest.xml b/kernel/src/test-data/NamedConstructorArgsTest.xml
new file mode 100644
index 0000000..7a2ef2e
--- /dev/null
+++ b/kernel/src/test-data/NamedConstructorArgsTest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<beans>
+ <bean name="hal" class="org.gbean.spring.HelloMessage">
+ <property name="gbean-object-name"><value>foo:name=hello,j2eeType=HelloMessage</value></property>
+ <property name="prefix"><value>I'm sorry </value></property>
+ <property name="suffix"><value>; I'm afraid I can't do that.</value></property>
+ </bean>
+
+ <bean name="foobar" class="org.gbean.spring.HelloMessage" init-method="foo" destroy-method="bar">
+ <property name="prefix"><value>foo </value></property>
+ <property name="suffix"><value> bar</value></property>
+ <property name="properties">
+ <props>
+ <prop key="cheese">yes</prop>
+ <prop key="bacon">yes</prop>
+ </props>
+ </property>
+ </bean>
+</beans>
+
diff --git a/kernel/src/test-data/PostProcessorTest.xml b/kernel/src/test-data/PostProcessorTest.xml
new file mode 100644
index 0000000..7a2ef2e
--- /dev/null
+++ b/kernel/src/test-data/PostProcessorTest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<beans>
+ <bean name="hal" class="org.gbean.spring.HelloMessage">
+ <property name="gbean-object-name"><value>foo:name=hello,j2eeType=HelloMessage</value></property>
+ <property name="prefix"><value>I'm sorry </value></property>
+ <property name="suffix"><value>; I'm afraid I can't do that.</value></property>
+ </bean>
+
+ <bean name="foobar" class="org.gbean.spring.HelloMessage" init-method="foo" destroy-method="bar">
+ <property name="prefix"><value>foo </value></property>
+ <property name="suffix"><value> bar</value></property>
+ <property name="properties">
+ <props>
+ <prop key="cheese">yes</prop>
+ <prop key="bacon">yes</prop>
+ </props>
+ </property>
+ </bean>
+</beans>
+
diff --git a/kernel/src/test-data/server-gbean.xml b/kernel/src/test-data/server-gbean.xml
new file mode 100644
index 0000000..9c8ae1d
--- /dev/null
+++ b/kernel/src/test-data/server-gbean.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<configuration
+ configId="org/apache/geronimo/Server"
+ domain="geronimo.server"
+ server="geronimo"
+ >
+
+ <dependency>
+ <uri>mx4j/jars/mx4j-remote-3.0.1.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo-spec/jars/geronimo-spec-j2ee-1.4-rc4.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo-spec/jars/geronimo-spec-j2ee-jacc-1.0-rc4.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-activation-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-j2ee-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-core-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-connector-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>concurrent/jars/concurrent-1.3.4.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-timer-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-transaction-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-naming-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-security-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-system-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-webservices-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tranql/jars/tranql-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>openejb/jars/openejb-core-2.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-orb-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-orb-omg-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-orb-tools-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-tools-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-ins-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tmporb/jars/tmporb-pss-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo-spec/jars/geronimo-spec-corba-2.3-rc4.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>bouncycastle/jars/bcprov-jdk14-124.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>avalon/jars/avalon-framework-4.1.4.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>avalon/jars/avalon-logkit-1.2.2.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>ant/jars/ant-1.5.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>xfire/jars/xfire-20050202.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>xfire/jars/xfire-java-20050202.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>stax/jars/stax-1.1.1-dev.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>stax/jars/stax-api-1.0.jar</uri>
+ </dependency>
+
+
+ <dependency>
+ <uri>geronimo/jars/geronimo-jetty-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-jmxremoting-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>howl/jars/howl-logger-0.1.8.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>antlr/jars/antlr-2.7.2.jar</uri>
+ </dependency>
+
+ <!-- required for rar 1.5 to load realms -->
+ <dependency>
+ <uri>regexp/jars/regexp-1.3.jar</uri>
+ </dependency>
+
+ <!-- for timer serialization implementation -->
+ <dependency>
+ <uri>xstream/jars/xstream-1.0.2.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>xpp3/jars/xpp3-1.1.3.3.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>geronimo/jars/geronimo-common-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>geronimo/jars/geronimo-client-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>asm/jars/asm-1.4.3.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>geronimo/jars/geronimo-axis-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>axis/jars/axis-1.3-SNAPSHOT.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>wsdl4j/jars/wsdl4j-PATCH-1193602.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>commons-discovery/jars/commons-discovery-SNAPSHOT.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>geronimo/jars/geronimo-webservices-1.0-SNAPSHOT.jar</uri>
+ </dependency>
+
+ <dependency>
+ <uri>jetty/jars/org.mortbay.jetty-5.1.4rc0.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tomcat/jars/jasper-compiler-5.5.9.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tomcat/jars/jasper-compiler-jdt-5.5.9.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>tomcat/jars/jasper-runtime-5.5.9.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>commons-el/jars/commons-el-1.0.jar</uri>
+ </dependency>
+ <dependency>
+ <uri>commons-collections/jars/commons-collections-3.1.jar</uri>
+ </dependency>
+</configuration>
\ No newline at end of file
diff --git a/kernel/src/test-data/server.xml b/kernel/src/test-data/server.xml
new file mode 100644
index 0000000..2be03a8
--- /dev/null
+++ b/kernel/src/test-data/server.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+* Copyright 2005 the original author or authors.
+*
+* 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.
+-->
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<beans>
+ <bean name="JMXBridge" class="org.gbean.jmx.JMXBridge">
+ <constructor-arg index="0"><bean class="org.gbean.spring.KernelReference"/></constructor-arg>
+ <constructor-arg index="1"><ref bean=":j2eeType=ServiceInvokerManager,name=default"/></constructor-arg>
+ </bean>
+
+ <bean name="ServerInfo" class="org.apache.geronimo.system.serverinfo.ServerInfo">
+ <property name="gbean-object-name"><value>geronimo.server:J2EEServer=geronimo,J2EEApplication=null,J2EEModule=org/apache/geronimo/System,j2eeType=GBean,name=ServerInfo</value></property>
+ </bean>
+
+ <bean name="URLFactory" class="org.apache.geronimo.system.url.GeronimoURLFactory"/>
+
+ <bean name="LocalConfigurationStore" class="org.apache.geronimo.system.configuration.LocalConfigStore">
+ <property name="gbean-object-name"><value>geronimo.server:J2EEApplication=null,J2EEModule=org/apache/geronimo/System,J2EEServer=geronimo,j2eeType=ConfigurationStore,name=Local</value></property>
+ <property name="root"><value>config-store</value></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ </bean>
+
+ <bean name="GeronimoLoaderBridge" class="org.gbean.geronimo.LoaderBridge">
+ <property name="gbean-object-name"><value>geronimo.server:j2eeType=Loader,name=GeronimoLoaderBridge</value></property>
+ <constructor-arg index="0"><ref bean="LocalConfigurationStore"/></constructor-arg>
+ </bean>
+
+ <bean name="ConfigurationManager" class="org.apache.geronimo.kernel.config.ConfigurationManagerImpl">
+ <property name="stores">
+ <bean class="org.gbean.spring.LiveProxyHashSetReference">
+ <property name="name"><value>Stores</value></property>
+ <property name="pattern"><value>*:j2eeType=ConfigurationStore,*</value></property>
+ <property name="type"><value>org.apache.geronimo.kernel.config.ConfigurationStore</value></property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="FileConfigurationList" class="org.apache.geronimo.system.configuration.FileConfigurationList">
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ <property name="configurationManager"><ref bean="ConfigurationManager"/></property>
+ <property name="configFile"><value>var/config/config.list</value></property>
+ </bean>
+
+ <bean name="Repository" class="org.apache.geronimo.system.repository.ReadOnlyRepository">
+ <property name="root"><value>repository/</value></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ </bean>
+
+ <bean name="RMIRegistry" class="org.apache.geronimo.system.rmi.RMIRegistryService">
+ <property name="port"><value>1099</value></property>
+ </bean>
+
+ <bean name="NamingProperties" class="org.apache.geronimo.system.properties.NamingProperties">
+ <property name="namingFactoryInitial"><value>com.sun.jndi.rmi.registry.RegistryContextFactory</value></property>
+ <property name="namingFactoryUrlPkgs"><value>org.apache.geronimo.naming</value></property>
+ <property name="namingProviderUrl"><value>rmi://localhost:1099</value></property>
+ </bean>
+
+ <bean name="properties-login" class="org.apache.geronimo.security.jaas.LoginModuleGBean">
+ <property name="loginModuleClass"><value>org.apache.geronimo.security.realm.providers.PropertiesFileLoginModule</value></property>
+ <property name="serverSide"><value>true</value></property>
+ <property name="options">
+ <props>
+ <prop key="usersURI">var/security/users.properties</prop>
+ <prop key="groupsURI">var/security/groups.properties</prop>
+ </props>
+ </property>
+ <property name="loginDomainName"><value>geronimo-properties-realm</value></property>
+ </bean>
+
+ <bean name="geronimo-properties-realm" class="org.apache.geronimo.security.realm.GenericSecurityRealm">
+ <property name="realmName"><value>geronimo-properties-realm</value></property>
+ <property name="loginModuleConfiguration"><ref bean="properties-login-options"/></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ </bean>
+
+ <bean name="properties-login-options" class="org.apache.geronimo.security.jaas.JaasLoginModuleUse">
+ <property name="loginModule"><ref bean="properties-login"/></property>
+ <property name="controlFlag"><value>REQUIRED</value></property>
+ </bean>
+
+ <bean name="JMX" class="org.apache.geronimo.security.jaas.ServerRealmConfigurationEntry">
+ <property name="applicationConfigName"><value>JMX</value></property>
+ <property name="realmName"><value>geronimo-properties-realm</value></property>
+ </bean>
+
+ <bean name="LoginConfiguration" class="org.apache.geronimo.security.jaas.GeronimoLoginConfiguration">
+ <property name="configurations">
+ <bean class="org.gbean.geronimo.CollectionReference">
+ <property name="name"><value>Configurations</value></property>
+ <property name="patterns">
+ <set>
+ <value type="javax.management.ObjectName">*:j2eeType=SecurityRealm,*</value>
+ <value type="javax.management.ObjectName">*:j2eeType=ConfigurationEntry,*</value>
+ </set>
+ </property>
+ <property name="type"><value>org.apache.geronimo.security.jaas.ConfigurationEntryFactory</value></property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="SecurityService" class="org.apache.geronimo.security.SecurityServiceImpl">
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ <property name="policyConfigurationFactory"><value>org.apache.geronimo.security.jacc.GeronimoPolicyConfigurationFactory</value></property>
+ <property name="policyProvider"><value>org.apache.geronimo.security.jacc.GeronimoPolicy</value></property>
+ </bean>
+
+ <bean name="JaasLoginService" class="org.apache.geronimo.security.jaas.JaasLoginService">
+ <property name="gbean-object-name"><value>geronimo.server:J2EEApplication=null,J2EEModule=org/apache/geronimo/Server,J2EEServer=geronimo,j2eeType=GBean,name=JaasLoginService</value></property>
+ <property name="algorithm"><value>HmacSHA1</value></property>
+ <property name="password"><value>secret</value></property>
+ <property name="realms">
+ <bean class="org.gbean.geronimo.CollectionReference">
+ <property name="name"><value>realms</value></property>
+ <property name="pattern"><value>*:j2eeType=SecurityRealm,*</value></property>
+ <property name="type"><value>org.apache.geronimo.security.realm.SecurityRealm</value></property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="DefaultThreadPool" class="org.apache.geronimo.pool.ThreadPool">
+ <property name="poolSize"><value>10</value></property>
+ <property name="poolName"><value>DefaultThreadPool</value></property>
+ <property name="keepAliveTime"><value>5000</value></property>
+ </bean>
+
+ <bean name="ConnectionTracker" class="org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator"/>
+
+ <bean name="DefaultWorkManager" class="org.apache.geronimo.connector.work.GeronimoWorkManager">
+ <property name="syncMaximumPoolSize"><value>10</value></property>
+ <property name="startMaximumPoolSize"><value>10</value></property>
+ <property name="scheduledMaximumPoolSize"><value>10</value></property>
+ <property name="transactionContextManager"><ref bean="TransactionContextManager"/></property>
+ </bean>
+
+ <bean name="HOWLTransactionLog" class="org.apache.geronimo.transaction.log.HOWLLog">
+ <property name="bufferClassName"><value>org.objectweb.howl.log.BlockLogBuffer</value></property>
+ <property name="bufferSizeKBytes"><value>32</value></property>
+ <property name="checksumEnabled"><value>true</value></property>
+ <property name="flushSleepTimeMilliseconds"><value>50</value></property>
+ <property name="logFileDir"><value>var/txlog</value></property>
+ <property name="logFileExt"><value>log</value></property>
+ <property name="logFileName"><value>howl</value></property>
+ <property name="maxBlocksPerFile"><value>-1</value></property>
+ <property name="maxBuffers"><value>0</value></property>
+ <property name="maxLogFiles"><value>2</value></property>
+ <property name="minBuffers"><value>4</value></property>
+ <property name="threadsWaitingForceThreshold"><value>-1</value></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ </bean>
+
+ <bean name="TransactionManager" class="org.apache.geronimo.transaction.manager.TransactionManagerImpl">
+ <property name="defaultTransactionTimeoutSeconds"><value>600</value></property>
+ <property name="transactionLog"><ref bean="HOWLTransactionLog"/></property>
+ <property name="resourceManagers">
+ <bean class="org.gbean.geronimo.CollectionReference">
+ <property name="name"><value>ResourceManagers</value></property>
+ <property name="patterns">
+ <set>
+ <value type="javax.management.ObjectName">*:j2eeType=JCAManagedConnectionFactory,*</value>
+ <value type="javax.management.ObjectName">*:j2eeType=ActivationSpec,*</value>
+ </set>
+ </property>
+ <property name="type"><value>org.apache.geronimo.transaction.manager.ResourceManager</value></property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="TransactionContextManager" class="org.apache.geronimo.transaction.context.TransactionContextManager">
+ <property name="transactionManager"><ref bean="TransactionManager"/></property>
+ <property name="xidImporter"><ref bean="TransactionManager"/></property>
+ </bean>
+
+ <bean name="JettyWebContainer" class="org.apache.geronimo.jetty.JettyContainerImpl"/>
+
+ <bean name="JettyRequestLog" class="org.apache.geronimo.jetty.requestlog.NCSARequestLog">
+ <property name="jettyContainer"><ref bean="JettyWebContainer"/></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ <property name="filename"><value>var/log/jetty_yyyy_mm_dd.log</value></property>
+ <property name="logDateFormat"><value>dd/MMM/yyyy:HH:mm:ss ZZZ</value></property>
+ <property name="logTimeZone"><value>GMT</value></property>
+ </bean>
+
+ <bean name="JettyWebConnector" class="org.apache.geronimo.jetty.connector.HTTPConnector">
+ <property name="jettyContainer"><ref bean="JettyWebContainer"/></property>
+ <property name="port"><value>8080</value></property>
+ </bean>
+
+ <bean name="JettySSLConnector" class="org.apache.geronimo.jetty.connector.HTTPSConnector">
+ <property name="jettyContainer"><ref bean="JettyWebContainer"/></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ <property name="port"><value>8443</value></property>
+ <property name="keystore"><value>var/security/keystore</value></property>
+ <property name="keystoreType"><value>JKS</value></property>
+ <property name="password"><value>secret</value></property>
+ <property name="keyPassword"><value>secret</value></property>
+ <property name="needClientAuth"><value>false</value></property>
+ <property name="protocol"><value>TLS</value></property>
+ </bean>
+
+ <bean name="EjbNetworkService" class="org.openejb.server.StandardServiceStack">
+ <property name="name"><value>EJB</value></property>
+ <property name="port"><value>4201</value></property>
+ <property name="address"><value>127.0.0.1</value></property>
+ <property name="allowHosts"><value>127.0.0.1</value></property>
+ <property name="logOnSuccess"><value>HOST,NAME,THREADID,USERID</value></property>
+ <property name="logOnFailure"><value>HOST,NAME</value></property>
+ <property name="executor"><ref bean="DefaultThreadPool"/></property>
+ <property name="server"><ref bean="EjbServer"/></property>
+ </bean>
+
+ <bean name="EjbServer" class="org.openejb.server.ejbd.EjbServer">
+ <property name="containerIndex"><ref bean="ContainerIndex"/></property>
+ </bean>
+
+ <bean name="ContainerIndex" class="org.openejb.ContainerIndex">
+ <property name="eJBContainers">
+ <bean class="org.gbean.geronimo.CollectionReference">
+ <property name="name"><value>ResourceManagers</value></property>
+ <property name="patterns">
+ <set>
+ <value type="javax.management.ObjectName">*:j2eeType=StatelessSessionBean,*</value>
+ <value type="javax.management.ObjectName">*:j2eeType=StatefulSessionBean,*</value>
+ <value type="javax.management.ObjectName">*:j2eeType=EntityBean,*</value>
+ </set>
+ </property>
+ <property name="type"><value>org.openejb.EJBContainer</value></property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean name="JMXService" class="org.apache.geronimo.jmxremoting.JMXConnector" depends-on="NamingProperties, RMIRegistry">
+ <property name="url"><value>service:jmx:rmi://localhost/jndi/rmi:/JMXConnector</value></property>
+ <property name="applicationConfigName"><value>JMX</value></property>
+ </bean>
+
+ <bean name="eis/JAXR" class="org.apache.geronimo.webservices.jaxr.JAXRGBean"/>
+
+ <bean name="J2EEDomain" class="org.apache.geronimo.j2ee.management.impl.J2EEDomainImpl">
+ <property name="gbean-object-name"><value>geronimo.server:j2eeType=J2EEDomain,name=geronimo.server</value></property>
+ </bean>
+
+ <bean name="J2EEServer" class="org.apache.geronimo.j2ee.management.impl.J2EEServerImpl">
+ <property name="gbean-object-name"><value>geronimo.server:j2eeType=J2EEServer,name=geronimo</value></property>
+ <property name="serverInfo"><ref bean="ServerInfo"/></property>
+ </bean>
+
+ <bean name="JVM" class="org.apache.geronimo.j2ee.management.impl.JVMImpl">
+ <property name="gbean-object-name"><value>geronimo.server:j2eeType=JVM,J2EEServer=geronimo,name=JVM</value></property>
+ </bean>
+
+ <bean name="MEJB" class="org.openejb.mejb.MEJB">
+ <property name="gbean-object-name"><value>geronimo.server:J2EEApplication=null,EJBModule=org/apache/geronimo/Server,J2EEServer=geronimo,j2eeType=StatelessSessionBean,name=ejb/mgmt/MEJB</value></property>
+ </bean>
+
+</beans>
+
diff --git a/kernel/src/test/org/gbean/classloader/JarFileClassLoaderTest.java b/kernel/src/test/org/gbean/classloader/JarFileClassLoaderTest.java
new file mode 100644
index 0000000..fc127a0
--- /dev/null
+++ b/kernel/src/test/org/gbean/classloader/JarFileClassLoaderTest.java
@@ -0,0 +1,156 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.classloader;
+
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class JarFileClassLoaderTest extends TestCase {
+ private static final String ENTRY_NAME = "foo";
+ private static final String ENTRY_VALUE = "bar";
+ private File file;
+ private static final String NON_EXISTANT_RESOURCE = "non-existant-resource";
+
+ // this stuff doesn't work on windows
+ public void testNothing() {
+ }
+
+ public void XtestReadEntry() throws Exception {
+ JarFile jarFile = new JarFile(file);
+ JarEntry jarEntry = jarFile.getJarEntry(ENTRY_NAME);
+ String urlString = "jar:" + file.toURL() + "!/" + ENTRY_NAME;
+ URL url = new URL(file.toURL(), urlString);
+ assertStreamContains(ENTRY_VALUE, url.openStream());
+ jarFile.close();
+ }
+
+ public void XtestGetResourceAsStream() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ InputStream in = classLoader.getResourceAsStream(ENTRY_NAME);
+ assertStreamContains(ENTRY_VALUE, in);
+
+ classLoader.destroy();
+ }
+
+ public void XtestGetNonExistantResourceAsStream() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ InputStream in = classLoader.getResourceAsStream(NON_EXISTANT_RESOURCE);
+ assertNull(in);
+
+ classLoader.destroy();
+ }
+
+ public void XtestGetResource() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ URL resource = classLoader.getResource(ENTRY_NAME);
+ assertNotNull(resource);
+
+ InputStream in = resource.openStream();
+ assertStreamContains(ENTRY_VALUE, in);
+
+ classLoader.destroy();
+ }
+
+ public void XtestGetNonExistantResource() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ URL resource = classLoader.getResource(NON_EXISTANT_RESOURCE);
+ assertNull(resource);
+
+ classLoader.destroy();
+ }
+
+ public void XtestGetResources() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ Enumeration resources = classLoader.getResources(ENTRY_NAME);
+ assertNotNull(resources);
+ assertTrue(resources.hasMoreElements());
+
+ URL resource = (URL) resources.nextElement();
+ assertNotNull(resource);
+
+ InputStream in = resource.openStream();
+ assertStreamContains(ENTRY_VALUE, in);
+
+ classLoader.destroy();
+ }
+
+ public void XtestGetNonExistantResources() throws Exception {
+ JarFileClassLoader classLoader = new JarFileClassLoader("test", Collections.singletonList(file.toURL()));
+ Enumeration resources = classLoader.getResources(NON_EXISTANT_RESOURCE);
+ assertNotNull(resources);
+ assertFalse(resources.hasMoreElements());
+
+ classLoader.destroy();
+ }
+
+ private void assertStreamContains(String expectedValue, InputStream in) throws IOException {
+ String entryValue;
+ try {
+ StringBuffer stringBuffer = new StringBuffer();
+ byte[] bytes = new byte[4000];
+ for (int count = in.read(bytes); count != -1; count = in.read(bytes)) {
+ stringBuffer.append(new String(bytes, 0, count));
+ }
+ entryValue = stringBuffer.toString();
+ } finally {
+ in.close();
+ }
+ assertEquals(expectedValue, entryValue);
+ }
+
+ private static void assertFileExists(File file) {
+ assertTrue("File should exist: " + file, file.canRead());
+ }
+
+ private static void assertFileNotExists(File file) {
+ assertTrue("File should not exist: " + file, !file.canRead());
+ }
+
+ protected void setUp() throws Exception {
+ file = new File("test.jar");
+ file.delete();
+
+ assertFileNotExists(file);
+
+ FileOutputStream out = new FileOutputStream(file);
+ JarOutputStream jarOut = new JarOutputStream(out);
+ jarOut.putNextEntry(new JarEntry(ENTRY_NAME));
+ jarOut.write(ENTRY_VALUE.getBytes());
+ jarOut.close();
+ out.close();
+
+ assertFileExists(file);
+ }
+
+ protected void tearDown() throws Exception {
+ file.delete();
+ assertFileNotExists(file);
+ }
+}
diff --git a/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.java b/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.java
new file mode 100644
index 0000000..89d06db
--- /dev/null
+++ b/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.java
@@ -0,0 +1,244 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LotsOfTypes {
+ private byte b;
+ private short s;
+ private int i;
+ private long l;
+ private float f;
+ private double d;
+ private char c;
+ private boolean bool;
+ private String string;
+
+ private byte[] bArray;
+ private short[] sArray;
+ private int[] iArray;
+ private long[] lArray;
+ private float[] fArray;
+ private double[] dArray;
+ private char[] cArray;
+ private boolean[] boolArray;
+ private String[] stringArray;
+
+ public LotsOfTypes() {
+ }
+
+ public LotsOfTypes(byte b, short s, int i, long l, float f, double d, char c, boolean bool, String string) {
+ this.b = b;
+ this.s = s;
+ this.i = i;
+ this.l = l;
+ this.f = f;
+ this.d = d;
+ this.c = c;
+ this.bool = bool;
+ this.string = string;
+ }
+
+ public LotsOfTypes(byte[] bArray, short[] sArray, int[] iArray, long[] lArray, float[] fArray, double[] dArray, char[] cArray, boolean[] boolArray, String[] stringArray) {
+ this.bArray = bArray;
+ this.sArray = sArray;
+ this.iArray = iArray;
+ this.lArray = lArray;
+ this.fArray = fArray;
+ this.dArray = dArray;
+ this.cArray = cArray;
+ this.boolArray = boolArray;
+ this.stringArray = stringArray;
+ }
+
+ public LotsOfTypes(byte b, short s, int i, long l, float f, double d, char c, boolean bool, String string, byte[] bArray, short[] sArray, int[] iArray, long[] lArray, float[] fArray, double[] dArray, char[] cArray, boolean[] boolArray, String[] stringArray) {
+ this.b = b;
+ this.s = s;
+ this.i = i;
+ this.l = l;
+ this.f = f;
+ this.d = d;
+ this.c = c;
+ this.bool = bool;
+ this.string = string;
+ this.bArray = bArray;
+ this.sArray = sArray;
+ this.iArray = iArray;
+ this.lArray = lArray;
+ this.fArray = fArray;
+ this.dArray = dArray;
+ this.cArray = cArray;
+ this.boolArray = boolArray;
+ this.stringArray = stringArray;
+ }
+
+ public void allBasic(byte b, short s, int i, long l, float f, double d, char c, boolean bool, String string) {
+ }
+
+ public void allArray(byte[] bArray, short[] sArray, int[] iArray, long[] lArray, float[] fArray, double[] dArray, char[] cArray, boolean[] boolArray, String[] stringArray) {
+ }
+
+ public void all(byte b, short s, int i, long l, float f, double d, char c, boolean bool, String string, byte[] bArray, short[] sArray, int[] iArray, long[] lArray, float[] fArray, double[] dArray, char[] cArray, boolean[] boolArray, String[] stringArray) {
+ }
+
+
+ public byte getB() {
+ return b;
+ }
+
+ public void setB(byte b) {
+ this.b = b;
+ }
+
+ public short getS() {
+ return s;
+ }
+
+ public void setS(short s) {
+ this.s = s;
+ }
+
+ public int getI() {
+ return i;
+ }
+
+ public void setI(int i) {
+ this.i = i;
+ }
+
+ public long getL() {
+ return l;
+ }
+
+ public void setL(long l) {
+ this.l = l;
+ }
+
+ public float getF() {
+ return f;
+ }
+
+ public void setF(float f) {
+ this.f = f;
+ }
+
+ public double getD() {
+ return d;
+ }
+
+ public void setD(double d) {
+ this.d = d;
+ }
+
+ public char getC() {
+ return c;
+ }
+
+ public void setC(char c) {
+ this.c = c;
+ }
+
+ public boolean isBool() {
+ return bool;
+ }
+
+ public void setBool(boolean bool) {
+ this.bool = bool;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public void setString(String string) {
+ this.string = string;
+ }
+
+ public byte[] getbArray() {
+ return bArray;
+ }
+
+ public void setbArray(byte[] bArray) {
+ this.bArray = bArray;
+ }
+
+ public short[] getsArray() {
+ return sArray;
+ }
+
+ public void setsArray(short[] sArray) {
+ this.sArray = sArray;
+ }
+
+ public int[] getiArray() {
+ return iArray;
+ }
+
+ public void setiArray(int[] iArray) {
+ this.iArray = iArray;
+ }
+
+ public long[] getlArray() {
+ return lArray;
+ }
+
+ public void setlArray(long[] lArray) {
+ this.lArray = lArray;
+ }
+
+ public float[] getfArray() {
+ return fArray;
+ }
+
+ public void setfArray(float[] fArray) {
+ this.fArray = fArray;
+ }
+
+ public double[] getdArray() {
+ return dArray;
+ }
+
+ public void setdArray(double[] dArray) {
+ this.dArray = dArray;
+ }
+
+ public char[] getcArray() {
+ return cArray;
+ }
+
+ public void setcArray(char[] cArray) {
+ this.cArray = cArray;
+ }
+
+ public boolean[] getBoolArray() {
+ return boolArray;
+ }
+
+ public void setBoolArray(boolean[] boolArray) {
+ this.boolArray = boolArray;
+ }
+
+ public String[] getStringArray() {
+ return stringArray;
+ }
+
+ public void setStringArray(String[] stringArray) {
+ this.stringArray = stringArray;
+ }
+}
diff --git a/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.properties b/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.properties
new file mode 100644
index 0000000..2e9e2da
--- /dev/null
+++ b/kernel/src/test/org/gbean/metadata/simple/LotsOfTypes.properties
@@ -0,0 +1,155 @@
+# LotsOfTypes()
+
+description=class description
+LotsOfTypes().description = constructor description
+getB().description = method description
+
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).0.name = b
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).1.name = s
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).2.name = i
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).3.name = l
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).4.name = f
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).5.name = d
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).6.name = c
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).7.name = bool
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String).8.name = string
+
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).0.name = bArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).1.name = sArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).2.name = iArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).3.name = lArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).4.name = fArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).5.name = dArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).6.name = cArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).7.name = boolArray
+LotsOfTypes(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).8.name = stringArray
+
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).0.name = b
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).1.name = s
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).2.name = i
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).3.name = l
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).4.name = f
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).5.name = d
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).6.name = c
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).7.name = bool
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).8.name = string
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).9.name = bArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).10.name = sArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).11.name = iArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).12.name = lArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).13.name = fArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).14.name = dArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).15.name = cArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).16.name = boolArray
+LotsOfTypes(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).17.name = stringArray
+
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).0.name = b
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).1.name = s
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).2.name = i
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).3.name = l
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).4.name = f
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).5.name = d
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).6.name = c
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).7.name = bool
+allBasic(byte, short, int, long, float, double, char, boolean, java.lang.String).8.name = string
+
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).0.name = bArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).1.name = sArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).2.name = iArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).3.name = lArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).4.name = fArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).5.name = dArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).6.name = cArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).7.name = boolArray
+allArray(byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).8.name = stringArray
+
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).0.name = b
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).1.name = s
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).2.name = i
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).3.name = l
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).4.name = f
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).5.name = d
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).6.name = c
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).7.name = bool
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).8.name = string
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).9.name = bArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).10.name = sArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).11.name = iArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).12.name = lArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).13.name = fArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).14.name = dArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).15.name = cArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).16.name = boolArray
+all(byte, short, int, long, float, double, char, boolean, java.lang.String, byte[], short[], int[], long[], float[], double[], char[], boolean[], java.lang.String[]).17.name = stringArray
+
+# getB()
+
+setB(byte).0.name = b
+
+# getS()
+
+setS(short).0.name = s
+
+# getI()
+
+setI(int).0.name = i
+
+# getL()
+
+setL(long).0.name = l
+
+# getF()
+
+setF(float).0.name = f
+
+# getD()
+
+setD(double).0.name = d
+
+# getC()
+
+setC(char).0.name = c
+
+# boolean isBool()
+
+setBool(boolean).0.name = bool
+
+# getString()
+
+setString(java.lang.String).0.name = string
+
+# getbArray()
+
+setbArray(byte[]).0.name = bArray
+
+# getsArray()
+
+setsArray(short[]).0.name = sArray
+
+# getiArray()
+
+setiArray(int[]).0.name = iArray
+
+# getlArray()
+
+setlArray(long[]).0.name = lArray
+
+# getfArray()
+
+setfArray(float[]).0.name = fArray
+
+# getdArray()
+
+setdArray(double[]).0.name = dArray
+
+# getcArray()
+
+setcArray(char[]).0.name = cArray
+
+# getBoolArray()
+
+setBoolArray(boolean[]).0.name = boolArray
+
+# getStringArray()
+
+setStringArray(java.lang.String[]).0.name = stringArray
diff --git a/kernel/src/test/org/gbean/metadata/simple/PropertiesMetadataProviderTest.java b/kernel/src/test/org/gbean/metadata/simple/PropertiesMetadataProviderTest.java
new file mode 100644
index 0000000..1e0176f
--- /dev/null
+++ b/kernel/src/test/org/gbean/metadata/simple/PropertiesMetadataProviderTest.java
@@ -0,0 +1,105 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.metadata.simple;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.TestCase;
+import org.gbean.kernel.ConstructorSignature;
+import org.gbean.kernel.OperationSignature;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MethodMetadata;
+import org.gbean.metadata.ParameterMetadata;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class PropertiesMetadataProviderTest extends TestCase {
+ private static final Map NAMES = new HashMap();
+ static {
+ NAMES.put(int.class, "i");
+ NAMES.put(byte.class, "b");
+ NAMES.put(short.class, "s");
+ NAMES.put(int.class, "i");
+ NAMES.put(long.class, "l");
+ NAMES.put(float.class, "f");
+ NAMES.put(double.class, "d");
+ NAMES.put(char.class, "c");
+ NAMES.put(boolean.class, "bool");
+ NAMES.put(String.class, "string");
+ NAMES.put(byte[].class, "bArray");
+ NAMES.put(short[].class, "sArray");
+ NAMES.put(int[].class, "iArray");
+ NAMES.put(long[].class, "lArray");
+ NAMES.put(float[].class, "fArray");
+ NAMES.put(double[].class, "dArray");
+ NAMES.put(char[].class, "cArray");
+ NAMES.put(boolean[].class, "boolArray");
+ NAMES.put(String[].class, "stringArray");
+ }
+
+ public void testLoad() {
+ PropertiesMetadataProvider propertiesMetadataProvider = new PropertiesMetadataProvider();
+ Class type = LotsOfTypes.class;
+ SimpleClassMetadata classMetadata = new SimpleClassMetadata(type);
+ propertiesMetadataProvider.addClassMetadata(classMetadata);
+ assertNotNull(classMetadata);
+
+ Constructor[] constructors = type.getDeclaredConstructors();
+ for (int i = 0; i < constructors.length; i++) {
+ Constructor constructor = constructors[i];
+ ConstructorMetadata constructorMetadata = classMetadata.getConstructor(constructor);
+ assertNotNull(constructorMetadata);
+ assertEquals(new ConstructorSignature(constructor), constructorMetadata.getSignature());
+ assertEquals(constructor.getParameterTypes().length, constructorMetadata.getParameters().size());
+ verifyParameterNames(constructor.getParameterTypes(), constructorMetadata.getParameters());
+ }
+
+ Method[] methods = type.getDeclaredMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ MethodMetadata methodMetadata = classMetadata.getMethod(method);
+ assertNotNull(methodMetadata);
+ assertEquals(new OperationSignature(method), methodMetadata.getSignature());
+ assertEquals(method.getParameterTypes().length, methodMetadata.getParameters().size());
+ verifyParameterNames(method.getParameterTypes(), methodMetadata.getParameters());
+ }
+
+ assertEquals(classMetadata.get("description"), "class description");
+ assertEquals(classMetadata.getConstructor(new ConstructorSignature(new String[]{})).get("description"), "constructor description");
+ assertEquals(classMetadata.getMethod(new OperationSignature("getB", new String[]{})).get("description"), "method description");
+
+ }
+
+ private void verifyParameterNames(Class[] parameterTypes, List parameterMetadata) {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class parameterType = parameterTypes[i];
+ ParameterMetadata metadata = (ParameterMetadata) parameterMetadata.get(i);
+ assertEquals(i, metadata.getIndex());
+ assertEquals(parameterType, metadata.getType());
+ String name = (String) metadata.get("name");
+ assertNotNull(name);
+ String typeName = (String) NAMES.get(parameterType);
+ assertNotNull(typeName);
+ assertEquals(typeName, name);
+ }
+ }
+}
diff --git a/kernel/src/test/org/gbean/spring/HelloMessage.java b/kernel/src/test/org/gbean/spring/HelloMessage.java
new file mode 100644
index 0000000..77a854d
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/HelloMessage.java
@@ -0,0 +1,76 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.util.Properties;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class HelloMessage implements MyLifecycle {
+ private String prefix;
+ private String suffix;
+ private Properties properties;
+
+ public HelloMessage() {
+ }
+
+ public HelloMessage(String prefix, String suffix) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ }
+
+ public HelloMessage(String prefix, String suffix, Properties properties) {
+ this.prefix = prefix;
+ this.suffix = suffix;
+ this.properties = properties;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getSuffix() {
+ return suffix;
+ }
+
+ public void setSuffix(String suffix) {
+ this.suffix = suffix;
+ }
+
+ public String message(String message) {
+ return prefix + message + suffix;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ public void begin() {
+ }
+
+ public void end() {
+ }
+}
diff --git a/kernel/src/test/org/gbean/spring/HelloMessage.properties b/kernel/src/test/org/gbean/spring/HelloMessage.properties
new file mode 100644
index 0000000..15e088d
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/HelloMessage.properties
@@ -0,0 +1,9 @@
+HelloMessage(java.lang.String, java.lang.String).0.name = prefix
+HelloMessage(java.lang.String, java.lang.String).1.name = suffix
+HelloMessage(java.lang.String, java.lang.String, java.util.Properties).0.name = prefix
+HelloMessage(java.lang.String, java.lang.String, java.util.Properties).1.name = suffix
+HelloMessage(java.lang.String, java.lang.String, java.util.Properties).2.name = properties
+setPrefix(java.lang.String).0.name = prefix
+setSuffix(java.lang.String).0.name = suffix
+message(java.lang.String).0.name = message
+setProperties(java.util.Properties).0.name = properties
diff --git a/kernel/src/test/org/gbean/spring/LifecycleDetectorTest.java b/kernel/src/test/org/gbean/spring/LifecycleDetectorTest.java
new file mode 100644
index 0000000..d3c85ff
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/LifecycleDetectorTest.java
@@ -0,0 +1,68 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class LifecycleDetectorTest extends TestCase {
+ private DefaultListableBeanFactory factory;
+
+ public void testLifecycleDetection() {
+ String beanName = "hal";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ LifecycleDetector lifecycleDetector = new LifecycleDetector();
+ lifecycleDetector.addLifecycleInterface(MyLifecycle.class, "begin", "end");
+ lifecycleDetector.postProcessBeanFactory(factory);
+
+ assertEquals("begin", beanDefinition.getInitMethodName());
+ assertEquals("end", beanDefinition.getDestroyMethodName());
+ }
+
+ public void testObjectNameCreation() {
+ String beanName = "foobar";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ LifecycleDetector lifecycleDetector = new LifecycleDetector();
+ lifecycleDetector.addLifecycleInterface(MyLifecycle.class, "begin", "end");
+ lifecycleDetector.postProcessBeanFactory(factory);
+
+ assertEquals("foo", beanDefinition.getInitMethodName());
+ assertEquals("bar", beanDefinition.getDestroyMethodName());
+ }
+
+ protected void setUp() throws Exception {
+ factory = new DefaultListableBeanFactory();
+ Resource resource = new FileSystemResource(new File("src/test-data/PostProcessorTest.xml"));
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
+ reader.loadBeanDefinitions(resource);
+ }
+}
diff --git a/kernel/src/test/org/gbean/spring/MyLifecycle.java b/kernel/src/test/org/gbean/spring/MyLifecycle.java
new file mode 100644
index 0000000..395b1a7
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/MyLifecycle.java
@@ -0,0 +1,25 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public interface MyLifecycle {
+ void begin();
+ void end();
+}
diff --git a/kernel/src/test/org/gbean/spring/NamedConstructorArgsTest.java b/kernel/src/test/org/gbean/spring/NamedConstructorArgsTest.java
new file mode 100644
index 0000000..0e42756
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/NamedConstructorArgsTest.java
@@ -0,0 +1,141 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.File;
+import java.util.Properties;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.beans.factory.config.ConstructorArgumentValues;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.gbean.metadata.simple.PropertiesMetadataProvider;
+import org.gbean.metadata.simple.SimpleMetadataManager;
+import org.gbean.metadata.ClassMetadata;
+import org.gbean.metadata.ConstructorMetadata;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.kernel.ConstructorSignature;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class NamedConstructorArgsTest extends TestCase {
+ private DefaultListableBeanFactory factory;
+
+ public void testSimplePropertiesConversion() {
+ // pre conditions
+ String beanName = "hal";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
+ assertEquals(0, constructorArgumentValues.getArgumentCount());
+
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ assertTrue(propertyValues.contains("prefix"));
+ assertTrue(propertyValues.contains("suffix"));
+
+ // process factory
+ PropertiesMetadataProvider metadataProvider = new PropertiesMetadataProvider();
+ MetadataManager metadataManager = new SimpleMetadataManager(Collections.singleton(metadataProvider));
+ NamedConstructorArgs namedConstructorArgs = new NamedConstructorArgs(metadataManager);
+ namedConstructorArgs.postProcessBeanFactory(factory);
+
+ // post conditions
+ beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
+ assertEquals(2, constructorArgumentValues.getArgumentCount());
+ assertTrue(constructorArgumentValues.getGenericArgumentValues().isEmpty());
+ ConstructorArgumentValues.ValueHolder arg = constructorArgumentValues.getIndexedArgumentValue(0, String.class);
+ assertNotNull(arg);
+ assertEquals("I'm sorry ", arg.getValue());
+ arg = constructorArgumentValues.getIndexedArgumentValue(1, String.class);
+ assertNotNull(arg);
+ assertEquals("; I'm afraid I can't do that.", arg.getValue());
+
+ propertyValues = beanDefinition.getPropertyValues();
+ assertFalse(propertyValues.contains("prefix"));
+ assertFalse(propertyValues.contains("suffix"));
+ }
+
+ public void testForcedConstructor() {
+ // pre conditions
+ String beanName = "hal";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ RootBeanDefinition beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
+ assertEquals(0, constructorArgumentValues.getArgumentCount());
+
+ MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
+ assertTrue(propertyValues.contains("prefix"));
+ assertTrue(propertyValues.contains("suffix"));
+
+ // process factory
+ PropertiesMetadataProvider metadataProvider = new PropertiesMetadataProvider() {
+ public void addClassMetadata(ClassMetadata classMetadata) {
+ super.addClassMetadata(classMetadata);
+ if (classMetadata.getType().equals(HelloMessage.class)) {
+ ConstructorMetadata constructor = classMetadata.getConstructor(
+ new ConstructorSignature(new String[] {"java.lang.String", "java.lang.String", "java.util.Properties"}));
+ constructor.put("always-use", null);
+ }
+ }
+ };
+
+ MetadataManager metadataManager = new SimpleMetadataManager(Collections.singleton(metadataProvider));
+ NamedConstructorArgs namedConstructorArgs = new NamedConstructorArgs(metadataManager);
+ namedConstructorArgs.postProcessBeanFactory(factory);
+
+ // post conditions
+ beanDefinition = (RootBeanDefinition) factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+
+ constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
+ assertEquals(3, constructorArgumentValues.getArgumentCount());
+ assertTrue(constructorArgumentValues.getGenericArgumentValues().isEmpty());
+ ConstructorArgumentValues.ValueHolder arg = constructorArgumentValues.getIndexedArgumentValue(0, String.class);
+ assertNotNull(arg);
+ assertEquals("I'm sorry ", arg.getValue());
+ arg = constructorArgumentValues.getIndexedArgumentValue(1, String.class);
+ assertNotNull(arg);
+ assertEquals("; I'm afraid I can't do that.", arg.getValue());
+ arg = constructorArgumentValues.getIndexedArgumentValue(2, Properties.class);
+ assertNotNull(arg);
+ assertNull(arg.getValue());
+
+ propertyValues = beanDefinition.getPropertyValues();
+ assertFalse(propertyValues.contains("prefix"));
+ assertFalse(propertyValues.contains("suffix"));
+ }
+
+ protected void setUp() throws Exception {
+ factory = new DefaultListableBeanFactory();
+ Resource resource = new FileSystemResource(new File("src/test-data/NamedConstructorArgsTest.xml"));
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
+ reader.loadBeanDefinitions(resource);
+ }
+}
diff --git a/kernel/src/test/org/gbean/spring/ObjectNameBuilderTest.java b/kernel/src/test/org/gbean/spring/ObjectNameBuilderTest.java
new file mode 100644
index 0000000..fcdb1a9
--- /dev/null
+++ b/kernel/src/test/org/gbean/spring/ObjectNameBuilderTest.java
@@ -0,0 +1,91 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * 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.gbean.spring;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import javax.management.ObjectName;
+
+import junit.framework.TestCase;
+import org.gbean.kernel.ServiceName;
+import org.gbean.metadata.MetadataManager;
+import org.gbean.metadata.simple.PropertiesMetadataProvider;
+import org.gbean.metadata.simple.SimpleMetadataManager;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class ObjectNameBuilderTest extends TestCase {
+ private DefaultListableBeanFactory factory;
+
+ public void testObjectNameProperty() {
+ String beanName = "hal";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+ assertTrue(beanDefinition.getPropertyValues().contains("gbean-object-name"));
+
+ ObjectName objectName = ServiceName.createName((String) beanDefinition.getPropertyValues().getPropertyValue("gbean-object-name").getValue());
+
+ // convert properties into named constructor args
+ List metadataProviders = new ArrayList(2);
+ metadataProviders.add(new PropertiesMetadataProvider());
+ MetadataManager metadataManager = new SimpleMetadataManager(metadataProviders);
+
+ ObjectNameBuilder objectNameBuilder = new ObjectNameBuilder(metadataManager, "domain", "server", "application");
+ objectNameBuilder.postProcessBeanFactory(factory);
+
+ assertFalse(beanDefinition.getPropertyValues().contains("gbean-object-name"));
+ assertEquals(objectName, objectNameBuilder.getObjectName(beanName));
+ }
+
+ public void testObjectNameCreation() {
+ String beanName = "foobar";
+ assertTrue(factory.containsBeanDefinition(beanName));
+ BeanDefinition beanDefinition = factory.getBeanDefinition(beanName);
+ assertNotNull(beanDefinition);
+ assertFalse(beanDefinition.getPropertyValues().contains("gbean-object-name"));
+
+ // convert properties into named constructor args
+ List metadataProviders = new ArrayList(2);
+ metadataProviders.add(new PropertiesMetadataProvider());
+ MetadataManager metadataManager = new SimpleMetadataManager(metadataProviders);
+
+ ObjectNameBuilder objectNameBuilder = new ObjectNameBuilder(metadataManager, "domain", "server", "module");
+ objectNameBuilder.postProcessBeanFactory(factory);
+
+ ObjectName objectName = ServiceName.createName("domain:J2EEServer=server,J2EEApplication=null,J2EEModule=module,name=" + beanName);
+
+ objectNameBuilder.postProcessBeanFactory(factory);
+
+ assertFalse(beanDefinition.getPropertyValues().contains("gbean-object-name"));
+ assertEquals(objectName, objectNameBuilder.getObjectName(beanName));
+ }
+
+ protected void setUp() throws Exception {
+ factory = new DefaultListableBeanFactory();
+ Resource resource = new FileSystemResource(new File("src/test-data/PostProcessorTest.xml"));
+ XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
+ reader.loadBeanDefinitions(resource);
+ }
+}