Author: vanto
Date: Thu Jan  6 17:44:08 2011
New Revision: 1055956

URL: http://svn.apache.org/viewvc?rev=1055956&view=rev
Log:
ODE-901: Improved handling of SMX4 BPEL bundles. Big thanks to Kurt Westerfeld.

Added:
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeDeployedBundle.java
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtender.java
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderImpl.java
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderThreadFactory.java
Modified:
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/ServiceUnitActivator.java
    
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/resources/META-INF/spring/ode-jbi.xml

Modified: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/ServiceUnitActivator.java
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/ServiceUnitActivator.java?rev=1055956&r1=1055955&r2=1055956&view=diff
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/ServiceUnitActivator.java
 (original)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/ServiceUnitActivator.java
 Thu Jan  6 17:44:08 2011
@@ -19,101 +19,27 @@
 
 package org.apache.ode.jbi.osgi;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
+import java.util.logging.Logger;
 
-import javax.jbi.component.Component;
-import javax.jbi.component.ServiceUnitManager;
-
-import org.apache.commons.io.IOUtils;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
+
 
 /**
- * @author mproch
+ * This class is now deprecated in favor of using OdeExtender service, which 
watches
+ * deployment of bundles and manages start/stop/install/uninstall/update from 
OSGi
+ * to ODE.
  * 
+ * @deprecated
+ * @see OdeExtenderImpl
  */
 public class ServiceUnitActivator implements BundleActivator {
-
-    File rootDir;
-    String generatedName;
+    private static final Logger LOG = 
Logger.getLogger(ServiceUnitActivator.class.getName());
 
     public void start(BundleContext context) throws Exception {
-        generatedName = context.getBundle().getSymbolicName();
-        rootDir = context.getDataFile("bpelData");
-        rootDir.mkdirs();
-        Enumeration<?> en = context.getBundle().findEntries("/", "*", false);
-        while (en.hasMoreElements()) {
-            copyOne(rootDir, (URL) en.nextElement());
-        }
-        ServiceReference[] refs = context.getAllServiceReferences(
-                "javax.jbi.component.Component", "(&(NAME=OdeBpelEngine))");
-        if (refs == null || refs.length != 1) {
-            throw new RuntimeException("no appropriate service :(");
-        }
-        ServiceUnitManager suM = ((Component) context.getService(refs[0]))
-                .getServiceUnitManager();
-        ClassLoader l = Thread.currentThread().getContextClassLoader();
-        try {
-            ClassLoader suL = suM.getClass().getClassLoader();
-            Thread.currentThread().setContextClassLoader(new 
BundleClassLoader(suL, context.getBundle()));
-            suM.deploy(generatedName, rootDir.getAbsolutePath());
-            suM.init(generatedName, rootDir.getAbsolutePath());
-            suM.start(generatedName);
-        } finally {
-            Thread.currentThread().setContextClassLoader(l);
-        }
-
-    }
-
-    private void copyOne(File dest, URL url) throws Exception {
-        File d = new File(dest, url.getPath());
-        InputStream str = url.openStream();
-        if (str != null) {
-            FileWriter wr = new FileWriter(d);
-            try {
-                IOUtils.copy(str, wr);
-            } finally {
-                wr.flush();
-                wr.close();
-            }
-        }
+       LOG.warning("Use of " + this.getClass().getName() + " has been 
deprecated.  BPEL bundle deployment is now handled by the ODE extender service. 
 Remove Bundle-Activator from OSGi manifest for bundle: " + 
context.getBundle().getSymbolicName());
     }
 
     public void stop(BundleContext context) throws Exception {
-        ServiceReference[] refs = context.getAllServiceReferences(
-                "javax.jbi.component.Component", "(&(NAME=OdeBpelEngine))");
-        if (refs == null || refs.length != 1) {
-            throw new RuntimeException("no appropriate service :(");
-        }
-        ServiceUnitManager suM = ((Component) context.getService(refs[0]))
-                .getServiceUnitManager();
-        suM.shutDown(generatedName);
-        suM.undeploy(generatedName, rootDir.getAbsolutePath());
-
     }
-
-    public class BundleClassLoader extends ClassLoader {
-        private final Bundle delegate;
-
-        public BundleClassLoader(ClassLoader parent, Bundle delegate) {
-            super(parent);
-            this.delegate = delegate;
-        }
-
-        @Override
-        public Class<?> loadClass(String name) throws ClassNotFoundException {
-            try {
-                return getParent().loadClass(name);
-            } catch (Exception e) {
-                return delegate.loadClass(name);
-            }
-        }
-    }
-
 }

