You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ga...@apache.org on 2011/10/31 21:49:26 UTC

svn commit: r1195665 - in /geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core: DeploymentUtils.java GeronimoServerBehaviourDelegate.java

Author: gawor
Date: Mon Oct 31 20:49:25 2011
New Revision: 1195665

URL: http://svn.apache.org/viewvc?rev=1195665&view=rev
Log:
GERONIMODEVTOOLS-771: Support for class hot swap for OSGi applications

Modified:
    geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/DeploymentUtils.java
    geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/GeronimoServerBehaviourDelegate.java

Modified: geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/DeploymentUtils.java
URL: http://svn.apache.org/viewvc/geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/DeploymentUtils.java?rev=1195665&r1=1195664&r2=1195665&view=diff
==============================================================================
--- geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/DeploymentUtils.java (original)
+++ geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/DeploymentUtils.java Mon Oct 31 20:49:25 2011
@@ -17,6 +17,7 @@
 package org.apache.geronimo.st.v30.core;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -36,6 +37,7 @@ import org.eclipse.core.runtime.CoreExce
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jst.j2ee.application.internal.operations.AppClientComponentExportDataModelProvider;
 import org.eclipse.jst.j2ee.application.internal.operations.EARComponentExportDataModelProvider;
@@ -58,6 +60,7 @@ import org.eclipse.wst.server.core.model
 import org.eclipse.wst.server.core.model.IModuleResource;
 import org.eclipse.wst.server.core.model.IModuleResourceDelta;
 import org.eclipse.wst.server.core.util.ProjectModule;
