File file = bundleContext.getDataFile("bundle-checksums.properties");
bundleChecksums.load(file);
for (Bundle bundle : systemBundleContext.getBundles()) {
if (bundle.getSymbolicName() != null && bundle.getBundleId() != 0) {
Resource resource = null;
boolean update = false;
for (Resource res : toDeploy) {
if (bundle.getSymbolicName().equals(getSymbolicName(res))) {
if (bundle.getVersion().equals(getVersion(res))) {
if (isUpdateable(res)) {
// if the checksum are different
InputStream is = null;
try {
is = getBundleInputStream(res, providers);
long newCrc = ChecksumUtils.checksum(is);
long oldCrc = bundleChecksums.containsKey(bundle.getLocation()) ? Long.parseLong(bundleChecksums.get(bundle.getLocation())) : 0l;
if (newCrc != oldCrc) {
LOGGER.debug("New snapshot available for " + bundle.getLocation());
update = true;
newCheckums.put(bundle.getLocation(), Long.toString(newCrc));
}
} finally {
if (is != null) {
is.close();
}
}
}
resource = res;
break;
}
}
}
if (resource != null) {
toDeploy.remove(resource);
resToBnd.put(resource, bundle);
if (update) {
toUpdate.put(bundle, resource);
}
} else if (bundleSymbolicNameMatches(bundle, ignoredBundles)) {
//Do nothing and ignore the bundle.
} else {
toDelete.add(bundle);
}
}
}
// Second pass on remaining resources
for (Resource resource : toDeploy) {
TreeMap<Version, Bundle> matching = new TreeMap<Version, Bundle>();
VersionRange range = getMicroVersionRange(getVersion(resource));
for (Bundle bundle : toDelete) {
if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
matching.put(bundle.getVersion(), bundle);
}
}
if (!matching.isEmpty()) {
Bundle bundle = matching.lastEntry().getValue();
toUpdate.put(bundle, resource);
toDelete.remove(bundle);
resToBnd.put(resource, bundle);
} else {
toInstall.add(resource);
}
}
// Check if an update of the agent is needed
Resource agentResource = toUpdate.get(bundleContext.getBundle());
if (agentResource != null) {
LOGGER.info("Updating agent");
LOGGER.info(" " + getUri(agentResource));
InputStream is = getBundleInputStream(agentResource, providers);
Bundle bundle = bundleContext.getBundle();
//We need to store the agent checksum and save before we update the agent.
if (newCheckums.containsKey(bundle.getLocation())) {
bundleChecksums.put(bundle.getLocation(), newCheckums.get(bundle.getLocation()));
}
bundleChecksums.save(); // Force the needed classes to be loaded
bundle.update(is);
return;
}
// Display
LOGGER.info("Changes to perform:");
LOGGER.info(" Bundles to uninstall:");
for (Bundle bundle : toDelete) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
}
LOGGER.info(" Bundles to update:");
for (Map.Entry<Bundle, Resource> entry : toUpdate.entrySet()) {
LOGGER.info(" " + entry.getKey().getSymbolicName() + " / " + entry.getKey().getVersion() + " with " + getUri(entry.getValue()));
}
LOGGER.info(" Bundles to install:");
for (Resource resource : toInstall) {
LOGGER.info(" " + getUri(resource));
}
Set<Bundle> toRefresh = new HashSet<Bundle>();
// Execute
LOGGER.info("Stopping bundles:");
List<Bundle> toStop = new ArrayList<Bundle>();
toStop.addAll(toUpdate.keySet());
toStop.addAll(toDelete);
while (!toStop.isEmpty()) {
List<Bundle> bs = getBundlesToDestroy(toStop);
for (Bundle bundle : bs) {
String hostHeader = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
if (hostHeader == null && (bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STARTING)) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
bundle.stop(Bundle.STOP_TRANSIENT);
}
toStop.remove(bundle);
}
}
LOGGER.info("Uninstalling bundles:");
for (Bundle bundle : toDelete) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
bundle.uninstall();
toRefresh.add(bundle);
}
LOGGER.info("Updating bundles:");
for (Map.Entry<Bundle, Resource> entry : toUpdate.entrySet()) {
Bundle bundle = entry.getKey();
Resource resource = entry.getValue();
LOGGER.info(" " + getUri(resource));
InputStream is = getBundleInputStream(resource, providers);
bundle.update(is);
toRefresh.add(bundle);
}
LOGGER.info("Installing bundles:");
for (Resource resource : toInstall) {
LOGGER.info(" " + getUri(resource));
InputStream is = getBundleInputStream(resource, providers);
Bundle bundle = systemBundleContext.installBundle(getUri(resource), is);
toRefresh.add(bundle);
resToBnd.put(resource, bundle);
// save a checksum of installed snapshot bundle
if (bundle.getVersion().getQualifier().endsWith(SNAPSHOT) && !newCheckums.containsKey(bundle.getLocation())) {
newCheckums.put(bundle.getLocation(), Long.toString(ChecksumUtils.checksum(getBundleInputStream(resource, providers))));
}
}
if (!newCheckums.isEmpty()) {
for (String key : newCheckums.keySet()) {
bundleChecksums.put(key, newCheckums.get(key));
}
try {
bundleChecksums.save();
} catch (IOException e) {
// this exception is most likely just due to fabric-agent version changes
// so the bundle has gone from under our feet so lets just log a warning
// so at least the agent can continue to load the new version of fabric-agent
LOGGER.warn("We failed to write the agent checksums which is probably due to the fabric-agent bundle being uninstalled so it can be replaced with a different version. Exception: " + e, e);
}
}
findBundlesWithOptionalPackagesToRefresh(toRefresh);
findBundlesWithFragmentsToRefresh(toRefresh);
LOGGER.info("Stopping bundles:");
toStop = new ArrayList<Bundle>();
toStop.addAll(toRefresh);
removeFragmentsAndBundlesInState(toStop, UNINSTALLED | RESOLVED | STOPPING);
while (!toStop.isEmpty()) {
List<Bundle> bs = getBundlesToDestroy(toStop);
for (Bundle bundle : bs) {
String hostHeader = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
if (hostHeader == null && (bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STARTING)) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
bundle.stop(Bundle.STOP_TRANSIENT);
}
toStop.remove(bundle);
}
}
updateStatus("finalizing", null);
LOGGER.info("Refreshing bundles:");
for (Bundle bundle : toRefresh) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
}
if (!toRefresh.isEmpty()) {
updateStatus("finalizing (refreshing)", null);
refreshPackages(toRefresh);
}
LOGGER.info("Resolving bundles");
List<Bundle> toResolve = new ArrayList<Bundle>();
removeFragmentsAndBundlesInState(toResolve, UNINSTALLED);
for (Resource resource : allResources) {
Bundle bundle = resToBnd.get(resource);
if (bundle != null) {
String hostHeader = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
if (hostHeader == null && bundle.getState() != Bundle.UNINSTALLED) {
toResolve.add(bundle);
}
}
}
if (!toResolve.isEmpty()) {
updateStatus("finalizing (resolving)", null);
}
systemBundleContext.getBundle().adapt(FrameworkWiring.class).resolveBundles(toResolve);
List<Resource> resourcesWithUrlHandlers = new ArrayList<Resource>();
for (Resource resource : allResources) {
for (Capability cap : resource.getCapabilities(null)) {
if (cap.getNamespace().equals(ServiceNamespace.SERVICE_NAMESPACE)) {
String[] itfs = getStrings(cap.getAttributes().get(Constants.OBJECTCLASS));
if (itfs != null) {
for (String itf : itfs) {
if (itf.equals(URLStreamHandlerService.class.getName())) {
if (!resourcesWithUrlHandlers.contains(resource)) {
resourcesWithUrlHandlers.add(resource);
}
break;
}
}
}
}
}
}
Set<Resource> firstSetToStart = new LinkedHashSet<Resource>();
Set<Resource> visited = new LinkedHashSet<Resource>();
for (Resource resource : resourcesWithUrlHandlers) {
visit(resource, visited, firstSetToStart, wiring);
}
// We hit FELIX-2949 if we don't use the correct order as Felix resolver isn't greedy.
// In order to minimize that, we make sure we resolve the bundles in the order they
// are given back by the resolution, meaning that all root bundles (i.e. those that were
// not flagged as dependencies in features) are started before the others. This should
// make sure those important bundles are started first and minimize the problem.
List<Throwable> exceptions = new ArrayList<Throwable>();
LOGGER.info("Starting bundles:");
if (!firstSetToStart.isEmpty()) {
updateStatus("finalizing (starting)", null);
}
// TODO: use wiring here instead of sorting
for (Resource resource : firstSetToStart) {
Bundle bundle = resToBnd.get(resource);
if (bundle == null) {
continue;
}
String hostHeader = bundle.getHeaders().get(Constants.FRAGMENT_HOST);
if (hostHeader == null && bundle.getState() != Bundle.ACTIVE) {
LOGGER.info(" " + bundle.getSymbolicName() + " / " + bundle.getVersion());
try {
bundle.start();
} catch (BundleException e) {
resourcesWithUrlHandlers.remove(resource);
exceptions.add(e);
}
}
}
if (!resourcesWithUrlHandlers.isEmpty()) {
LOGGER.info("Waiting for URL handlers...");
long t0 = System.currentTimeMillis();
while (!resourcesWithUrlHandlers.isEmpty() && t0 - System.currentTimeMillis() < 30 * 1000) {
for (Iterator<Resource> it = resourcesWithUrlHandlers.iterator(); it.hasNext(); ) {
Resource resource = it.next();
Bundle bundle = resToBnd.get(resource);
boolean remove = false;
if (bundle.getState() != Bundle.ACTIVE) {
remove = true;
} else {