geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ga...@apache.org
Subject svn commit: r1179228 - in /geronimo/server/trunk: ./ framework/ plugins/aries/geronimo-aries/ plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/
Date Wed, 05 Oct 2011 13:57:49 GMT
Author: gawor
Date: Wed Oct  5 13:57:49 2011
New Revision: 1179228

URL: http://svn.apache.org/viewvc?rev=1179228&view=rev
Log:
GERONIMO-6181: Better error messages when OSGi application fails to start

Added:
    geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
  (with props)
Modified:
    geronimo/server/trunk/framework/pom.xml
    geronimo/server/trunk/plugins/aries/geronimo-aries/pom.xml
    geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ApplicationGBean.java
    geronimo/server/trunk/pom.xml

Modified: geronimo/server/trunk/framework/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/pom.xml?rev=1179228&r1=1179227&r2=1179228&view=diff
==============================================================================
--- geronimo/server/trunk/framework/pom.xml (original)
+++ geronimo/server/trunk/framework/pom.xml Wed Oct  5 13:57:49 2011
@@ -34,7 +34,6 @@
     <packaging>pom</packaging>
     
     <properties>        
-        <equinox.version>3.7.1.R37x_v20110808_1106</equinox.version>        
         <felix.configadmin.version>1.2.4</felix.configadmin.version>        
         <felix.framework.version>3.0.2</felix.framework.version>       
         <pax.url.version>1.1.2</pax.url.version>        
@@ -43,12 +42,6 @@
     <dependencyManagement>
         <dependencies>
             <dependency>
-                <groupId>org.eclipse.osgi</groupId>
-                <artifactId>org.eclipse.osgi</artifactId>
-                <version>${equinox.version}</version>
-            </dependency>
-
-            <dependency>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>org.apache.felix.framework</artifactId>
                 <version>${felix.framework.version}</version>

Modified: geronimo/server/trunk/plugins/aries/geronimo-aries/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/aries/geronimo-aries/pom.xml?rev=1179228&r1=1179227&r2=1179228&view=diff
==============================================================================
--- geronimo/server/trunk/plugins/aries/geronimo-aries/pom.xml (original)
+++ geronimo/server/trunk/plugins/aries/geronimo-aries/pom.xml Wed Oct  5 13:57:49 2011
@@ -40,13 +40,18 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-                <groupId>org.apache.aries</groupId>
-                <artifactId>org.apache.aries.util</artifactId>              
 
-            </dependency>
+            <groupId>org.apache.aries</groupId>
+            <artifactId>org.apache.aries.util</artifactId>                
+        </dependency>
         <dependency>
             <groupId>org.apache.aries.application</groupId>
             <artifactId>org.apache.aries.application.utils</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.osgi</groupId>
+            <artifactId>org.eclipse.osgi</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -59,6 +64,10 @@
                         <Export-Package>
                           org.apache.geronimo.aries
                         </Export-Package>
+                        <Import-Package>
+                            org.eclipse.*;resolution:=optional,
+                            *
+                        </Import-Package>
                     </instructions>
                 </configuration>
             </plugin>

Modified: geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ApplicationGBean.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ApplicationGBean.java?rev=1179228&r1=1179227&r2=1179228&view=diff
==============================================================================
--- geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ApplicationGBean.java
(original)
+++ geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ApplicationGBean.java
Wed Oct  5 13:57:49 2011
@@ -24,6 +24,7 @@ import java.io.InputStream;
 import java.net.URI;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -190,7 +191,17 @@ public class ApplicationGBean implements
             Bundle[] bundles = new Bundle [] { targetBundle };
             // resolve the bundle
             if (!packageAdmin.resolveBundles(bundles)) {
-                throw new BundleException("Updated " + bundleName  + " bundle cannot be resolved");
+                StringBuilder builder = new StringBuilder();
+                builder.append("Updated ").append(bundleName).append(" bundle cannot be resolved.");
+                
+                // check for resolver errors
+                ResolverErrorAnalyzer errorAnalyzer = new ResolverErrorAnalyzer(context);
+                String resolverErrors = errorAnalyzer.getErrorsAsString(Arrays.asList(bundles));
+                if (resolverErrors != null) {
+                    builder.append(" ").append(resolverErrors);
+                }
+                
+                throw new BundleException(builder.toString());
             }
             
             Set<Bundle> dependents = new HashSet<Bundle>();
