I'm trying to do session replication with hazelcast in grails application as given in Hazelcast docs.
Grails version: 1.2.1
Hazelcast: 2.5.1 (Opensource edition)
I'm getting com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
when login.
All the domain objects that are added to session are serialized. But org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
is from spring framework. How can i serialize classes from springframework?.
Please help on configuring properly with spring and spring security in grails app.
Log when application is started:
Running Grails application..
loading security config ...
Feb 18, 2016 9:04:11 PM com.hazelcast.config.UrlXmlConfig
INFO: Configuring Hazelcast from 'jndi:/localhost/WEB-INF/hazelcast.xml'.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Prefer IPv4 stack is true.
Feb 18, 2016 9:04:11 PM com.hazelcast.impl.AddressPicker
INFO: Picked Address[192.168.43.68]:5702, using socket ServerSocket[addr=/0.0.0.0,localport=5702], bind any local is true
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Hazelcast Community Edition 2.5.1 (20130427) starting at Address[192.168.43.68]:5702
Feb 18, 2016 9:04:12 PM com.hazelcast.system
INFO: [192.168.43.68]:5702 [dev] Copyright (C) 2008-2013 Hazelcast.com
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTING
Feb 18, 2016 9:04:12 PM com.hazelcast.impl.MulticastJoiner
INFO: [192.168.43.68]:5702 [dev] Connecting to master node: Address[192.168.43.68]:5701
Feb 18, 2016 9:04:12 PM com.hazelcast.nio.ConnectionManager
INFO: [192.168.43.68]:5702 [dev] 57981 accepted socket connection from /192.168.43.68:5701
Feb 18, 2016 9:04:18 PM com.hazelcast.cluster.ClusterManager
INFO: [192.168.43.68]:5702 [dev]
Members [2] {
Member [192.168.43.68]:5701
Member [192.168.43.68]:5702 this
}
Feb 18, 2016 9:04:19 PM com.hazelcast.impl.LifecycleServiceImpl
INFO: [192.168.43.68]:5702 [dev] Address[192.168.43.68]:5702 is STARTED
Server running. Browse to http://localhost:8090/
Once I logged in I'm getting HazelcastSerializationException
.
Stacktrace:
Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
Feb 18, 2016 9:04:27 PM com.hazelcast.impl.FactoryImpl
WARNING: [192.168.43.68]:5702 [dev] Destroying unknown instance name: a:my-sessions_HZ64E63E3B97D348738114474A17CA7CCE
[/].[default][21:04:27,561][http-8090-4] Servlet.service() for servlet default threw exception
com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
at com.hazelcast.nio.AbstractSerializer.toByteArray(AbstractSerializer.java:139)
at com.hazelcast.nio.Serializer.writeObject(Serializer.java:56)
...
Caused by: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
organization.ErrorController[21:04:27,754][http-8090-4] Exception in Controller; Cause=java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, Message=org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver, forwardURI=/j_spring_security_check
org.codehaus.groovy.grails.web.errors.GrailsWrappedRuntimeException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at java.lang.Thread.run(Thread.java:662)
Caused by: com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver
at com.hazelcast.nio.AbstractSerializer.toByte(AbstractSerializer.java:111)
Process finished with exit code -1
User Domain Class:
class User implements Serializable {
def authenticateService
//domain properties
boolean isAccessingOwnProfile(){
User user = authenticateService.userDomain()
if(user?.id?.toString()?.equalsIgnoreCase(id?.toString())){
return true
}else {
return false
}
}
}
With this i got
com.hazelcast.nio.HazelcastSerializationException: java.io.NotSerializableException: org.grails.plugins.springsecurity.service.AuthenticateService
So i did a quick fix by creating AuthenticateService as below
package com.example
class AuthenticateService extends org.grails.plugins.springsecurity.service.AuthenticateService implements Serializable {
}
after this i'm getting same exception in QualifierAnnotationAutowireCandidateResolver class
Config files:
/src/templates/war/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>hazelcast-filter</filter-name>
<filter-class>com.hazelcast.web.WebFilter</filter-class>
<init-param>
<param-name>map-name</param-name>
<param-value>my-sessions</param-value>
</init-param>
<init-param>
<param-name>config-location</param-name>
<param-value>/WEB-INF/hazelcast.xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hazelcast-filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>com.hazelcast.web.SessionListener</listener-class>
</listener>
<display-name>/@grails.project.key@</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>@grails.project.key@</param-value>
</context-param>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter</filter-class>
</filter>
<filter>
<filter-name>charEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>characterEncodingFilter</param-value>
</init-param>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>charEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.codehaus.groovy.grails.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
</listener>
<!-- Grails dispatcher servlet -->
<servlet>
<servlet-name>grails</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- The Groovy Server Pages servlet -->
<servlet>
<servlet-name>gsp</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gsp</servlet-name>
<url-pattern>*.gsp</url-pattern>
</servlet-mapping>
<welcome-file-list>
<!--
The order of the welcome pages is important. JBoss deployment will
break if index.gsp is first in the list.
-->
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.gsp</welcome-file>
</welcome-file-list>
<jsp-config>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
<taglib-location>/WEB-INF/tld/c.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://java.sun.com/jsp/jstl/fmt</taglib-uri>
<taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://www.springframework.org/tags</taglib-uri>
<taglib-location>/WEB-INF/tld/spring.tld</taglib-location>
</taglib>
<taglib>
<taglib-uri>http://grails.codehaus.org/tags</taglib-uri>
<taglib-location>/WEB-INF/tld/grails.tld</taglib-location>
</taglib>
</jsp-config>
</web-app>
/WEB-INF/hazelcast.xml
<?xml version="1.0" encoding="UTF-8"?>
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-2.5.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<group>
<name>dev</name>
<password>dev-pass</password>
</group>
<network>
<port auto-increment="true">5701</port>
<join>
<multicast enabled="true">
<multicast-group>224.2.2.3</multicast-group>
<multicast-port>54327</multicast-port>
</multicast>
<tcp-ip enabled="false">
<interface>127.0.0.1</interface>
</tcp-ip>
<aws enabled="false">
<access-key>my-access-key</access-key>
<secret-key>my-secret-key</secret-key>
<!--optional, default is us-east-1 -->
<region>us-west-1</region>
<!-- optional, only instances belonging to this group will be discovered, default will try all running instances -->
<security-group-name>hazelcast-sg</security-group-name>
<tag-key>type</tag-key>
<tag-value>hz-nodes</tag-value>
</aws>
</join>
<interfaces enabled="false">
<interface>10.10.1.*</interface>
</interfaces>
<ssl enabled="false" />
<socket-interceptor enabled="false" />
<symmetric-encryption enabled="false">
<algorithm>PBEWithMD5AndDES</algorithm>
<!-- salt value to use when generating the secret key -->
<salt>thesalt</salt>
<!-- pass phrase to use when generating the secret key -->
<password>thepass</password>
<!-- iteration count to use when generating the secret key -->
<iteration-count>19</iteration-count>
</symmetric-encryption>
<asymmetric-encryption enabled="false">
<!-- encryption algorithm -->
<algorithm>RSA/NONE/PKCS1PADDING</algorithm>
<!-- private key password -->
<keyPassword>thekeypass</keyPassword>
<!-- private key alias -->
<keyAlias>local</keyAlias>
<!-- key store type -->
<storeType>JKS</storeType>
<!-- key store password -->
<storePassword>thestorepass</storePassword>
<!-- path to the key store -->
<storePath>keystore</storePath>
</asymmetric-encryption>
</network>
<partition-group enabled="false"/>
<management-center enabled="false" update-interval="3" >http://localhost:9999</management-center>
<executor-service>
<core-pool-size>16</core-pool-size>
<max-pool-size>64</max-pool-size>
<keep-alive-seconds>60</keep-alive-seconds>
</executor-service>
<queue name="default">
<max-size-per-jvm>0</max-size-per-jvm>
<backing-map-ref>default</backing-map-ref>
</queue>
<map name="default">
<backup-count>1</backup-count>
<time-to-live-seconds>0</time-to-live-seconds>
<max-idle-seconds>0</max-idle-seconds>
<eviction-policy>NONE</eviction-policy>
<max-size policy="cluster_wide_map_size">0</max-size>
<eviction-percentage>25</eviction-percentage>
<merge-policy>hz.ADD_NEW_ENTRY</merge-policy>
</map>
</hazelcast>
The exception is because of injecting service in domain class that implements Serializable interface.
I removed service injection in Domain class and tried logged in. User domain class after removing dependency injection
and also removed custom AuthenticateService, that implements Serializable.
Now i can login to 1 instance and the session was replicated remaining instances.