[ 
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)

Reply via email to