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 <[email protected]>
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);