You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2022/12/13 23:10:01 UTC
[brooklyn-server] branch master updated: fixing osgi loading issue where osgi lets resources come from other bundles than oneself
This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
The following commit(s) were added to refs/heads/master by this push:
new 931a6adf38 fixing osgi loading issue where osgi lets resources come from other bundles than oneself
931a6adf38 is described below
commit 931a6adf38881ab7cb1d2e7065c7f09f3dcf0b48
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Tue Dec 13 21:55:05 2022 +0000
fixing osgi loading issue where osgi lets resources come from other bundles than oneself
if package imports include its own packages and there are eg bundle v 1-A and 1-B
always prefer local resources. (might not do that for classes, but the main issue was during bom processing.)
also be lenient if such a problem does occur, but there are no types affected, warn rather than throw.
---
.../catalog/internal/BasicBrooklynCatalog.java | 14 ++--
.../catalog/internal/CatalogInitialization.java | 7 +-
.../apache/brooklyn/core/mgmt/ha/OsgiManager.java | 15 +++-
.../BrooklynMementoPersisterToObjectStore.java | 37 ++++++++--
.../brooklyn/core/mgmt/rebind/RebindIteration.java | 11 +++
.../jackson/BrooklynJacksonSerializationUtils.java | 3 +-
.../brooklyn/core/typereg/BundleUpgradeParser.java | 80 +++++++++++++---------
.../core/typereg/BundleUpgradeParserTest.java | 46 +++++++++++++
.../brooklyn/util/core/ClassLoaderUtilsTest.java | 9 ++-
.../brooklyn/rest/resources/ServerResource.java | 8 ++-
10 files changed, 175 insertions(+), 55 deletions(-)
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index f28f819b64..4be8e65385 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -681,7 +681,6 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
// brooklyn.libraries we treat specially, to append the list, with the child's list preferred in classloading order
// `libraries` is supported in some places as a legacy syntax; it should always be `brooklyn.libraries` for new apps
- // TODO in 0.8.0 require brooklyn.libraries, don't allow "libraries" on its own
List<?> librariesAddedHereNames = MutableList.copyOf(getFirstAs(itemMetadataWithoutItemDef, List.class, "brooklyn.libraries", "libraries").orNull());
Collection<CatalogBundle> librariesAddedHereBundles = CatalogItemDtoAbstract.parseLibraries(librariesAddedHereNames);
@@ -745,6 +744,12 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
String id = getFirstAs(catalogMetadata, String.class, "id").orNull();
String version = getFirstAs(catalogMetadata, String.class, "version").orNull();
+ if (log.isTraceEnabled()) log.trace("Installing "+id+":"+version);
+ if (parentMetadata.containsKey("version") && !Objects.equal(parentMetadata.get("version"), version))
+ log.warn("Bundle "+containingBundle+" declares version "+version+" for items overriding broader version "+parentMetadata.get("version"));
+ else if (!parentMetadata.containsKey("version") && containingBundle!=null && version!=null && !Objects.equal(new VersionedName("x", version).getOsgiVersionString(), containingBundle.getVersionedName().getOsgiVersionString()))
+ log.warn("Bundle "+containingBundle+" declares items at different version "+version);
+
String symbolicName = getFirstAs(catalogMetadata, String.class, "symbolicName").orNull();
String displayName = getFirstAs(catalogMetadata, String.class, "displayName").orNull();
String name = getFirstAs(catalogMetadata, String.class, "name").orNull();
@@ -1154,9 +1159,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
private void collectUrlReferencedCatalogItems(String url, ManagedBundle containingBundle, List<CatalogItemDtoAbstract<?, ?>> resultLegacyFormat, Map<RegisteredType, RegisteredType> resultNewFormat, boolean requireValidation, Map<Object, Object> parentMeta, int depth, boolean force, Boolean throwOnError) {
+ log.debug("Catalog load, loading referenced BOM at "+url+" as part of "+(containingBundle==null ? "non-bundled load" : containingBundle.getVersionedName())+" ("+(resultNewFormat!=null ? resultNewFormat.size() : resultLegacyFormat!=null ? resultLegacyFormat.size() : "(unknown)")+" items before load)");
BrooklynClassLoadingContext loader = getClassLoadingContext("catalog url reference loader", parentMeta, null);
String yaml;
- log.debug("Catalog load, loading referenced BOM at "+url+" as part of "+(containingBundle==null ? "non-bundled load" : containingBundle.getVersionedName())+" ("+(resultNewFormat!=null ? resultNewFormat.size() : resultLegacyFormat!=null ? resultLegacyFormat.size() : "(unknown)")+" items before load)");
if (url.startsWith("http")) {
// give greater visibility to these
log.info("Loading external referenced BOM at "+url+" as part of "+(containingBundle==null ? "non-bundled load" : containingBundle.getVersionedName()));
@@ -1168,6 +1173,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
throw new IllegalStateException("Remote catalog url " + url + " in "+(containingBundle==null ? "non-bundled load" : containingBundle.getVersionedName())+" can't be fetched.", e);
}
try {
+ if (log.isTraceEnabled()) log.trace("Loaded yaml for "+containingBundle+" from "+url+":\n"+yaml);
collectCatalogItemsFromCatalogBomRoot("BOM expected at "+url, yaml, containingBundle, resultLegacyFormat, resultNewFormat, requireValidation, parentMeta, depth, force, throwOnError);
} catch (Exception e) {
Exceptions.propagateAnnotated("Error loading "+url+" as part of "+(containingBundle==null ? "non-bundled load" : containingBundle.getVersionedName()), e);
@@ -1393,7 +1399,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
}
// couldn't resolve it with the plan transformers; retry with legacy "spec" transformers.
- // TODO this legacy path is still needed where an entity is declared with nice abbreviated 'type: xxx' syntax, not the full-camp 'services: [ { type: xxx } ]' syntax.
+ // TODO this legacy path is still needed where an entity is declared with nice abbreviated 'type: ...' syntax, not the full-camp 'services: [ { type: ... } ]' syntax.
// would be nice to move that logic internally to CAMP and see if we can remove this altogether.
// (see org.apache.brooklyn.camp.brooklyn.spi.creation.CampResolver.createEntitySpecFromServicesBlock )
if (format == null) {
@@ -1567,7 +1573,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
String candidateYamlWithKeyAdded = null;
boolean legacyModeForOriginalBlueprint;
if (optionalKeyForModifyingYaml!=null) {
- /* often when added to a catalog we simply say "type: xxx" for the definition;
+ /* often when added to a catalog we simply say "type: ..." for the definition;
* the services: parent key at root (or brooklyn.policies, etc) needed by the camp parser
* are implicit, and added here */
if (item.containsKey(optionalKeyForModifyingYaml)) {
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
index 14f95d2bab..99597d5737 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
@@ -292,8 +292,7 @@ public class CatalogInitialization implements ManagementContextInjectable {
} else {
final OsgiManager osgiManager = maybesOsgiManager.get();
final BundleContext bundleContext = osgiManager.getFramework().getBundleContext();
- final CatalogUpgrades catalogUpgrades =
- catalogUpgradeScanner.scan(osgiManager, bundleContext, rebindLogger);
+ final CatalogUpgrades catalogUpgrades = catalogUpgradeScanner.scan(osgiManager, bundleContext, rebindLogger);
CatalogUpgrades.storeInManagementContext(catalogUpgrades, managementContext);
}
@@ -563,8 +562,8 @@ public class CatalogInitialization implements ManagementContextInjectable {
}
});
bundlesToRemove.forEach(b -> {
- ManagedBundle mb = getManagementContext().getOsgiManager().get().getManagedBundle(b.getVersionedName());
- if (b.getBundle().getState() >= Bundle.INSTALLED && b.getBundle().getState() < Bundle.STARTING) {
+ log.debug("Considering to uninstall: "+b+" / "+getManagementContext().getOsgiManager().get().getManagedBundle(b.getVersionedName()));
+ if (b.getBundle()!=null && b.getBundle().getState() >= Bundle.INSTALLED && b.getBundle().getState() < Bundle.STARTING) {
// we installed it, catalog did not start it, so let's uninstall it
OsgiBundleInstallationResult result = getManagementContext().getOsgiManager().get().uninstallUploadedBundle(b.getMetadata());
log.debug("Result of uninstalling "+b+" due to catalog upgrade metadata instructions: "+result);
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
index edd4349396..7482dd88a3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
@@ -807,7 +807,12 @@ public class OsgiManager {
try {
Maybe<Bundle> bundle = findBundle(osgiBundle);
if (bundle.isPresent()) {
- URL result = bundle.get().getResource(name);
+ URL result;
+ if (!name.endsWith(".class")) {
+ result = bundle.get().getEntry(name); // see comments at getResources
+ if (result != null) return result;
+ }
+ result = bundle.get().getResource(name);
if (result!=null) return result;
}
} catch (Exception e) {
@@ -821,13 +826,19 @@ public class OsgiManager {
* @return URL's to all resources matching the given name (using {@link Bundle#getResources(String)} in the referenced osgi bundles.
*/
public Iterable<URL> getResources(String name, Iterable<? extends OsgiBundleWithUrl> osgiBundles) {
- Set<URL> resources = Sets.newLinkedHashSet();
+ MutableSet<URL> resources = MutableSet.of();
for (OsgiBundleWithUrl catalogBundle : osgiBundles) {
try {
Maybe<Bundle> bundle = findBundle(catalogBundle);
if (bundle.isPresent()) {
+ boolean isClass = name.endsWith(".class");
+ if (!isClass) resources.putIfNotNull(bundle.get().getEntry(name)); // files in the same bundle are not always preferred
+ // (observed with a bundle at 1.0.0-2022 being installed when 1.0.0-SNAPSHOT is installed, the former includes its packages in import-package,
+ // with the result that it returns the contents of the 1.0.0-SNAPSHOT bundle instead of its own contents, which is not what we want);
+ // see also in BundleUpgradeParser
Enumeration<URL> result = bundle.get().getResources(name);
resources.addAll(Collections.list(result));
+ if (isClass) resources.putIfNotNull(bundle.get().getEntry(name)); //class resources, for consistency and to match loadClass, we prefer osgi behaviour
}
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
index 7593b1082a..82fd7c5cda 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
@@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.xml.xpath.XPathConstants;
@@ -364,19 +365,34 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
} else {
String xmlId = (String) XmlUtil.xpathHandlingIllegalChars(contents, "/" + type.toCamelCase() + "/id");
+ String xmlUrl = getXmlValue(contents, "/" + type.toCamelCase() + "/url").orNull();
+ String xmlJavaType = getXmlValue(contents, "/" + type.toCamelCase() + "/type").orNull();
+ String summary = MutableList.<String>of(contentsSubpath, type.toCamelCase()).appendIfNotNull(xmlId).appendIfNotNull(xmlUrl).appendIfNotNull(xmlJavaType).stream().collect(Collectors.joining(" / "));
+
String safeXmlId = Strings.makeValidFilename(xmlId);
- if (!Objects.equal(id, safeXmlId))
- LOG.warn("ID mismatch on " + type.toCamelCase() + ", " + id + " from path, " + safeXmlId + " from xml");
+ if (!Objects.equal(id, safeXmlId)) {
+ LOG.warn("ID mismatch on " + summary + ": xml id is " + safeXmlId);
+ }
+ boolean include;
if (type == BrooklynObjectType.MANAGED_BUNDLE) {
- // TODO could R/W to cache space directly, rather than memory copy then extra file copy
+ // could R/W to cache space directly, rather than memory copy then extra file copy
byte[] jarData = readBytes(contentsSubpath + ".jar");
- if (jarData == null) {
- throw new IllegalStateException("No bundle data for " + contentsSubpath);
+ include = (jarData != null);
+ if (!include) {
+ LOG.warn("No JAR data for "+summary+"; assuming deprecated and not meant to be installed, so ignoring");
+ //throw new IllegalStateException("No bundle data for " + contentsSubpath+".jar; contents:\n"+contents);
+ } else {
+ LOG.debug("Including bundle "+summary+", with jar data size "+jarData.length);
+ builder.bundleJar(id, ByteSource.wrap(jarData));
}
- builder.bundleJar(id, ByteSource.wrap(jarData));
+ } else {
+ LOG.debug("Including item "+summary);
+ include = true;
+ }
+ if (include) {
+ builder.put(type, xmlId, contents);
}
- builder.put(type, xmlId, contents);
}
}
};
@@ -399,6 +415,13 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
return result;
}
+ private Maybe<String> getXmlValue(String xml, String path) {
+ try {
+ return Maybe.ofDisallowingNull((String) XmlUtil.xpathHandlingIllegalChars(xml, path));
+ } catch (Exception e) { Exceptions.propagateIfFatal(e); /* otherwise ignore if no url */ }
+ return Maybe.absent();
+ }
+
private static class XPathHelper {
private String contents;
private String prefix;
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index 03d8018707..a7675af57d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
@@ -360,6 +360,14 @@ public abstract class RebindIteration {
}
});
}
+
+ @Override
+ public String toString() {
+ return "InstallableManagedBundleImpl{" +
+ "memento=" + memento +
+ ", managedBundle=" + managedBundle +
+ '}';
+ }
}
protected void installBundlesAndRebuildCatalog() {
@@ -1137,6 +1145,9 @@ public abstract class RebindIteration {
logRebindingWarn("Needed rebind catalog to resolve search path entry " + searchItemId + " (now " + fixedSearchItemId + ") for " + bType.getSimpleName().toLowerCase() + " " + contextSuchAsId +
", persistence should remove this in future but future versions will not support this and definitions should be fixed");
} else {
+ // could do some magic if there is a peer with the same version use it, might be handy for snapshots especially
+ // (snapshots upgrading bundle version "*" drop the qualifier so don't replace peers;
+ // but as soon as you have a larger datestamp, it will replace the previous ones)
logRebindingWarn("Could not find search path entry " + searchItemId + " for " + bType.getSimpleName().toLowerCase() + " " + contextSuchAsId + ", ignoring");
}
}
diff --git a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynJacksonSerializationUtils.java b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynJacksonSerializationUtils.java
index ad5f0efe97..240e914b64 100644
--- a/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynJacksonSerializationUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/resolve/jackson/BrooklynJacksonSerializationUtils.java
@@ -252,7 +252,8 @@ public class BrooklynJacksonSerializationUtils {
Object type = rm.get("type");
if (type instanceof String && ((String)type).startsWith("org.apache.brooklyn.camp.brooklyn.spi.dsl.")) {
// should always have a brooklyn:literal on outermost type, so that even with json pass through (used for steps etc) dsl gets preserved across convertDeeply
- log.warn("Failed to deserialize "+result+" as DSL; will treat as map");
+ // apart from nested DSL expressions; and unf there is no easy way to tell here, so we just log debug either way
+ log.debug("Data "+result+" looks like DSL but has no literal entry; probably it is a nested DSL expression, or otherwise it may be left as a map after deserialization");
}
}
}
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
index 89a77258e3..ea685c0704 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
@@ -18,26 +18,19 @@
*/
package org.apache.brooklyn.core.typereg;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Dictionary;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.stream.Collectors;
-
-import javax.annotation.Nonnull;
-
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Supplier;
+import com.google.common.collect.*;
import org.apache.brooklyn.api.catalog.CatalogItem;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.api.typereg.RegisteredType;
import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.osgi.Osgis;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.osgi.VersionedName;
@@ -50,16 +43,11 @@ import org.osgi.framework.VersionRange;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
+import javax.annotation.Nonnull;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static com.google.common.base.Preconditions.checkNotNull;
/**
* Internal class for parsing bundle manifests to extract their upgrade instructions.
@@ -551,16 +539,16 @@ public class BundleUpgradeParser {
// TODO Add support for the other options described in the proposal:
// https://docs.google.com/document/d/1Lm47Kx-cXPLe8BO34-qrL3ZMPosuUHJILYVQUswEH6Y/edit#
// section "Bundle Upgrade Metadata"
-
+
Dictionary<String, String> headers = bundle.getHeaders();
String upgradesForBundlesHeader = headers.get(MANIFEST_HEADER_UPGRADE_FOR_BUNDLES);
- Multimap<VersionedName,VersionRangedName> upgradesForBundles = parseUpgradeForBundlesHeader(upgradesForBundlesHeader, bundle);
+ Multimap<VersionedName, VersionRangedName> upgradesForBundles = parseUpgradeForBundlesHeader(upgradesForBundlesHeader, bundle);
return CatalogUpgrades.builder()
.removedLegacyItems(parseForceRemoveLegacyItemsHeader(headers.get(MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS), bundle, typeSupplier))
.removedBundles(parseForceRemoveBundlesHeader(headers.get(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES), bundle))
.upgradeBundles(upgradesForBundles)
- .upgradeTypes(parseUpgradeForTypesHeader(headers.get(MANIFEST_HEADER_UPGRADE_FOR_TYPES), bundle, typeSupplier,
- upgradesForBundlesHeader==null ? null : upgradesForBundles))
+ .upgradeTypes(parseUpgradeForTypesHeader(headers.get(MANIFEST_HEADER_UPGRADE_FOR_TYPES), bundle, typeSupplier,
+ upgradesForBundlesHeader == null ? null : upgradesForBundles))
.build();
}
@@ -582,6 +570,7 @@ public class BundleUpgradeParser {
// default target is this bundle
(i) -> { return new VersionedName(bundle); });
}
+
private static Multimap<VersionedName, VersionRangedName> parseUpgradeForTypesHeader(String input, Bundle bundle, Supplier<? extends Iterable<? extends RegisteredType>> typeSupplier, Multimap<VersionedName, VersionRangedName> upgradesForBundles) {
List<String> sourceVersions = null;
if (upgradesForBundles!=null) {
@@ -609,8 +598,35 @@ public class BundleUpgradeParser {
(i) -> {
VersionedName targetTypeAtBundleVersion = new VersionedName(i.getSymbolicName(), bundle.getVersion());
if (!typeSupplierNames.contains(VersionedName.toOsgiVersionedName(targetTypeAtBundleVersion))) {
- throw new IllegalStateException("Bundle manifest for "+bundle+" declares it upgrades "+i+" "
- + "but does not declare an explicit target and does not contain inferred target "+targetTypeAtBundleVersion);
+ String error = "Bundle manifest for " + bundle + " declares it upgrades " + i + " "
+ + "but does not declare an explicit target and does not contain inferred target " + targetTypeAtBundleVersion;
+
+ ManagementContext mgmt = Osgis.getManagementContext();
+ if (mgmt!=null) {
+ List<RegisteredType> matches = MutableList.copyOf(mgmt.getTypeRegistry().getMatching(rt -> Objects.equal(i.getSymbolicName(), rt.getSymbolicName()) && i.getOsgiVersionRange().includes(rt.getVersionedName().getOsgiVersion())));
+ if (matches.isEmpty()) {
+ /* can happen if a bundle imports its own packages and references a path/to/bom which is available in the bundle it imports, eg v 1.0.0-A and 1.0.0-B;
+ * curiously osgi will sometimes read the resource from the imported bundle (see OsgiManager.getResources)
+ */
+ log.debug(error+"; however there are no such types to be upgrades so ignoring");
+ return null;
+ }
+ CatalogUpgrades previousUpgrades = CatalogUpgrades.getFromManagementContext(mgmt);
+ if (!previousUpgrades.getUpgradesForBundle(new VersionedName(bundle)).isEmpty()) {
+ log.debug(error+"; however this bundle has applicable upgrade instructions so ignoring");
+ return null;
+ }
+ matches = matches.stream().filter(rt -> previousUpgrades.getUpgradesForType(rt.getVersionedName()).isEmpty()).collect(Collectors.toList());
+ if (matches.isEmpty()) {
+ log.debug(error+"; however all such types have other upgrade instructions so ignoring");
+ return null;
+ }
+
+ log.debug(error+"; types we cannot upgrade: "+matches+"; types available here: "+typeSupplierNames);
+ } else {
+ log.debug(error + "; details: mgmt context unavailable, osgi target '" + VersionedName.toOsgiVersionedName(targetTypeAtBundleVersion) + "', supplier names: " + typeSupplierNames);
+ }
+ throw new IllegalStateException(error);
}
return targetTypeAtBundleVersion;
});
@@ -766,7 +782,9 @@ public class BundleUpgradeParser {
} else {
throw new IllegalArgumentException("Wildcard entry key must be of the form \"*\" or \"*:range\"");
}
- result.put(target, source);
+ if (target!=null) {
+ result.put(target, source);
+ }
}
}
}
diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
index 1b437b397b..91c2226f7e 100644
--- a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
@@ -89,6 +89,52 @@ public class BundleUpgradeParserTest {
assertFalse(from1.includes(Version.valueOf("0.0.0.SNAPSHOT")));
assertFalse(from1.includes(Version.valueOf("0.1.0.SNAPSHOT")));
}
+
+ @Test
+ public void testVersionRangesWithTimestampsAndSnapshots() throws Exception {
+ VersionRange from0lessThan1 = VersionRangedName.fromString("foo:[0,1.0.0.2022)", false).getOsgiVersionRange();
+ assertTrue(from0lessThan1.includes(Version.valueOf("0.1.0.SNAPSHOT")));
+ assertTrue(from0lessThan1.includes(Version.valueOf("1.0.0")));
+ assertTrue(from0lessThan1.includes(Version.valueOf("1.0.0.2021")));
+ assertTrue(from0lessThan1.includes(Version.valueOf(BrooklynVersionSyntax.toValidOsgiVersion("1.0.0-2021"))));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf(BrooklynVersionSyntax.toValidOsgiVersion("1.0.0-2023"))));
+
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.2022")));
+ assertFalse(from0lessThan1.includes(Version.valueOf(BrooklynVersionSyntax.toValidOsgiVersion("1.0.0-2022"))));
+
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.SNAPSHOT")));
+ assertFalse(from0lessThan1.includes(Version.valueOf(BrooklynVersionSyntax.toValidOsgiVersion("1.0.0-SNAPSHOT"))));
+
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.SNAPSHOT")));
+
+ // note however when given * for a snapshot we strip the snapshot qualifier, and so only match up to 1.0.0)
+ from0lessThan1 = VersionRangedName.fromString("foo:[0,1.0.0.SNAPSHOT)", false).getOsgiVersionRange();
+ assertTrue(from0lessThan1.includes(Version.valueOf("0.1.0.SNAPSHOT")));
+ assertTrue(from0lessThan1.includes(Version.valueOf("1.0.0")));
+ assertTrue(from0lessThan1.includes(Version.valueOf("1.0.0.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.SNAPSHOT")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.SNAPSHOT")));
+
+ from0lessThan1 = VersionRangedName.fromString("foo:[0,1.0.0)", false).getOsgiVersionRange();
+ assertTrue(from0lessThan1.includes(Version.valueOf("0.1.0.SNAPSHOT")));
+
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.0.SNAPSHOT")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.2023")));
+ assertFalse(from0lessThan1.includes(Version.valueOf("1.0.1.SNAPSHOT")));
+
+ VersionRange from1lessThan101 = VersionRangedName.fromString("foo:(1.0.0,1.0.1)", false).getOsgiVersionRange();
+ assertFalse(from1lessThan101.includes(Version.valueOf("0.1.0.SNAPSHOT")));
+ assertFalse(from1lessThan101.includes(Version.valueOf("1.0.0")));
+ assertTrue(from1lessThan101.includes(Version.valueOf("1.0.0.2023")));
+ assertTrue(from1lessThan101.includes(Version.valueOf("1.0.0.SNAPSHOT")));
+ assertFalse(from1lessThan101.includes(Version.valueOf("1.0.1")));
+ assertFalse(from1lessThan101.includes(Version.valueOf("1.0.1.2023")));
+ }
@Test
public void testParseSingleQuotedVal() throws Exception {
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
index db90666722..b868c46764 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/ClassLoaderUtilsTest.java
@@ -144,7 +144,7 @@ public class ClassLoaderUtilsTest {
BundledName resource = new BundledName(classname).toResource();
BundledName bn = new BundledName(resource.bundle, resource.version, "/" + resource.name);
- Asserts.assertSize(cluEntity.getResources(bn.toString()), 1);
+ Asserts.assertSize(cluEntity.getResources(bn.toString()), 2); // should no longer mask the other available option
}
@@ -354,12 +354,15 @@ public class ClassLoaderUtilsTest {
String bundledResource = resource.toString();
URL resourceUrl = cl.getResource(resource.name);
assertEquals(clu.getResource(bundledResource), resourceUrl);
- assertEquals(clu.getResources(bundledResource), ImmutableList.of(resourceUrl), "Loading with "+clu);
+ Iterable<URL> allMatches = clu.getResources(bundledResource);
+ assertEquals(allMatches.iterator().next(), resourceUrl, "Loading with "+clu);
+ // may have others, eg if the bundle provides it via multiple sources
BundledName rootResource = new BundledName(resource.bundle, resource.version, "/" + resource.name);
String rootBundledResource = rootResource.toString();
assertEquals(clu.getResource(rootBundledResource), resourceUrl);
- assertEquals(clu.getResources(rootBundledResource), ImmutableList.of(resourceUrl));
+ allMatches = clu.getResources(rootBundledResource);
+ assertEquals(allMatches.iterator().next(), resourceUrl);
}
private void assertLoadFails(String bundledClassName, ClassLoaderUtils... clua) {
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
index 7614e2c157..00c3cf029f 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
@@ -590,6 +590,8 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv
File tempZipFile = null;
String unzippedPath = null;
try {
+ log.debug("Importing persisted state via REST API, starting");
+
// create a temporary archive where persistence data supplied is written to
tempZipFile = File.createTempFile("persistence-import",null);
Files.write(tempZipFile.toPath(), persistenceData, StandardOpenOption.TRUNCATE_EXISTING);
@@ -623,15 +625,15 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv
ManagedBundleMemento bundleMemento = mementoManifest.getBundle(bundleJar.getKey());
ManagedBundle b = RebindIteration.newManagedBundle(bundleMemento);
bundles.put(b.getVersionedName(), new RebindIteration.InstallableManagedBundleImpl(bundleMemento, b));
- log.debug("Installing "+bundleMemento+" for "+b+" as part of persisted state import");
+ log.debug("Importing persisted state, preparing bundle "+b+" from "+bundleMemento);
}
CatalogInitialization.PersistedCatalogState persistedCatalogState = new CatalogInitialization.PersistedCatalogState(bundles, Collections.emptySet());
CatalogInitialization.RebindLogger rebindLogger = new CatalogInitialization.RebindLogger() {
@Override public void debug(String message, Object... args) {
- log.debug(message, args);
+ log.debug("Importing persisted state: "+message, args);
}
@Override public void info(String message, Object... args) {
- log.warn(message, args);
+ log.warn("Importing persisted state: "+message, args);
}
};
mgmtInternal().getCatalogInitialization().installPersistedBundles(persistedCatalogState, null, ((RebindManagerImpl)mgmt().getRebindManager()).newExceptionHandler(), rebindLogger);