+import org.eclipse.wst.server.core.util.PublishHelper;
 
 /**
  * @version $Rev$ $Date$
@@ -379,7 +382,7 @@ public class DeploymentUtils {
             }
         }
         return false;
-    }
+    }     
     
     public static boolean isInstalledModule(IServer server, String configId) {
         Trace.tracePoint("Entry", Activator.traceCore, "DeploymentUtils.isInstalledModule", server, configId);
@@ -434,4 +437,74 @@ public class DeploymentUtils {
         
         return configId;
     }
+        
+    public static IModuleResource[] getChangedClassResources(IModuleResourceDelta[] deltaArray) {
+        Trace.tracePoint("Entry", Activator.traceCore, "DeploymentUtils.getChangedClassResources", deltaArray);
+        List<IModuleResource> changedClassResources = new ArrayList<IModuleResource>();
+        // collect only changed classes resources
+        if (collectChangedClassResources(deltaArray, changedClassResources) && !changedClassResources.isEmpty()) {
+            // modified class resources were only found
+            IModuleResource[] resources = new IModuleResource[changedClassResources.size()];
+            changedClassResources.toArray(resources);
+            Trace.tracePoint("Exit ", Activator.traceCore, "DeploymentUtils.getChangedClassResources", resources);
+            return resources;
+        } else {
+            // added or removed resources or non-class resources were found
+            Trace.tracePoint("Exit ", Activator.traceCore, "DeploymentUtils.getChangedClassResources", "Added or removed resources or non-class resources were found");
+            return null;
+        }
+    }
+    
+    private static boolean collectChangedClassResources(IModuleResourceDelta[] deltaArray, List<IModuleResource> list) {
+        for (IModuleResourceDelta delta : deltaArray) {
+            int kind = delta.getKind();        
+            if (kind == IModuleResourceDelta.ADDED || kind == IModuleResourceDelta.REMOVED) {
+                return false;
+            }
+            IModuleResource resource = delta.getModuleResource();
+            if (resource instanceof IModuleFile) {
+                String name = resource.getName();
+                if (!name.endsWith(".class")) {
+                    return false;
+                }
+                if (kind == IModuleResourceDelta.CHANGED) {
+                    list.add(resource);
+                }
+            } else if (resource instanceof IModuleFolder) {
+                IModuleResourceDelta[] childDeltaArray = delta.getAffectedChildren();
+                if (!collectChangedClassResources(childDeltaArray, list)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+    
+    public static File createChangeSetFile(IModuleResource[] resources) {
+        Trace.tracePoint("Entry", Activator.traceCore, "DeploymentUtils.createChangeSetFile", resources);
+        
+        File file = null;
+        try {
+            file = File.createTempFile("changeset", ".jar");
+        } catch (IOException e) {
+            Trace.tracePoint("Exit ", Activator.traceCore, "DeploymentUtils.createChangeSetFile", e);
+            return null;
+        }
+        
+        PublishHelper publishHelper = new PublishHelper(null);
+        IStatus[] statusArray = publishHelper.publishZip(resources, new Path(file.getAbsolutePath()), null);
+        if (statusArray != null) {
+            for (IStatus status : statusArray) {
+                if (!status.isOK()) {
+                    file.delete();
+                    Trace.tracePoint("Exit ", Activator.traceCore, "DeploymentUtils.createChangeSetFile", status);
+                    return null;
+                }
+            }
+        }
+        
+        Trace.tracePoint("Exit ", Activator.traceCore, "DeploymentUtils.createChangeSetFile", file);
+        return file;
+    }
+
 }

Modified: geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/GeronimoServerBehaviourDelegate.java
URL: http://svn.apache.org/viewvc/geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/GeronimoServerBehaviourDelegate.java?rev=1195665&r1=1195664&r2=1195665&view=diff
==============================================================================
--- geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/GeronimoServerBehaviourDelegate.java (original)
+++ geronimo/devtools/eclipse-plugin/trunk/plugins/org.apache.geronimo.st.v30.core/src/main/java/org/apache/geronimo/st/v30/core/GeronimoServerBehaviourDelegate.java Mon Oct 31 20:49:25 2011
@@ -105,8 +105,10 @@ import org.eclipse.wst.server.core.Serve
 import org.eclipse.wst.server.core.internal.IModulePublishHelper;
 import org.eclipse.wst.server.core.internal.ProgressUtil;
 import org.eclipse.wst.server.core.model.IModuleFile;
+import org.eclipse.wst.server.core.model.IModuleResource;
 import org.eclipse.wst.server.core.model.IModuleResourceDelta;
 import org.eclipse.wst.server.core.model.ServerBehaviourDelegate;
+import org.eclipse.wst.server.core.util.PublishHelper;
 import org.eclipse.wst.server.core.util.SocketUtil;
 
 /**
@@ -589,10 +591,7 @@ public class GeronimoServerBehaviourDele
     
     private IStatus refreshBundle(IModule ebaModule, IModule bundleModule, AbstractName ebaName, Map<String, Long> bundleMap) {
         Trace.tracePoint("Entry", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundle", ebaModule, bundleModule, ebaName, bundleMap);
-
         try {
-            File file = DeploymentUtils.getTargetFile(getServer(), bundleModule);
-            
             String symbolicName = AriesHelper.getSymbolicName(bundleModule);
             Long bundleId = bundleMap.get(symbolicName);
             
@@ -602,7 +601,13 @@ public class GeronimoServerBehaviourDele
             }
             
             ExtendedDeploymentManager dm = (ExtendedDeploymentManager) DeploymentCommandFactory.getDeploymentManager(getServer());
-            dm.updateEBAContent(ebaName, bundleId, file);
+            /*
+             * Try class hot swap first and if it fails fallback to regular bundle update.
+             */
+            if (!refreshBundleClasses(dm, ebaModule, bundleModule, ebaName, bundleId)) {
+                File file = DeploymentUtils.getTargetFile(getServer(), bundleModule);
+                dm.updateEBAContent(ebaName, bundleId, file);
+            }
         } catch (Exception e) {
             return new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.REFRESH_FAIL, e);
         }
@@ -612,6 +617,52 @@ public class GeronimoServerBehaviourDele
         return Status.OK_STATUS;
     }
 
