Map<String, Set<Bundle>> unmanagedBundles = apply(diff(dstate.bundlesPerRegion, dstate.state.managedBundles),
map(dstate.bundles));
// Resolve
SubsystemResolver resolver = new SubsystemResolver(manager);
resolver.prepare(
dstate.features.values(),
request.requirements,
apply(unmanagedBundles, adapt(BundleRevision.class))
);
Set<String> prereqs = resolver.collectPrerequisites();
if (!prereqs.isEmpty()) {
for (Iterator<String> iterator = prereqs.iterator(); iterator.hasNext(); ) {
String prereq = iterator.next();
String[] parts = prereq.split("/");
VersionRange range;
if (parts[1].equals("0.0.0")) {
range = VersionRange.ANY_VERSION;
} else if (!parts[1].startsWith("[") && !parts[1].startsWith("(")) {
range = new VersionRange(Macro.transform(request.featureResolutionRange, parts[1]));
} else {
range = new VersionRange(parts[1]);
}
boolean found = false;
for (Set<String> featureSet : dstate.state.installedFeatures.values()) {
for (String feature : featureSet) {
String[] p = feature.split("/");
found = parts[0].equals(p[0]) && range.contains(VersionTable.getVersion(p[1]));
if (found) break;
}
if (found) break;
}
if (found) {
iterator.remove();
}
}
}
if (!prereqs.isEmpty()) {
DeploymentRequest newRequest = new DeploymentRequest();
newRequest.bundleUpdateRange = request.bundleUpdateRange;
newRequest.featureResolutionRange = request.featureResolutionRange;
newRequest.globalRepository = request.globalRepository;
newRequest.options = request.options;
newRequest.overrides = request.overrides;
newRequest.requirements = copy(dstate.state.requirements);
for (String prereq : prereqs) {
addToMapSet(newRequest.requirements, ROOT_REGION, prereq);
}
newRequest.stateChanges = Collections.emptyMap();
newRequest.updateSnaphots = request.updateSnaphots;
deploy(dstate, newRequest);
throw new PartialDeploymentException(prereqs);
}
resolver.resolve(
request.overrides,
request.featureResolutionRange,
request.globalRepository);
Map<String, StreamProvider> providers = resolver.getProviders();
Map<String, Set<Resource>> featuresPerRegion = resolver.getFeaturesPerRegions();
Map<String, Set<String>> installedFeatures = apply(featuresPerRegion, featureId());
Map<String, Set<String>> newFeatures = diff(installedFeatures, dstate.state.installedFeatures);
Map<String, Set<String>> delFeatures = diff(dstate.state.installedFeatures, installedFeatures);
//
// Compute requested features state
//
Map<String, Map<String, String>> stateFeatures = copy(dstate.state.stateFeatures);
for (Map.Entry<String, Set<String>> entry : delFeatures.entrySet()) {
Map<String, String> map = stateFeatures.get(entry.getKey());
if (map != null) {
map.entrySet().removeAll(entry.getValue());
if (map.isEmpty()) {
stateFeatures.remove(entry.getKey());
}
}
}
for (Map.Entry<String, Map<String, FeaturesService.RequestedState>> entry1 : request.stateChanges.entrySet()) {
String region = entry1.getKey();
Map<String, String> regionStates = stateFeatures.get(region);
if (regionStates != null) {
for (Map.Entry<String, FeaturesService.RequestedState> entry2 : entry1.getValue().entrySet()) {
String feature = entry2.getKey();
if (regionStates.containsKey(feature)) {
regionStates.put(feature, entry2.getValue().name());
}
}
}
}
for (Map.Entry<String, Set<String>> entry : newFeatures.entrySet()) {
for (String feature : entry.getValue()) {
Map<String, String> map = stateFeatures.get(entry.getKey());
if (map == null) {
map = new HashMap<>();
stateFeatures.put(entry.getKey(), map);
}
map.put(feature, noStart ? FeaturesService.RequestedState.Installed.name() : FeaturesService.RequestedState.Started.name());
}
}
// Compute information for each bundle
Map<String, Map<String, BundleInfo>> bundleInfos = resolver.getBundleInfos();
//
// Compute deployment
//
Deployer.Deployment deployment = computeDeployment(dstate, request, resolver);
//
// Compute the set of bundles to refresh
//
Set<Bundle> toRefresh = new TreeSet<>(new BundleComparator()); // sort is only used for display
for (Deployer.RegionDeployment regionDeployment : deployment.regions.values()) {
toRefresh.addAll(regionDeployment.toDelete);
toRefresh.addAll(regionDeployment.toUpdate.keySet());
}
if (!noRefreshManaged) {
computeBundlesToRefresh(toRefresh, dstate.bundles.values(), deployment.resToBnd, resolver.getWiring());
}
if (noRefreshUnmanaged) {
toRefresh.removeAll(flatten(unmanagedBundles));
}
// Automatically turn unmanaged bundles into managed bundles
// if they are required by a feature and no other unmanaged
// bundles have a requirement on it
Set<Bundle> toManage = new TreeSet<>(new BundleComparator()); // sort is only used for display
if (!noManageBundles) {
Set<Resource> features = resolver.getFeatures().keySet();
Set<? extends Resource> unmanaged = apply(flatten(unmanagedBundles), adapt(BundleRevision.class));
Set<Resource> requested = new HashSet<>();
// Gather bundles required by a feature
for (List<Wire> wires : resolver.getWiring().values()) {
for (Wire wire : wires) {
if (features.contains(wire.getRequirer()) && unmanaged.contains(wire.getProvider())) {
requested.add(wire.getProvider());
}
}
}
// Now, we know which bundles are completely unmanaged
unmanaged.removeAll(requested);
// Check if bundles have wires from really unmanaged bundles
for (List<Wire> wires : resolver.getWiring().values()) {
for (Wire wire : wires) {
if (requested.contains(wire.getProvider()) && unmanaged.contains(wire.getRequirer())) {
requested.remove(wire.getProvider());
}
}
}
if (!requested.isEmpty()) {
Map<Long, String> bundleToRegion = new HashMap<>();
for (Map.Entry<String, Set<Long>> entry : dstate.bundlesPerRegion.entrySet()) {
for (long id : entry.getValue()) {
bundleToRegion.put(id, entry.getKey());
}
}
for (Resource rev : requested) {
Bundle bundle = ((BundleRevision) rev).getBundle();
long id = bundle.getBundleId();
addToMapSet(managedBundles, bundleToRegion.get(id), id);
toManage.add(bundle);
}
}
}
Set<Bundle> toStart = new HashSet<>();
Set<Bundle> toResolve = new HashSet<>();
Set<Bundle> toStop = new HashSet<>();
//
// Compute bundle states
//
Map<Resource, FeaturesService.RequestedState> states = new HashMap<>();
for (Map.Entry<String, Set<Resource>> entry : resolver.getFeaturesPerRegions().entrySet()) {
String region = entry.getKey();
Map<String, String> fss = stateFeatures.get(region);
for (Resource feature : entry.getValue()) {
String fs = fss.get(getFeatureId(feature));
propagateState(states, feature, FeaturesService.RequestedState.valueOf(fs), resolver);
}
}
states.keySet().retainAll(resolver.getBundles().keySet());
//
// Compute bundles to start, stop and resolve
//
for (Map.Entry<Resource, FeaturesService.RequestedState> entry : states.entrySet()) {
Bundle bundle = deployment.resToBnd.get(entry.getKey());
if (bundle != null) {
switch (entry.getValue()) {
case Started:
toResolve.add(bundle);
toStart.add(bundle);
break;
case Resolved:
toResolve.add(bundle);
toStop.add(bundle);
break;
}
}
}
//
// Compute bundle all start levels and start levels to update
//
Map<Resource, Integer> startLevels = new HashMap<>();
Map<Bundle, Integer> toUpdateStartLevel = new HashMap<>();
for (Map.Entry<String, Set<Resource>> entry : resolver.getBundlesPerRegions().entrySet()) {
String region = entry.getKey();
for (Resource resource : entry.getValue()) {
BundleInfo bi = bundleInfos.get(region).get(getUri(resource));
if (bi != null) {
int sl = bi.getStartLevel() > 0 ? bi.getStartLevel() : dstate.initialBundleStartLevel;
startLevels.put(resource, sl);
Bundle bundle = deployment.resToBnd.get(resource);
if (bundle != null) {
int curSl = bundle.adapt(BundleStartLevel.class).getStartLevel();
if (sl != curSl) {
toUpdateStartLevel.put(bundle, sl);
if (sl > dstate.currentStartLevel) {
toStop.add(bundle);
}
}
}
}
}
}
//
// Log deployment
//
logDeployment(deployment, verbose);
if (simulate) {
if (!noRefresh && !toRefresh.isEmpty()) {
print(" Bundles to refresh:", verbose);
for (Bundle bundle : toRefresh) {
print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
}
}
if (!toManage.isEmpty()) {
print(" Managing bundle:", verbose);
for (Bundle bundle : toManage) {
print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
}
}
return;
}
//
// Execute deployment
//
// #1: stop bundles that needs to be updated or uninstalled in order
// #2: uninstall needed bundles
// #3: update regions
// #4: update bundles
// #5: install bundles
// #6: save state
// #7: install configuration
// #8: refresh bundles
// #9: start bundles in order
// #10: send events
//
//
// Handle updates on the FeaturesService bundle
//
Deployer.RegionDeployment rootRegionDeployment = deployment.regions.get(ROOT_REGION);
// We don't support uninstalling the bundle
if (rootRegionDeployment != null && rootRegionDeployment.toDelete.contains(dstate.serviceBundle)) {
throw new UnsupportedOperationException("Uninstalling the FeaturesService bundle is not supported");
}
// If the bundle needs to be updated, do the following:
// - persist the request to indicate the resolution must be continued after restart
// - update the checksum and save the state
// - compute bundles wired to the FeaturesService bundle that will be refreshed
// - stop the bundle
// - update the bundle
// - refresh wired bundles
// - start the bundle
// - exit
// When restarting, the resolution will be attempted again
if (rootRegionDeployment != null && rootRegionDeployment.toUpdate.containsKey(dstate.serviceBundle)) {
callback.persistResolveRequest(request);
// If the bundle is updated because of a different checksum,
// save the new checksum persistently
if (deployment.bundleChecksums.containsKey(dstate.serviceBundle.getBundleId())) {
State state = dstate.state.copy();
state.bundleChecksums.put(dstate.serviceBundle.getBundleId(),
deployment.bundleChecksums.get(dstate.serviceBundle.getBundleId()));
callback.saveState(state);
}
Resource resource = rootRegionDeployment.toUpdate.get(dstate.serviceBundle);
String uri = getUri(resource);
print("The FeaturesService bundle needs is being updated with " + uri, verbose);
toRefresh.clear();
toRefresh.add(dstate.serviceBundle);
computeBundlesToRefresh(toRefresh,
dstate.bundles.values(),
Collections.<Resource, Bundle>emptyMap(),
Collections.<Resource, List<Wire>>emptyMap());
callback.stopBundle(dstate.serviceBundle, STOP_TRANSIENT);
try (
InputStream is = getBundleInputStream(resource, providers)
) {
callback.updateBundle(dstate.serviceBundle, is);
}
callback.refreshPackages(toRefresh);
callback.startBundle(dstate.serviceBundle);
return;
}
//
// Perform bundle operations
//
//
// Stop bundles by chunks
//
for (Deployer.RegionDeployment regionDeployment : deployment.regions.values()) {
toStop.addAll(regionDeployment.toUpdate.keySet());
toStop.addAll(regionDeployment.toDelete);
}
removeFragmentsAndBundlesInState(toStop, UNINSTALLED | RESOLVED | STOPPING);
if (!toStop.isEmpty()) {
print("Stopping bundles:", verbose);
while (!toStop.isEmpty()) {
List<Bundle> bs = getBundlesToStop(toStop);
for (Bundle bundle : bs) {
print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
// If the bundle start level will be changed, stop it persistently to
// avoid a restart when the start level is actually changed
callback.stopBundle(bundle, toUpdateStartLevel.containsKey(bundle) ? 0 : STOP_TRANSIENT);
toStop.remove(bundle);
}
}
}
//
// Delete bundles
//
boolean hasToDelete = false;
for (Deployer.RegionDeployment regionDeployment : deployment.regions.values()) {
if (hasToDelete = !regionDeployment.toDelete.isEmpty()) {
break;
}
}
if (hasToDelete) {
print("Uninstalling bundles:", verbose);
for (Map.Entry<String, Deployer.RegionDeployment> entry : deployment.regions.entrySet()) {
String name = entry.getKey();
Deployer.RegionDeployment regionDeployment = entry.getValue();
for (Bundle bundle : regionDeployment.toDelete) {
print(" " + bundle.getSymbolicName() + " / " + bundle.getVersion(), verbose);
callback.uninstall(bundle);
removeFromMapSet(managedBundles, name, bundle.getBundleId());
}
}
}
//
// Update regions
//
{
// Add bundles
Map<String, Set<Long>> bundles = new HashMap<>();
add(bundles, apply(unmanagedBundles, bundleId()));
add(bundles, managedBundles);
// Compute policies
RegionDigraph computedDigraph = resolver.getFlatDigraph();
Map<String, Map<String, Map<String, Set<String>>>> policies = copy(dstate.filtersPerRegion);
// Only keep regions which still have bundles
policies.keySet().retainAll(bundles.keySet());
// Fix broken filters
for (String name : policies.keySet()) {