[
https://issues.apache.org/jira/browse/BROOKLYN-453?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15927716#comment-15927716
]
ASF GitHub Bot commented on BROOKLYN-453:
-----------------------------------------
Github user neykov commented on a diff in the pull request:
https://github.com/apache/brooklyn-server/pull/598#discussion_r106369844
--- Diff:
core/src/main/java/org/apache/brooklyn/util/core/xstream/ClassRenamingMapper.java
---
@@ -22,32 +22,168 @@
import java.util.Map;
+import org.apache.brooklyn.core.mgmt.persist.OsgiClassPrefixer;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.javalang.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Supplier;
+import com.thoughtworks.xstream.mapper.CannotResolveClassException;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.MapperWrapper;
+/**
+ * An xstream mapper that handles class-renames, so we can rebind to
historic persisted state.
+ */
public class ClassRenamingMapper extends MapperWrapper {
+
+ /*
+ * TODO There is a strange relationship between this and
XmlMementoSerializer$OsgiClassnameMapper.
+ * Should these be perhaps merged?
+ *
+ * TODO For class-loading on deserialzation, should we push the
class-rename logic into
+ * org.apache.brooklyn.util.core.ClassLoaderUtils instead? Does the
xstream mapper do
+ * anything else important, beyond that class-loading responsibility?
It's registration
+ * in XmlSerializer makes it look a bit scary:
wrapMapperForAllLowLevelMentions().
+ *
+ * ---
+ * TODO This code feels overly complicated, and deserves a cleanup.
+ *
+ * The aim is to handle two use-cases in the
deserializingClassRenames.properties:
+ *
+ * 1. A very explicit rename that includes bundle prefixes (e.g. so
as to limit scope, or to support
+ * moving a class from one bundle to another).
+ *
+ * 2. Just the class-rename (e.g. `com.acme.Foo: com.acme.Bar`).
+ * This would rename "acme-bundle:com.acme.Foo" to
"acme-bundle:com.acme.Bar".
+ *
+ * However, to achieve that is fiddly for several reasons:
+ *
+ * 1. We might be passed qualified or unqualified names (e.g.
"com.acme.Foo" or "acme-bundle:com.acme.Foo"),
+ * depending how old the persisted state is, where OSGi was used
previously, and whether
+ * whitelabelled bundles were used.
+ *
+ * 2. Calling `super.realClass(name)` must return a class that has
exactly the same name as
+ * was passed in. This is because xstream will subsequently use
`Class.forName` which is
+ * fussy about that. However, if we're passed
"acme-bundle:com.acme.Foo" then we'd expect
+ * to return a class named "com.acme.Foo". The final classloading
in our
+ * `XmlMementoSerializer$OsgiClassLoader.findClass()` will handle
stripping out the bundle
+ * name, and using the right bundle.
+ *
+ * In the case where we haven't changed the name, then we can
leave it up to
+ * `XmlMementoSerializer$OsgiClassnameMapper.realClass()` to do
sort this out. But if we've
+ * done a rename, then unforutnately it's currently this class'
responsibility!
+ *
+ * That means it has to fallback to calling
classLoader.loadClass().
+ *
+ * 3. As mentioned under the use-cases, the rename could include the
full bundle name prefix,
+ * or it might just be the classname. We want to handle both, so
need to implement yet
+ * more fallback behaviour.
+ *
+ * ---
+ * TODO Wanted to pass xstream, rather than Supplier<ClassLoader>, in
constructor. However,
+ * this caused NPE because of how this is constructed from inside
+ * XmlMementoSerializer.wrapMapperForNormalUsage, called from within
an anonymous subclass of XStream!
+ */
+
public static final Logger LOG =
LoggerFactory.getLogger(ClassRenamingMapper.class);
private final Map<String, String> nameToType;
-
- public ClassRenamingMapper(Mapper wrapped, Map<String, String>
nameToType) {
+ private final Supplier<? extends ClassLoader> classLoaderSupplier;
+
+ public ClassRenamingMapper(Mapper wrapped, Map<String, String>
nameToType, Supplier<? extends ClassLoader> classLoaderSupplier) {
super(wrapped);
this.nameToType = checkNotNull(nameToType, "nameToType");
+ this.classLoaderSupplier = checkNotNull(classLoaderSupplier,
"classLoaderSupplier");
}
@Override
public Class<?> realClass(String elementName) {
+ String elementNamOrig = elementName;
--- End diff --
Typo elementNam**e**Orig
> Rebinding fails when using class-renames with bundle prefixes
> -------------------------------------------------------------
>
> Key: BROOKLYN-453
> URL: https://issues.apache.org/jira/browse/BROOKLYN-453
> Project: Brooklyn
> Issue Type: Bug
> Reporter: Aled Sage
> Priority: Blocker
>
> I have some persisted state from an older version of Brooklyn (but still
> 0.11.0-SNAPSHOT, from January). This includes a reference to
> {{org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier}}
> - note the bundle name prefix.
> In the `deserializingClassRenames.properties`, there is an entry for:
> {noformat}
> org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier :
> org.apache.brooklyn.feed.AbstractCommandFeed$CommandPollIdentifier
> {noformat}
> However, this is not used - rebind therefore fails with an error like:
> {noformat}
> 2017-03-15 18:25:26,721 WARN 120 o.a.b.c.m.p.RetryingMementoSerializer
> [ooklyn-persister] Error deserializing memento (attempt 4 of 5):
> com.thoughtworks.xstream.converters.ConversionException: Could not call
> com.google.common.collect.HashMultimap.readObject() :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> via loadClass :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> ---- Debugging information ----
> message : Could not call
> com.google.common.collect.HashMultimap.readObject()
> cause-exception :
> com.thoughtworks.xstream.mapper.CannotResolveClassException
> cause-message :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> via loadClass :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> class : com.google.common.collect.HashMultimap
> required-type : com.google.common.collect.HashMultimap
> converter-type :
> com.thoughtworks.xstream.converters.reflection.SerializableConverter
> path :
> /feed/config/polls/com.google.guava:com.google.common.collect.HashMultimap/com.google.guava:com.google.common.collect.HashMultimap/org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> line number : 24
> class[1] : java.util.LinkedHashMap
> converter-type[1] :
> org.apache.brooklyn.util.core.xstream.StringKeyMapConverter
> class[2] :
> org.apache.brooklyn.core.mgmt.rebind.dto.BasicFeedMemento
> converter-type[2] :
> com.thoughtworks.xstream.converters.reflection.ReflectionConverter
> version : 0.11.0-20170314.1743
> -------------------------------
> com.thoughtworks.xstream.converters.ConversionException: Could not call
> com.google.common.collect.HashMultimap.readObject() :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> via loadClass :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> ---- Debugging information ----
> message : Could not call
> com.google.common.collect.HashMultimap.readObject()
> cause-exception :
> com.thoughtworks.xstream.mapper.CannotResolveClassException
> cause-message :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> via loadClass :
> org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> class : com.google.common.collect.HashMultimap
> required-type : com.google.common.collect.HashMultimap
> converter-type :
> com.thoughtworks.xstream.converters.reflection.SerializableConverter
> path :
> /feed/config/polls/com.google.guava:com.google.common.collect.HashMultimap/com.google.guava:com.google.common.collect.HashMultimap/org.apache.brooklyn.core:org.apache.brooklyn.feed.ssh.SshFeed$SshPollIdentifier
> line number : 24
> class[1] : java.util.LinkedHashMap
> converter-type[1] :
> org.apache.brooklyn.util.core.xstream.StringKeyMapConverter
> class[2] :
> org.apache.brooklyn.core.mgmt.rebind.dto.BasicFeedMemento
> converter-type[2] :
> com.thoughtworks.xstream.converters.reflection.ReflectionConverter
> version : 0.11.0-20170314.1743
> -------------------------------
> {noformat}
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)