001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package org.apache.xbean.osgi.bundle.util; 021 022 import java.net.URL; 023 import java.util.Collections; 024 import java.util.Dictionary; 025 import java.util.Enumeration; 026 import java.util.LinkedHashSet; 027 import java.util.List; 028 029 import org.osgi.framework.Bundle; 030 import org.osgi.framework.BundleReference; 031 import org.osgi.framework.Constants; 032 import org.osgi.framework.ServiceReference; 033 import org.osgi.service.packageadmin.ExportedPackage; 034 import org.osgi.service.packageadmin.PackageAdmin; 035 036 /** 037 * @version $Rev: 937957 $ $Date: 2010-04-26 10:00:08 +0200 (Mon, 26 Apr 2010) $ 038 */ 039 public class BundleUtils { 040 041 public static boolean canStart(Bundle bundle) { 042 return (bundle.getState() != Bundle.UNINSTALLED) && (bundle.getState() != Bundle.STARTING) && (!isFragment(bundle)); 043 } 044 045 public static boolean canStop(Bundle bundle) { 046 return (bundle.getState() != Bundle.UNINSTALLED) && (bundle.getState() != Bundle.STOPPING) && (!isFragment(bundle)); 047 } 048 049 public static boolean canUninstall(Bundle bundle) { 050 return bundle.getState() != Bundle.UNINSTALLED; 051 } 052 053 public static boolean isFragment(Bundle bundle) { 054 Dictionary headers = bundle.getHeaders(); 055 return (headers != null && headers.get(Constants.FRAGMENT_HOST) != null); 056 } 057 058 /** 059 * Returns bundle (if any) associated with current thread's context classloader. 060 * 061 * @param unwrap if true and if the bundle associated with the context classloader is a 062 * {@link DelegatingBundle}, this function will return the main application bundle 063 * backing with the {@link DelegatingBundle}. Otherwise, the bundle associated with 064 * the context classloader is returned as is. See {@link BundleClassLoader#getBundle(boolean)} 065 * for more information. 066 * @return The bundle associated with the current thread's context classloader. Might be null. 067 */ 068 public static Bundle getContextBundle(boolean unwrap) { 069 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 070 if (classLoader instanceof BundleClassLoader) { 071 return ((BundleClassLoader) classLoader).getBundle(unwrap); 072 } else if (classLoader instanceof BundleReference) { 073 return ((BundleReference) classLoader).getBundle(); 074 } else { 075 return null; 076 } 077 } 078 079 /** 080 * Works like {@link Bundle#getEntryPaths(String)} but also returns paths 081 * in attached fragment bundles. 082 * 083 * @param bundle 084 * @param name 085 * @return 086 */ 087 public static Enumeration<String> getEntryPaths(Bundle bundle, String name) { 088 Enumeration<URL> entries = bundle.findEntries(name, null, false); 089 if (entries == null) { 090 return null; 091 } 092 LinkedHashSet<String> paths = new LinkedHashSet<String>(); 093 while (entries.hasMoreElements()) { 094 URL url = entries.nextElement(); 095 String path = url.getPath(); 096 if (path.startsWith("/")) { 097 path = path.substring(1); 098 } 099 paths.add(path); 100 } 101 return Collections.enumeration(paths); 102 } 103 104 /** 105 * Works like {@link Bundle#getEntry(String)} but also checks 106 * attached fragment bundles for the given entry. 107 * 108 * @param bundle 109 * @param name 110 * @return 111 */ 112 public static URL getEntry(Bundle bundle, String name) { 113 if (name.equals("/")) { 114 return bundle.getEntry(name); 115 } else if (name.endsWith("/")) { 116 name = name.substring(0, name.length() - 1); 117 } 118 String path; 119 String pattern; 120 int pos = name.lastIndexOf("/"); 121 if (pos == -1) { 122 path = "/"; 123 pattern = name; 124 } else if (pos == 0) { 125 path = "/"; 126 pattern = name.substring(1); 127 } else { 128 path = name.substring(0, pos); 129 pattern = name.substring(pos + 1); 130 } 131 Enumeration<URL> entries = bundle.findEntries(path, pattern, false); 132 if (entries != null && entries.hasMoreElements()) { 133 return entries.nextElement(); 134 } else { 135 return null; 136 } 137 } 138 139 public static LinkedHashSet<Bundle> getWiredBundles(Bundle bundle) { 140 ServiceReference reference = bundle.getBundleContext().getServiceReference(PackageAdmin.class.getName()); 141 PackageAdmin packageAdmin = (PackageAdmin) bundle.getBundleContext().getService(reference); 142 try { 143 return getWiredBundles(packageAdmin, bundle); 144 } finally { 145 bundle.getBundleContext().ungetService(reference); 146 } 147 } 148 149 public static LinkedHashSet<Bundle> getWiredBundles(PackageAdmin packageAdmin, Bundle bundle) { 150 BundleDescription description = new BundleDescription(bundle.getHeaders()); 151 // handle static wire via Import-Package 152 List<BundleDescription.ImportPackage> imports = description.getExternalImports(); 153 LinkedHashSet<Bundle> wiredBundles = new LinkedHashSet<Bundle>(); 154 for (BundleDescription.ImportPackage packageImport : imports) { 155 ExportedPackage[] exports = packageAdmin.getExportedPackages(packageImport.getName()); 156 Bundle wiredBundle = getWiredBundle(bundle, exports); 157 if (wiredBundle != null) { 158 wiredBundles.add(wiredBundle); 159 } 160 } 161 // handle dynamic wire via DynamicImport-Package 162 if (!description.getDynamicImportPackage().isEmpty()) { 163 for (Bundle b : bundle.getBundleContext().getBundles()) { 164 if (!wiredBundles.contains(b)) { 165 ExportedPackage[] exports = packageAdmin.getExportedPackages(b); 166 Bundle wiredBundle = getWiredBundle(bundle, exports); 167 if (wiredBundle != null) { 168 wiredBundles.add(wiredBundle); 169 } 170 } 171 } 172 } 173 return wiredBundles; 174 } 175 176 private static Bundle getWiredBundle(Bundle bundle, ExportedPackage[] exports) { 177 if (exports != null) { 178 for (ExportedPackage exportedPackage : exports) { 179 Bundle[] importingBundles = exportedPackage.getImportingBundles(); 180 if (importingBundles != null) { 181 for (Bundle importingBundle : importingBundles) { 182 if (importingBundle == bundle) { 183 return exportedPackage.getExportingBundle(); 184 } 185 } 186 } 187 } 188 } 189 return null; 190 } 191 }