Added: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeDeployedBundle.java
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeDeployedBundle.java?rev=1055956&view=auto
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeDeployedBundle.java
 (added)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeDeployedBundle.java
 Thu Jan  6 17:44:08 2011
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ode.jbi.osgi.deployer;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.jbi.component.Component;
+import javax.jbi.component.ComponentLifeCycle;
+import javax.jbi.component.ServiceUnitManager;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.ode.bpel.iapi.ProcessStore;
+import org.apache.ode.jbi.OdeContext;
+import org.osgi.framework.Bundle;
+
+public class OdeDeployedBundle {
+    private static final Logger LOG = 
Logger.getLogger(OdeDeployedBundle.class.getName());
+    private boolean updated;
+    private Bundle bundle;
+    private OdeExtenderImpl odeRegistrationService;
+    private File rootDir;
+    private String duName;
+    private String name;
+
+    OdeDeployedBundle(Bundle bundle, OdeExtenderImpl odeRegistrationService) {
+       if (LOG.isLoggable(Level.FINE))
+           LOG.fine("Initialized ODE service unit deployer for bundle: " + 
bundle.getSymbolicName());
+       this.bundle = bundle;
+       this.odeRegistrationService = odeRegistrationService;
+    }
+
+    String getName() {
+       if (this.name == null)
+           this.name = this.bundle.getSymbolicName();
+       return this.name;
+    }
+
+    private String getDUName() {
+       if (this.duName == null)
+           this.duName = getName() + "-" + bundle.getVersion().getMicro();
+       return this.duName;
+    }
+
+    private File getRootDir() {
+       if (this.rootDir == null && this.bundle.getBundleContext() != null)
+           this.rootDir = 
this.bundle.getBundleContext().getDataFile("bpelData/" + getDUName());
+       return this.rootDir;
+    }
+
+    void doStart() throws Exception {
+       // If we are already started, don't bother starting again.
+       LOG.info("Starting ODE service unit: " + getName());
+
+       // Wait until ODE is available before starting.
+       waitAvailable();
+
+       // Do we need to undeploy first?
+       boolean needUpdate = updated;
+       boolean forceDeploy = needUpdate;
+       this.updated = false;
+
+       // Do deploy.
+       this.deploy(this.bundle, 
this.odeRegistrationService.getOdeComponent().getServiceUnitManager(), 
forceDeploy, needUpdate);
+    }
+
+    void doStop() throws Exception {
+       LOG.info("Stopping ODE service unit: " + getName());
+       this.shutdown(this.bundle, 
this.odeRegistrationService.getOdeComponent().getServiceUnitManager());
+    }
+
+    void doInstall() throws Exception {
+       LOG.info("Installing ODE service unit: " + getName());
+    }
+
+    void doUninstall() throws Exception {
+       LOG.info("Uninstalling ODE service unit: " + getName());
+       this.undeploy(this.bundle, 
this.odeRegistrationService.getOdeComponent().getServiceUnitManager());
+    }
+
+    void doUpdate() throws Exception {
+       LOG.info("Updating ODE service unit: " + getName());
+       
+       // We simply mark the update state of this bundle so that on next 
start, we do a redeploy
+       updated = true;
+    }
+
+    private void deploy(Bundle bundle, ServiceUnitManager suM, boolean 
forceDeploy, boolean undeploy) throws Exception {
+       // Do deployment.
+       File rootDir = getRootDir();
+       String duName = getDUName();
+       boolean needDeploy = rootDir.mkdirs() || forceDeploy;
+       if (LOG.isLoggable(Level.FINE))
+           LOG.fine("Exploding content to " + rootDir + " for " + duName);
+       Enumeration<?> en = bundle.findEntries("/", "*", false);
+       while (en.hasMoreElements())
+           needDeploy |= copyOne(rootDir, (URL) en.nextElement());
+
+       // Now start it.
+       ClassLoader l = Thread.currentThread().getContextClassLoader();
+       try {
+           ClassLoader suL = suM.getClass().getClassLoader();
+           Thread.currentThread().setContextClassLoader(new 
BundleClassLoader(suL, bundle));
+           try {
+               // Try first an init/start, which will fail if the process isn't
+               // here.
+               if (needDeploy) {
+                   // If deployed, undeploy first.
+                   if (undeploy && isDeployed(duName)) {
+                       // Do the undeploy to service unit manager.
+                       LOG.info("Performing undeploy " + duName + " from dir " 
+ rootDir);
+                       suM.undeploy(duName, rootDir.getAbsolutePath());
+
+                       // Now, remove any .cbp files.
+                       File[] cbpFiles = rootDir.listFiles(new 
FilenameFilter() {
+                           @Override
+                           public boolean accept(File dir, String name) {
+                               return name.endsWith(".cbp");
+                           }
+                       });
+                       for (File cbpFile : cbpFiles) {
+                           LOG.info("Removing compiled bpel process: " + 
cbpFile);
+                           cbpFile.delete();
+                       }
+                   }
+
+                   LOG.info("Deploying " + duName + " to dir " + rootDir);
+                   suM.deploy(duName, rootDir.getAbsolutePath());
+               }
+               suM.init(duName, rootDir.getAbsolutePath());
+               suM.start(duName);
+           } catch (javax.jbi.management.DeploymentException e) {
+               LOG.log(Level.WARNING, "Deploy failed; could not deploy/start 
this bundle: " + this.getName(), e);
+               throw e;
+           }
+       } finally {
+           Thread.currentThread().setContextClassLoader(l);
+       }
+    }
+
+    private boolean isDeployed(String processName) {
+       boolean Result = true;
+       try {
+           // Get the "ProcessStore" interface by grabbing the internal field
+           // of OdeContext and querying for the processes. Could also use 
PMAPI here, 
+           // but in any case we just need to know if the process exists in a 
deployed state.
+           //
+           // TODO: add a OdeContext.getStore() method to clean this up.
+           OdeContext inst = OdeContext.getInstance();
+           Field _store = inst.getClass().getDeclaredField("_store");
+           _store.setAccessible(true);
+           ProcessStore ps = (ProcessStore) _store.get(inst);
+           List<QName> processes = ps.listProcesses(processName);
+           Result = processes != null && !processes.isEmpty();
+       } catch (Exception e) {
+           LOG.log(Level.WARNING, "Could not determine deployment state for 
process: " + processName, e);
+       }
+       return Result;
+    }
+
+    private boolean copyOne(File dest, URL url) throws Exception {
+       File d = new File(dest, url.getPath());
+       boolean needDeploy = !d.exists();
+       long length = d.exists() ? d.length() : 0L;
+       InputStream str = url.openStream();
+       if (str != null) {
+           FileWriter wr = new FileWriter(d);
+           try {
+               IOUtils.copy(str, wr);
+           } finally {
+               wr.flush();
+               wr.close();
+           }
+
+           // If file is zero-length (which is the case handling a directory),
+           // just remove it.
+           if (d.exists() && d.length() == 0) {
+               d.delete();
+               needDeploy = false;
+           } else
+               needDeploy |= length != d.length();
+       }
+       return needDeploy;
+    }
+
+    private void shutdown(Bundle bundle, ServiceUnitManager suM) throws 
Exception {
+       String duName = getDUName();
+       if (suM != null) {
+           suM.stop(duName);
+           suM.shutDown(duName);
+       } else {
+           LOG.warning("Could not shutdown this process (" + duName + ") 
because ode component was never located");
+       }
+    }
+
+    private void undeploy(Bundle bundle, ServiceUnitManager suM) throws 
Exception {
+       String duName = getDUName();
+       if (suM != null) {
+           if (isDeployed(duName)) {
+               // Use ODE's classloader to avoid class loading from the bundle
+               // being undeployed.
+               ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
+               try {
+                   
Thread.currentThread().setContextClassLoader(suM.getClass().getClassLoader());
+                   File rootDir = getRootDir();
+                   LOG.info("Performing undeploy " + duName + " from dir " + 
rootDir);
+                   suM.undeploy(duName, rootDir.getAbsolutePath());
+               } finally {
+                   Thread.currentThread().setContextClassLoader(classLoader);
+               }
+           }
+       } else {
+           LOG.warning("Could not shutdown this process (" + duName + ") 
because ode component was never located");
+       }
+    }
+
+    public class BundleClassLoader extends ClassLoader {
+       private final Bundle delegate;
+
+       public BundleClassLoader(ClassLoader parent, Bundle delegate) {
+           super(parent);
+           this.delegate = delegate;
+       }
+
+       @Override
+       public Class<?> loadClass(String name) throws ClassNotFoundException {
+           try {
+               return getParent().loadClass(name);
+           } catch (Exception e) {
+               return delegate.loadClass(name);
+           }
+       }
+    }
+
+    private void waitAvailable() throws InterruptedException {
+       /**
+        * We need to wait until the service unit manager is available before 
+        * proceeding.  Also, since the ode component itself does an 
asynchronous
+        * start with respect to this bundle, we need to wait until it is done
+        * initializing.  This would be much cleaner if we could simply
+        * call "isStarted" on OdeLifeCycle, which maintains a started state.
+        * 
+        * If we do not wait until the ode component is started, deployments
+        * will fail sporadically because of asynchronous start race conditions.
+        */
+       boolean showedWait = false;
+       while 
(this.odeRegistrationService.getOdeComponent().getServiceUnitManager() == null 
|| !isStarted(this.odeRegistrationService.getOdeComponent())) {
+
+           // Do a wait.
+           if (!showedWait) {
+               LOG.info("Waiting for ODE to arrive (" + getName() + ")...");
+               showedWait = true;
+           }
+           Thread.sleep(500L);
+       }
+    }
+
+    private boolean isStarted(Component odeComponent) {
+       
+       boolean Result = true;
+       try {
+           // Get the ODE component started state by grabbing the internal 
field
+           // of OdeLifeCycle.  We cannot rely on the started state of the ODE
+           // component bundle.
+           //
+           // TODO: add OdeLifeCycle.isStarted() and do a cast of 
odeComponent.getLifeCycle() accordingly.
+           ComponentLifeCycle inst = odeComponent.getLifeCycle();
+           Field _started = inst.getClass().getDeclaredField("_started");
+           _started.setAccessible(true);
+           Result = Boolean.TRUE.equals(_started.get(inst));
+       } catch (Exception e) {
+           LOG.log(Level.WARNING, "Could not determine started state for ode 
component", e);
+       }
+       return Result;
+    }
+}

Added: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtender.java
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtender.java?rev=1055956&view=auto
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtender.java
 (added)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtender.java
 Thu Jan  6 17:44:08 2011
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ode.jbi.osgi.deployer;
+
+import org.osgi.framework.Bundle;
+
+public interface OdeExtender {
+    public Bundle[] getBundles();
+}

Added: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderImpl.java
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderImpl.java?rev=1055956&view=auto
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderImpl.java
 (added)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderImpl.java
 Thu Jan  6 17:44:08 2011
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ode.jbi.osgi.deployer;
+
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.jbi.component.Component;
+
+import org.apache.ode.jbi.osgi.ServiceUnitActivator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.osgi.context.BundleContextAware;
+
+public class OdeExtenderImpl implements OdeExtender, InitializingBean, 
DisposableBean, BundleContextAware {
+    private static final Logger LOG = 
Logger.getLogger(OdeExtenderImpl.class.getName());
+    private static final String SU_ACTIVATOR_DEPRECATED = 
ServiceUnitActivator.class.getName();
+    private BundleContext bundleContext;
+    private BundleTracker tracker;
+    private Component odeComponent;
+    private Executor executor;
+
+    public OdeExtenderImpl() {
+    }
+
+    @Override
+    public void setBundleContext(BundleContext bundleContext) {
+       this.bundleContext = bundleContext;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+       // Create our executor.
+       executor = Executors.newSingleThreadExecutor(new 
OdeExtenderThreadFactory("ODE Extender"));
+
+       // Start tracking bundles. We are looking for /deploy.xml as a signature
+       // to deploy the ODE BPEL bundle, if the bundle has at least one .bpel
+       // file.
+       int stateMask = Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING | 
Bundle.INSTALLED | Bundle.UNINSTALLED;
+       this.tracker = new BundleTracker(this.bundleContext, stateMask, new 
ODEBundleTrackerCustomizer());
+       this.tracker.open();
+    }
+
+    @Override
+    public void destroy() throws Exception {
+       // Close the tracker.
+       BundleTracker tracker = this.tracker;
+       this.tracker = null;
+       if (tracker != null)
+           tracker.close();
+
+       // Drop our thread pool.
+       this.executor = null;
+    }
+
+    @Override
+    public Bundle[] getBundles() {
+       return this.tracker.getBundles();
+    }
+
+    public void setOdeComponent(Component odeComponent) {
+       this.odeComponent = odeComponent;
+    }
+
+    public Component getOdeComponent() {
+       return odeComponent;
+    }
+
+    private boolean isBPELBundle(Bundle bundle) {
+       boolean Result = false;
+
+       // First see if there is a deploy.xml.
+       URL entry = bundle.getEntry("deploy.xml");
+       if (entry != null) {
+           // Next, check if there's at least one BPEL file.
+           @SuppressWarnings("rawtypes")
+           Enumeration bpelFiles = bundle.findEntries("/", "*.bpel", false);
+           if (bpelFiles != null && bpelFiles.hasMoreElements()) {
+               // Make sure there's a symbolic name.
+               if (bundle.getSymbolicName() != null) {
+                   // Make sure there's no bundle activator.
+                   // NOTE: if the "ServiceUnitActivator" is found, we hijack 
those bundles as well and manage them.
+                   Dictionary<?, ?> headers = bundle.getHeaders();
+                   Object activator = null;
+                   if (headers == null || (activator = 
headers.get(Constants.BUNDLE_ACTIVATOR)) == null || 
SU_ACTIVATOR_DEPRECATED.equals(activator)) {
+                       if (LOG.isLoggable(Level.FINE))
+                           LOG.fine("Recognized ODE deployment bundle: " + 
bundle.getSymbolicName());
+                       Result = true;
+                   } else
+                       LOG.warning("Ignoring ODE bundle " + 
bundle.getSymbolicName() + " which has custom activator: " + activator);
+               } else
+                   LOG.warning("Ignoring ODE bundle " + bundle.getBundleId() + 
" which has no OSGi symbolic name");
+           }
+       }
+
+       return Result;
+    }
+
+    private class ODEBundleTrackerCustomizer implements 
BundleTrackerCustomizer {
+       private Map<Long, OdeDeployedBundle> bundles = new 
ConcurrentHashMap<Long, OdeDeployedBundle>();
+
+       @Override
+       public void removedBundle(Bundle bundle, BundleEvent event, Object 
object) {
+       }
+
+       @Override
+       public void modifiedBundle(Bundle bundle, BundleEvent event, Object 
object) {
+           if (event != null) {
+               if (LOG.isLoggable(Level.FINE))
+                   LOG.fine("Received " + getEventType(event.getType()) + " 
event for bundle: " + bundle.getSymbolicName());
+               switch (event.getType()) {
+               case BundleEvent.STARTED:
+                   executor.execute(new Start((OdeDeployedBundle) object));
+                   break;
+               case BundleEvent.STOPPING:
+                   executor.execute(new Stop((OdeDeployedBundle) object));
+                   break;
+               case BundleEvent.INSTALLED:
+                   executor.execute(new Install((OdeDeployedBundle) object));
+                   break;
+               case BundleEvent.UNINSTALLED:
+                   executor.execute(new Uninstall((OdeDeployedBundle) object));
+                   break;
+               case BundleEvent.UPDATED:
+                   executor.execute(new Update((OdeDeployedBundle) object));
+                   break;
+               }
+
+               // Do this outside the try/catch above. Last chance to drop a
+               // bundle.
+               if (event.getType() == BundleEvent.UNINSTALLED)
+                   bundles.remove(bundle.getBundleId());
+           }
+       }
+
+       private String getEventType(int type) {
+           switch (type) {
+           case BundleEvent.INSTALLED:
+               return "installed";
+           case BundleEvent.LAZY_ACTIVATION:
+               return "lazy activation";
+           case BundleEvent.RESOLVED:
+               return "resolved";
+           case BundleEvent.STARTED:
+               return "started";
+           case BundleEvent.STARTING:
+               return "starting";
+           case BundleEvent.STOPPED:
+               return "stopped";
+           case BundleEvent.STOPPING:
+               return "stopping";
+           case BundleEvent.UNINSTALLED:
+               return "uninstalled";
+           case BundleEvent.UNRESOLVED:
+               return "unresolved";
+           case BundleEvent.UPDATED:
+               return "updated";
+           }
+           return "(unknown: " + type + ")";
+       }
+
+       @Override
+       public Object addingBundle(Bundle bundle, BundleEvent event) {
+           Object Result = null;
+
+           // Is this a BPEL bundle?
+           if (isBPELBundle(bundle)) {
+               // Found BPEL signature; setup deployer.
+               OdeDeployedBundle deployer = bundles.get(bundle.getBundleId());
+               if (deployer == null)
+                   bundles.put(bundle.getBundleId(), deployer = new 
OdeDeployedBundle(bundle, OdeExtenderImpl.this));
+               Result = deployer;
+
+               // Is this an initial bundle?
+               if (event == null) {
+                   // If the bundle is active, then we didn't start it. So
+                   // start it now.
+                   if (bundle.getState() == Bundle.ACTIVE)
+                       executor.execute(new Start(deployer));
+               } else
+                   modifiedBundle(bundle, event, deployer);
+           }
+
+           return Result;
+       }
+    }
+
+    private static abstract class OperationClosure implements Runnable {
+       protected OdeDeployedBundle target;
+
+       OperationClosure(OdeDeployedBundle target) {
+           this.target = target;
+       }
+
+       @Override
+       public final void run() {
+           String name = Thread.currentThread().getName();
+           try {
+               Thread.currentThread().setName(name + ":" + 
getClass().getSimpleName() + ":" + target.getName());
+               perform();
+           } catch (Exception e) {
+               LOG.log(Level.WARNING, "Could not perform '" + 
getClass().getSimpleName() + "' operation on bundle: " + target.getName(), e);
+           } finally {
+               Thread.currentThread().setName(name);
+           }
+       }
+
+       protected abstract void perform() throws Exception;
+    }
+
+    private static class Start extends OperationClosure {
+       Start(OdeDeployedBundle target) {
+           super(target);
+       }
+
+       @Override
+       protected void perform() throws Exception {
+           target.doStart();
+       }
+    }
+
+    private static class Stop extends OperationClosure {
+       Stop(OdeDeployedBundle target) {
+           super(target);
+       }
+
+       @Override
+       protected void perform() throws Exception {
+           target.doStop();
+       }
+    }
+
+    private static class Install extends OperationClosure {
+       Install(OdeDeployedBundle target) {
+           super(target);
+       }
+
+       @Override
+       protected void perform() throws Exception {
+           target.doInstall();
+       }
+    }
+
+    private static class Uninstall extends OperationClosure {
+       Uninstall(OdeDeployedBundle target) {
+           super(target);
+       }
+
+       @Override
+       protected void perform() throws Exception {
+           target.doUninstall();
+       }
+    }
+
+    private static class Update extends OperationClosure {
+       Update(OdeDeployedBundle target) {
+           super(target);
+       }
+
+       @Override
+       protected void perform() throws Exception {
+           target.doUpdate();
+       }
+    }
+}

Added: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderThreadFactory.java
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderThreadFactory.java?rev=1055956&view=auto
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderThreadFactory.java
 (added)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/java/org/apache/ode/jbi/osgi/deployer/OdeExtenderThreadFactory.java
 Thu Jan  6 17:44:08 2011
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ode.jbi.osgi.deployer;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+public class OdeExtenderThreadFactory implements ThreadFactory {
+    private final ThreadFactory factory = Executors.defaultThreadFactory();
+    private final String name;
+
+    public OdeExtenderThreadFactory(String name) {
+       this.name = name;
+    }
+
+    public Thread newThread(Runnable r) {
+       final Thread t = factory.newThread(r);
+       t.setName(name);
+       t.setDaemon(true);
+       return t;
+    }
+}

Modified: 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/resources/META-INF/spring/ode-jbi.xml
URL: 
http://svn.apache.org/viewvc/ode/branches/ode-1.3.5.x/jbi-bundle/src/main/resources/META-INF/spring/ode-jbi.xml?rev=1055956&r1=1055955&r2=1055956&view=diff
==============================================================================
--- 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/resources/META-INF/spring/ode-jbi.xml
 (original)
+++ 
ode/branches/ode-1.3.5.x/jbi-bundle/src/main/resources/META-INF/spring/ode-jbi.xml
 Thu Jan  6 17:44:08 2011
@@ -63,5 +63,18 @@
         <prop key="ode-jbi.jca.port">0</prop>
         <prop 
key="javax.persistence.provider">org.apache.openjpa.persistence.PersistenceProviderImpl</prop>
     </osgix:cm-properties>
-    
+
+    <!-- ODE Extender Service -->
+    <bean id="ode-extender-service" 
class="org.apache.ode.jbi.osgi.deployer.OdeExtenderImpl">
+      <property name="odeComponent">
+        <ref bean="ode-jbi-component" />
+      </property>
+    </bean>
+
+    <osgi:service ref="ode-extender-service">
+        <osgi:interfaces>
+            <value>org.apache.ode.jbi.osgi.deployer.OdeExtender</value>
+        </osgi:interfaces>
+    </osgi:service>
+
 </beans>


Reply via email to