+    private boolean refreshBundleClasses(ExtendedDeploymentManager dm, IModule ebaModule, IModule bundleModule, AbstractName ebaName, long bundleId) throws Exception {
+        Trace.tracePoint("Entry", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", ebaModule, bundleModule, ebaName, bundleId);    
+        // check if class hot swap is supported
+        if (!dm.isRedefineClassesSupported()) {
+            Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", "Class redefinition is not supported");        
+            return false;
+        }
+        // ensure only classes have changed
+        IModuleResourceDelta[] delta = getPublishedResourceDelta(new IModule[] { ebaModule, bundleModule });
+        IModuleResource[] classResources = DeploymentUtils.getChangedClassResources(delta);
+        if (classResources == null) {
+            Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", "Non-class resource modifications found");
+            return false;
+        }
+        // create temp. zip with the changes
+        File changeSetFile = DeploymentUtils.createChangeSetFile(classResources);
+        if (changeSetFile == null) {
+            Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", "Error creating file with resource modifications");
+            return false;
+        }
+        // get document base for the module if it is expanded
+        String documentBase = getServerDelegate().isNoRedeploy() ? getWebModuleDocumentBase(bundleModule) : null;
+        // see if the classes can be hot swapped - update archive if module is not expanded
+        if (!dm.hotSwapEBAContent(ebaName, bundleId, changeSetFile, documentBase == null)) {
+            Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", "Bundle class hot swap cannot be preformed");
+            changeSetFile.delete();
+            return false;
+        } else {
+            changeSetFile.delete();
+        }
+        if (documentBase != null) {
+            PublishHelper publishHelper = new PublishHelper(getTempDirectory().toFile());   
+            IStatus[] statusArray = publishHelper.publishFull(classResources, new Path(documentBase), null);
+            if (statusArray != null) {
+                // XXX: in case of an error should we return false to force full re-deploy?
+                for (IStatus status : statusArray) {
+                    if (!status.isOK()) {
+                        Trace.trace(Trace.WARNING, "Error publishing changes: " + status.getMessage(), status.getException(), Activator.traceCore);
+                    }
+                }
+            }
+        }
+        Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.refreshBundleClasses", "Bundle class hot swap was succesfully preformed", documentBase);
+        return true;
+    }
+    
     private static class ModuleDelta {
         private final IModule[] module;
         private int delta = NO_CHANGE;
@@ -938,28 +989,34 @@ public class GeronimoServerBehaviourDele
         Trace.tracePoint("Exit ", Activator.traceCore, "GeronimoServerBehaviourDelegate.invokeCommand");
     }   
 
-    private IStatus tryFileReplace(IModule[] module) {
-        Trace.tracePoint("Entry", Activator.traceCore, "GeronimoServerBehaviourDelegate.tryFileReplace", module.toString());
+    private String getWebModuleDocumentBase(IModule webModule) {
+        Trace.tracePoint("Entry", Activator.traceCore, "GeronimoServerBehaviourDelegate.getWebModuleDocumentBase", webModule);
         
-        IModule webModule = module[module.length - 1];        
         if (webModule.isExternal()) {
-            Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.tryFileReplace", "External module");
+            Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.getWebModuleDocumentBase", "External module");
             return null;
         }
-
+                
         String contextPath = getServerDelegate().getContextPath(webModule);
         if (contextPath == null) {
-            Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.tryFileReplace", "Context path is null");
+            Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.getWebModuleDocumentBase", "Context path is null");
             return null;
         }
-        Trace.trace(Trace.INFO, "Context path: " + contextPath, Activator.logCore);
 
         String documentBase = getWebModuleDocumentBase(contextPath);
-        if (documentBase == null || documentBase.length() == 0) {
+        Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.getWebModuleDocumentBase", contextPath, documentBase);
+        return documentBase;        
+    }
+    
+    private IStatus tryFileReplace(IModule[] module) {
+        Trace.tracePoint("Entry", Activator.traceCore, "GeronimoServerBehaviourDelegate.tryFileReplace", module.toString());
+        
+        IModule webModule = module[module.length - 1];        
+        String documentBase = getWebModuleDocumentBase(webModule);
+        if (documentBase == null ) {
             Trace.tracePoint("Exit", Activator.traceCore, "GeronimoServerBehaviourDelegate.tryFileReplace", "Document base is null");
             return null;
         }
-        Trace.trace(Trace.INFO, "Document base: " + documentBase, Activator.logCore);
 
         List<IModuleResourceDelta> modifiedFiles = findModifiedFiles(module);
         if (modifiedFiles == null) {
@@ -1584,7 +1641,7 @@ public class GeronimoServerBehaviourDele
                 String moduleContextPath = (String) kernel.getAttribute(name, "contextPath");
                 if (contextPath.equals(moduleContextPath)) {
                     String docBase = (String) kernel.getAttribute(name, "docBase");
-                    return docBase;
+                    return (docBase != null && docBase.length() > 0) ? docBase : null;
                 }
             } catch (GBeanNotFoundException e) {
                 // ignore