@@ -281,6 +292,7 @@ public class ApplicationGBean implements
         while(iterator.hasNext()) {
             Bundle bundle = iterator.next();
             builder.append(bundle.getSymbolicName());
+            builder.append(" [").append(bundle.getBundleId()).append("]");
             if (iterator.hasNext()) {
                 builder.append(", ");
             }
@@ -511,20 +523,46 @@ public class ApplicationGBean implements
         LOG.debug("Starting {} application.", application.getApplicationMetadata().getApplicationScope());
         
         applicationState = ApplicationState.STARTING;
+        try {
+            startApplicationBundles();
+            applicationState = ApplicationState.ACTIVE;
+            LOG.debug("Application {} started successfully.", application.getApplicationMetadata().getApplicationScope());
+        } catch (BundleException be) {
+            applicationState = ApplicationState.INSTALLED;
+            
+            Exception rootException = be;
+            String rootMessage = be.getMessage();
+            
+            // check for resolver errors
+            ResolverErrorAnalyzer errorAnalyzer = new ResolverErrorAnalyzer(bundle.getBundleContext());
+            String resolverErrors = errorAnalyzer.getErrorsAsString(applicationBundles);
+            if (resolverErrors != null) {
+                rootException = null;
+                rootMessage = resolverErrors;
+            }
 
+            String message = MessageFormat.format("Error starting {0} application. {1}",

+                                                  application.getApplicationMetadata().getApplicationScope(),

+                                                  rootMessage);
+            
+            if (getFailOnStartError()) {
+                throw new BundleException(message, rootException);
+            } else {
+                LOG.error(message, rootException);
+            }
+        }        
+    }    
+    
+    private void startApplicationBundles() throws BundleException {
         List<Bundle> bundlesWeStarted = new ArrayList<Bundle>();
-        Bundle currentBundle = null;
         try {
             for (Bundle b : applicationBundles) {
-                currentBundle = b;
                 if (BundleUtils.canStart(b)) {
                     LOG.debug("Starting {} application bundle.", b);
                     b.start(Bundle.START_TRANSIENT);
                     bundlesWeStarted.add(b);
                 }
             }
-            applicationState = ApplicationState.ACTIVE;
-            LOG.debug("Application {} started successfully.", application.getApplicationMetadata().getApplicationScope());
         } catch (BundleException be) {
             for (Bundle b : bundlesWeStarted) {
                 try {
@@ -538,19 +576,10 @@ public class ApplicationGBean implements
                     // stop.
                 }
             }
-
-            applicationState = ApplicationState.INSTALLED;
-            if (getFailOnStartError()) {
-                throw be;
-            } else {
-                String message = MessageFormat.format("Error starting {0} application. Bundle
{1} failed to start.", 
-                                                      application.getApplicationMetadata().getApplicationScope(),

-                                                      currentBundle);
-                LOG.error(message, be);
-            }
-        }        
-    }    
-
+            throw be;
+        }
+    }
+    
     public void doStop() {
         LOG.debug("Stopping {} application.", application.getApplicationMetadata().getApplicationScope());
         

Added: geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java?rev=1179228&view=auto
==============================================================================
--- geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
(added)
+++ geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
Wed Oct  5 13:57:49 2011
@@ -0,0 +1,198 @@
+/**
+ *  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.geronimo.aries;
+
+import static org.eclipse.osgi.service.resolver.ResolverError.IMPORT_PACKAGE_USES_CONFLICT;
+import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_FRAGMENT_HOST;
+import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_IMPORT_PACKAGE;
+import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_REQUIRE_BUNDLE;
+import static org.eclipse.osgi.service.resolver.ResolverError.REQUIRE_BUNDLE_USES_CONFLICT;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.service.resolver.BundleSpecification;
+import org.eclipse.osgi.service.resolver.ExportPackageDescription;
+import org.eclipse.osgi.service.resolver.HostSpecification;
+import org.eclipse.osgi.service.resolver.ImportPackageSpecification;
+import org.eclipse.osgi.service.resolver.PlatformAdmin;
+import org.eclipse.osgi.service.resolver.ResolverError;
+import org.eclipse.osgi.service.resolver.State;
+import org.eclipse.osgi.service.resolver.VersionConstraint;
+import org.eclipse.osgi.service.resolver.VersionRange;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/*
+ * Collects resolver errors for a given set of bundles and trims out any errors caused by
+ * dependent errors and so generates a list of "root" errors.
+ */
+public class ResolverErrorAnalyzer {
+
+    private BundleContext bundleContext;
+    
+    public ResolverErrorAnalyzer(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+    
+    private boolean hasPlatformAdmin() {
+        try {
+            bundleContext.getBundle().loadClass("org.eclipse.osgi.service.resolver.PlatformAdmin");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+        
+    public String getErrorsAsString(Collection<Bundle> bundles) {
+        Collection<String> errors = getErrors(bundles);
+        if (errors.isEmpty()) {
+            return null;
+        } else {
+            String LF = System.getProperty("line.separator");
+            StringBuilder builder = new StringBuilder();
+            builder.append("The following problems were detected:").append(LF);
+            Iterator<String> iterator = errors.iterator();
+            while (iterator.hasNext()) {
+                builder.append("    ");
+                builder.append(iterator.next());
+                if (iterator.hasNext()) {
+                    builder.append(LF);
+                }
+            }
+            return builder.toString();
+        }
+    }
+    
+    public Collection<String> getErrors(Collection<Bundle> bundles) {
+        if (!hasPlatformAdmin()) {
+            return Collections.emptyList();
+        }
+
+        List<String> errors = new ArrayList<String>();
+        
+        ServiceReference ref = bundleContext.getServiceReference(PlatformAdmin.class.getName());
+        try {
+            PlatformAdmin platformAdmin = (PlatformAdmin) bundleContext.getService(ref);
+            State systemState = platformAdmin.getState(false);
+            List<BundleDescription> bundleDescriptions = new ArrayList<BundleDescription>(bundles.size());
+            for (Bundle bundle : bundles) {
+                BundleDescription bundleDescription = systemState.getBundle(bundle.getBundleId());
+                if (bundleDescription != null) {
+                    bundleDescriptions.add(bundleDescription);
+                }
+            }
+            for (BundleDescription bundleDescription : bundleDescriptions) {
+                collectErrors(bundleDescription, systemState, bundleDescriptions, errors);
               
+            }            
+        } finally {
+            bundleContext.ungetService(ref);
+        }
+        
+        return errors;
+    }
+        
+    private void collectErrors(BundleDescription bundle, State state, List<BundleDescription>
bundleDescriptions, Collection<String> errorList) {
+        ResolverError[] errors = state.getResolverErrors(bundle);
+        for (ResolverError error : errors) {
+            VersionConstraint constraint = error.getUnsatisfiedConstraint();
+            switch (error.getType()) {
+                case MISSING_IMPORT_PACKAGE:
+                    ImportPackageSpecification importPackageSpecification = (ImportPackageSpecification)
constraint;
+                    String resolution = (String) importPackageSpecification.getDirective(Constants.RESOLUTION_DIRECTIVE);
+                    if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(resolution)
|| ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(resolution)) {
+                        // don't care about unsatisfied optional or dynamic imports
+                        continue;
+                    }
+                    if (isSatisfied(importPackageSpecification, bundleDescriptions) == null)
{
+                        errorList.add("The package dependency " + versionToString(importPackageSpecification)
+ " required by bundle " + bundleToString(bundle) + " cannot be satisfied.");
+                    }
+                    break;
+                case MISSING_REQUIRE_BUNDLE:
+                    BundleSpecification bundleSpecification = (BundleSpecification) constraint;
+                    if (bundleSpecification.isOptional()) {
+                        // don't care about unsatisfied optional require-bundle
+                        continue;
+                    }
+                    if (isSatisfied(bundleSpecification, bundleDescriptions) == null) {
+                        errorList.add("The bundle dependency " + versionToString(bundleSpecification)
+ " required by bundle " + bundleToString(bundle) + " cannot be satisfied.");
+                    }
+                    break;
+                case MISSING_FRAGMENT_HOST:
+                    HostSpecification hostSpecification = (HostSpecification) constraint;
+                    if (isSatisfied(hostSpecification, bundleDescriptions) == null) {
+                        errorList.add("The host bundle dependency " + versionToString(hostSpecification)
+ " required by bundle " + bundleToString(bundle) + " cannot be satisfied.");
+                    }
+                    break;
+                case IMPORT_PACKAGE_USES_CONFLICT:
+                case REQUIRE_BUNDLE_USES_CONFLICT:
+                default:   
+                    errorList.add(error.toString());
+                    break;
+            }
+        }
+    }
+    
+    private static ExportPackageDescription isSatisfied(ImportPackageSpecification importPackageSpecification,
Collection<BundleDescription> bundleDescriptions) {
+        for (BundleDescription b : bundleDescriptions) {
+            ExportPackageDescription[] exportedPackages = b.getExportPackages();
+            if (exportedPackages != null) {
+                for (ExportPackageDescription exportedPackage : exportedPackages) {
+                    if (importPackageSpecification.isSatisfiedBy(exportedPackage)) {
+                        return exportedPackage;
+                    }
+                }
+            }
+        }
+        return null;
+    }    
+    
+    private static BundleDescription isSatisfied(VersionConstraint constraint, Collection<BundleDescription>
bundleDescriptions) {
+        for (BundleDescription b : bundleDescriptions) {
+            if (constraint.isSatisfiedBy(b)) {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    private static String bundleToString(BundleDescription bundle) {
+        return bundle.getSymbolicName() + " [" + bundle.getBundleId() + "]";            
+    }
+    
+    private static String versionToString(VersionConstraint constraint) {
+        VersionRange versionRange = constraint.getVersionRange();
+        if (versionRange == null) {
+            return constraint.getName();
+        } else {
+            String versionAttribute;            
+            if (constraint instanceof ImportPackageSpecification) {
+                versionAttribute = "version=\"" + versionRange + "\"";
+            } else {
+                versionAttribute = "bundle-version=\"" + versionRange + "\"";
+            }
+            return constraint.getName() + "; " + versionAttribute;
+        }
+    } 
+}

Propchange: geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: geronimo/server/trunk/plugins/aries/geronimo-aries/src/main/java/org/apache/geronimo/aries/ResolverErrorAnalyzer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: geronimo/server/trunk/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/server/trunk/pom.xml?rev=1179228&r1=1179227&r2=1179228&view=diff
==============================================================================
--- geronimo/server/trunk/pom.xml (original)
+++ geronimo/server/trunk/pom.xml Wed Oct  5 13:57:49 2011
@@ -148,6 +148,7 @@
         <pluginSrcRepoApacheSnapshots>http://repository.apache.org/snapshots/</pluginSrcRepoApacheSnapshots>
         
         <!-- OSGI properties -->
+        <equinox.version>3.7.1.R37x_v20110808_1106</equinox.version>    
         <felix.bundlerepository.version>1.6.6</felix.bundlerepository.version>
         <karaf.version>2.2.1</karaf.version>
         <karaf.osgi.version>2.2.1</karaf.osgi.version>
@@ -1682,6 +1683,12 @@ only found in cxf
             </dependency>
 
             <dependency>
+                <groupId>org.eclipse.osgi</groupId>
+                <artifactId>org.eclipse.osgi</artifactId>
+                <version>${equinox.version}</version>
+            </dependency>
+
+            <dependency>
                 <groupId>org.osgi</groupId>
                 <artifactId>org.osgi.core</artifactId>
                 <version>4.2.0</version>



Mime
View raw message