Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialization problem when doing aggregate on a map #33

Closed
bergander opened this issue Nov 22, 2017 · 7 comments
Closed

Deserialization problem when doing aggregate on a map #33

bergander opened this issue Nov 22, 2017 · 7 comments

Comments

@bergander
Copy link
Contributor

I've got a problem with deserialization when doing aggregate on a map in a P2P configuration.

map.aggregate(Supplier.fromPredicate(filter::test), Aggregations.count());

This will throw an HazelcastSerializationException caused by a ClassNotFoundException. The problem is similar to this issue: #13

The hazelcast thread doing the aggregate has a context ClassLoader with only the tomcat libraries, but it needs to have the webapp context classloader to be able to deserialize objects from the webapp. So I'm guessing the classloader in the config needs to be set to the webapp context classloader before creating the hazelcast instance (and the hazelcast threads). But currently the instance is created in the P2PLifecycleListener where the webapp context is not available. Should the instance be created in the SessionManager instead, like with the server-client case?

Or is there some other way to set the classloader in the webapp after the hazelcast instance has been created? Executing instance.getConfig().setClassLoader(...) seems to have no effect.

@bergander
Copy link
Contributor Author

One way of solving the problem would be to create the hazelcast instance in the webapp's contextInitialized(...) and then use that instance in the HazelcastSessionManger. Then Hazelcast will have the correct classloader and everything will work just fine. Just add something like this to HazelcastSessionManager.startInternal()

if (getHazelcastInstanceName() != null) {
  instance = Hazelcast.getHazelcastInstanceByName(getHazelcastInstanceName());
}

@emre-aydin
Copy link
Contributor

@bergander can you achieve what you described in your last comment by setting an instance name for your Config (possibly by setting it in your hazelcast.xml)? This line should use the existing Hazelcast instance if you define a name for your instance in your hazelcast.xml. This way, you could start your own instance first, and SessionManager would use that. Haven't tried it, but seems like a plausible solution for the time being.

As a proper fix, we can start the Hazelcast instance later in the process as you suggested and change its classloader. I didn't look into this yet, it might not be possible.

@bergander
Copy link
Contributor Author

bergander commented Jan 8, 2018

If I try that I get this log entry from Hazelcast:
com.hazelcast.instance.NodeExtensionFactory.null DefaultNodeExtension class has been loaded by two different class-loaders. Are you running Hazelcast in an OSGi environment? If so, set the bundle class-loader in the Config using the setClassloader() method

And the following exception, which seems to be a bug in Hazelcast?:

java.lang.NoSuchMethodException: com.hazelcast.instance.DefaultNodeExtension.<init>(com.hazelcast.instance.Node)
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at com.hazelcast.instance.NodeExtensionFactory.create(NodeExtensionFactory.java:49)

So I still have a classloader issue with that solution. I can only get around the problem by using getHazelcastInstanceByName(...) instead in the Hazelcast Tomcat SessionManager.

If I initialize Hazelcast in my webapp and then patch HazelcastSessionManager with the following code then all my problems goes away (and then there's no need for the listener in server.xml):

42a43,44
> 	
> 	private String hazelcastInstanceName;
82a85,86
> 		} else if (getHazelcastInstanceName() != null) {
> 			instance = Hazelcast.getHazelcastInstanceByName(getHazelcastInstanceName());
325a330,337
> 	public String getHazelcastInstanceName() {
>         return hazelcastInstanceName;
>     }
> 
>     public void setHazelcastInstanceName(String hazelcastInstanceName) {
>         this.hazelcastInstanceName = hazelcastInstanceName;
>     }
> 	

@emre-aydin
Copy link
Contributor

@bergander if you send a pull request for your patch, we can review and merge it if there's no problems with it.

@bergander
Copy link
Contributor Author

Pull request created: #37

@emre-aydin
Copy link
Contributor

Thanks for the PR @bergander, I will review it as soon as possible.

@mesutcelik
Copy link

fixed by #37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants