Reputation: 4213
I am developing an grails application(server) to track the mobile device which are in the Wi-Fi network. The users will send a request to the webservice which is running on grails applicion(server) along with Mobileid and Wi-Fi IP address.
In my grails application i am staring multiple external java threads, each thread will be pinging the Wi-Fi IP address of each mobile device(one thread per one device to track). If any device IP is not reachable then i will update mobile status as "Disconnected" in the database from the external thread. Here only i am facing the issue, if more than one device is in not reachable then multiple threads are going to update the status of each device in the same table using domain.withTransaction method while i am getting the following exception
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.NullPointerException at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:596) at org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager.super$3$doBegin(GrailsHibernateTransactionManager.groovy) at sun.reflect.GeneratedMethodAccessor492.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:88) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058) at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1070) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:127)
My Code:
Pinging device in thread
try {
final InetAddress inet = InetAddress.getByName(ipAddress);
boolean status = inet.isReachable(5000);
if (status) {
pool.run(MobileDeviceTracker.deviceMap.get(mobileId));
} else {
// Calling service to update the status of device as disconnected
getUserMobileService().deviceDisconnected(mobileId, ipAddress);
}
} catch (Exception e) { }
Updating Status in Database
class DisconnectionService implements UserMobileServiceInt{
static transactional = true
def void deviceDisconnected(String mobileId, String wifiIp){
try{
def mobile = Mobile.findByMobileId(mobileId)
def userMobile = UserMobile.findByMobileAndWifiIp(mobile, wifiIp)
userMobile.withTransaction {tx ->
userMobile.action = Constants.MOBILE_STATUS_DISCONNECTED
userMobile.alarmStatus = Constants.ALARM_STATUS_TURNED_ON
userMobile.modifiedDate = new Date()
userMobile.save(flush: true)
}
}catch(Exception e){
e.printStackTrace()
}
I am trying last 4 days but i am not able solve this.
Upvotes: 0
Views: 4642
Reputation: 1655
No need for me to spread mis-information and bad ways of doing things. Both the answers from Burt and Graeme will work. I just wrote a quick test app to prove this.
Upvotes: 0
Reputation: 7985
Rather than using the verbose binding code suggested by Tiggerizzy. It is better to use the built in withNewSession method on domain classes:
Mobile.withNewSession {
// your code here
}
Upvotes: 1
Reputation: 75671
Move the reads into the transaction, otherwise they'll be in a disconnected session and not the one that the transaction creates. Also, it's best to call static methods on the class, not an instance (in both Groovy and Java):
void deviceDisconnected(String mobileId, String wifiIp){
try {
UserMobile.withTransaction { tx ->
def mobile = Mobile.findByMobileId(mobileId)
def userMobile = UserMobile.findByMobileAndWifiIp(mobile, wifiIp)
userMobile.action = Constants.MOBILE_STATUS_DISCONNECTED
userMobile.alarmStatus = Constants.ALARM_STATUS_TURNED_ON
userMobile.modifiedDate = new Date()
userMobile.save(flush: true)
}
}
catch(e) {
e.printStackTrace()
}
}
Upvotes: 3