Here's a solution someone posted: http://jsfiddle.net/rur_d/tNZAm/
Some say it's bad idea to have your controllers being aware of classes. Well it's a solution that works.
My online tech scrapbook where I keep my notes in case I need to look them up later
Saturday, July 21, 2012
Document Ready Event When Using AngularJS With JQuery
When you are making a page out of multiple partials/fragments in AngularJS, the document ready event for JQuery seems to fire before the page is fully assembled.
The correct way to do something when the page is fully loaded in AngularJS is by using the '$viewContentLoaded' event listener, by putting the following code into your controller.
Reference: http://www.aleaiactaest.ch/angular-js-and-dom-readyness-for-jquery/
The correct way to do something when the page is fully loaded in AngularJS is by using the '$viewContentLoaded' event listener, by putting the following code into your controller.
$scope.$on('$viewContentLoaded', function(){ // do something }); |
Reference: http://www.aleaiactaest.ch/angular-js-and-dom-readyness-for-jquery/
AngularJS: Calling a Javascript Function in the Controller
This is done by using "ng-click".
Example assuming you already created a function in the controller called "doSomething":
Example assuming you already created a function in the controller called "doSomething":
<a href ng-click="doSomething()">Do It</a> |
Friday, July 20, 2012
Jersey Exception Handling
Jersey offers centralized Exception handling with "ExceptionMappers". This means you can allow Exceptions to be thrown up to the framework and then you can define how to handle them. It also means you are able to "catch" and handle exceptions that occur before and after the code that you write is being run.
Let's say you want to handle "MyWebServiceException", you can create an ExceptionMapper "MyWebServiceExceptionMapper" like this:
In order for this to be registered with Jersey, you'll need to put it in a package that's being scanned by Jersey to be resources or providers, so in the web.xml, have something like this:
In this example, I separated the packages for resources and providers, providing 2 packages to be scanned.
To handle each exception differently, just create as many ExceptionMapper classes as you wish, and put them in the same package to be picked up and registered.
You can also use this to return a different HTTP status code for different errors, but as mentioned in the comments of an earlier POST, that's not going to work well with cross-domain Javascript REST requests.
Let's say you want to handle "MyWebServiceException", you can create an ExceptionMapper "MyWebServiceExceptionMapper" like this:
@Provider public class MyWebServiceExceptionMapper implements ExceptionMapper<MyWebServiceException> { @Override public Response toResponse(Exception e) { GenericEntity<String> entity = new GenericEntity<String>( “{\"statusCode\":\"ERR-100\",\"responseData\":\"Error Processing Web Service\"}” ){}; return Response.status(Status.OK).entity(entity).type(MediaType.APPLICATION_JSON).build(); } } |
In order for this to be registered with Jersey, you'll need to put it in a package that's being scanned by Jersey to be resources or providers, so in the web.xml, have something like this:
<init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.myws.resource;com.myws.provider</param-value> </init-param> |
In this example, I separated the packages for resources and providers, providing 2 packages to be scanned.
To handle each exception differently, just create as many ExceptionMapper classes as you wish, and put them in the same package to be picked up and registered.
You can also use this to return a different HTTP status code for different errors, but as mentioned in the comments of an earlier POST, that's not going to work well with cross-domain Javascript REST requests.
Thursday, July 19, 2012
Jackson Polymorphism
You can handle polymorphism with Jackson using the following annotations at the class level:
This will tell Jackson to map the object to the "AdminAccount" class when the "accountType" property is "ADM", and to the "NormalAccount" class when the "accountType" property is "NML".
Other options are available, such as directly using the class name.
One "gotcha" I discovered is that the "accountType" property must not be implemented in the POJO class. If there is an "accountType" property in the class, it will be null when it's time to work with it in Java. In Java-land, you'll have to use "instanceof" to know what object it is.
A article with more detailed examples: http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html
j@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "accountType") @JsonSubTypes({ @Type(value = AdminAccount.class, name =”ADM”), @Type(value = NormalAccount.class, name =”NML”) }) |
This will tell Jackson to map the object to the "AdminAccount" class when the "accountType" property is "ADM", and to the "NormalAccount" class when the "accountType" property is "NML".
Other options are available, such as directly using the class name.
One "gotcha" I discovered is that the "accountType" property must not be implemented in the POJO class. If there is an "accountType" property in the class, it will be null when it's time to work with it in Java. In Java-land, you'll have to use "instanceof" to know what object it is.
A article with more detailed examples: http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html
Wednesday, July 18, 2012
HTTP Status Codes for REST
For REST services, one common pattern is to use HTTP status codes as the status code for the request itself.
A good reference: http://restpatterns.org/HTTP_Status_Codes
A good reference: http://restpatterns.org/HTTP_Status_Codes
ProGuard: Read Obfuscated Stack Traces
You'll need to run retrace.jar.
You'll also need proguard.jar in the same folder.
Link: http://proguard.sourceforge.net/index.html#manual/retrace/examples.html
java -jar retrace.jar proguard.map stacktrace.txt |
Link: http://proguard.sourceforge.net/index.html#manual/retrace/examples.html
Sunday, July 15, 2012
iOS: AudioQueue Get Audio Level
A very good example of this is found in the "SpeakHere" reference project provided by Apple:
Link: http://developer.apple.com/library/ios/#samplecode/SpeakHere/Introduction/Intro.html
Just some gotcha's and points to note:
You need to call AudioQueueSetProperty to enable the level metering feature in the first place:
The number returned by the AudioQueue will be a negative number with a maximum value of 0. To convert it to a number on a linear scale (i.e. gain level), use the following formula:
Where averagePower is the value returned by the AudioQueue for the audio level average power.
The rest should be pretty straight-forward from studying the example.
Links and References:
Link: http://developer.apple.com/library/ios/#samplecode/SpeakHere/Introduction/Intro.html
Just some gotcha's and points to note:
You need to call AudioQueueSetProperty to enable the level metering feature in the first place:
UInt32 enableMetering = 1; AudioQueueSetProperty(audioQueue, kAudioQueueProperty_EnableLevelMetering, &enableMetering, sizeof(UInt32)); |
The number returned by the AudioQueue will be a negative number with a maximum value of 0. To convert it to a number on a linear scale (i.e. gain level), use the following formula:
float level = pow(10., 0.05 * averagePower); |
Where averagePower is the value returned by the AudioQueue for the audio level average power.
The rest should be pretty straight-forward from studying the example.
Links and References:
- http://stackoverflow.com/questions/1149092/how-do-i-attenuate-a-wav-file-by-a-given-decibel-value
- http://stackoverflow.com/questions/1281494/how-to-obtain-accurate-decibel-leve-with-cocoa
- http://stackoverflow.com/questions/9403094/ios-audioqueue-kaudioqueueerr-invalidpropertyvalue-for-property-kaudioqueueprop
Mongo DB: Java API Get Object by ID
You'll get an error if you try to do something along the lines of "{_id: xxxxx}".
This is how it's done:
This is how it's done:
BasicDBObject searchCriteria = new BasicDBObject("_id", new ObjectId(id)); DBObject dbObj = collection.findOne(searchCriteria); |
Jackson: Ignore Unrecognized Fields
By default, Jackson will throw an exception when a field in the JSON is not declared as a member variable in the class it is mapped to.
To ignore these fields, add the following annotation to the POJO class:
@JsonIgnoreProperties(ignoreUnknown=true) |
AngularJS: Batarang Debugging Tool
Recently, a debugging tool call Batarang was released for AngularJS. It runs as a Google Chrome extension.
Here's a blog about it:
http://blog.angularjs.org/2012/07/introducing-angularjs-batarang.html
Installation instructions:
https://github.com/angular/angularjs-batarang/blob/master/README.md
Things to note:
Here's a blog about it:
http://blog.angularjs.org/2012/07/introducing-angularjs-batarang.html
Installation instructions:
https://github.com/angular/angularjs-batarang/blob/master/README.md
Things to note:
- It doesn't run on the stock Google Chrome. It runs on the "Canary" version which has experimental features for early adopters. You'll have to download, install, and run it as a separate program.
- Installing the extension the usual way won't work due to security restrictions. You'll have to drag the "crx" file into the extensions page (i.e. chrome://chrome/extensions/).
iOS: Making the Table Cell Background a Gradient
This is a good guide for doing it:
http://www.raywenderlich.com/2033/core-graphics-101-lines-rectangles-and-gradients
http://www.raywenderlich.com/2033/core-graphics-101-lines-rectangles-and-gradients
GUID Uniqueness
This is an article explaining how GUID can be almost certainly (if not totally certainly unique).
Link: http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx
This is done by including the following information in the GUID:
Link: http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx
This is done by including the following information in the GUID:
- Machine ID (network card Mac address)
- Timestamp
- Counter to differentiate entries generated within the same timestamp
- Algorithm version identifier
MongoDB: Scaling Approach
The first step in scaling is creating Replica sets (master/slave) where the slaves are allowed to service queries. This will be helpful for read-mostly workloads.
After that, the next step is sharding, where you'll need to define a partitioning mechanism. At a very large scale, the topology would be that of multiple shards, within which contain individual replica sets.
Link: http://www.mongodb.org/display/DOCS/Sharding+Introduction
After that, the next step is sharding, where you'll need to define a partitioning mechanism. At a very large scale, the topology would be that of multiple shards, within which contain individual replica sets.
Link: http://www.mongodb.org/display/DOCS/Sharding+Introduction
Mongo DB Object ID
It is the unique identifier for each document in a collection. Compared to UUID, it is smaller (12 vs 16 bytes) but should still be workable because the requirement is just to have uniqueness within the DB cluster.
Uniqueness is guaranteed by including the machine ID, process ID, a timestamp and a counter for entries generated within the same second.
Link: http://www.mongodb.org/display/DOCS/Object+IDs
Uniqueness is guaranteed by including the machine ID, process ID, a timestamp and a counter for entries generated within the same second.
Link: http://www.mongodb.org/display/DOCS/Object+IDs
Saturday, July 14, 2012
Git: Conflict Resolution By Choosing A Copy
Often, it is as simple as choosing either the local copy in its entirety or the remote copy in its entirety.
In this case, use the following commands:
In this case, use the following commands:
- Use local copy: git checkout --ours FILENAME
- Use remote copy: git checkout --theirs FILENAME
Thursday, July 12, 2012
iOS Activity Indicator
This is how it is done (example is using WebView)
Link: http://stackoverflow.com/questions/11334247/add-activity-indicator-to-web-view
I made some further changes so the indicator is more visible (by putting it inside an alert popup):
Note that I set the frame after "show". This is because if I wanted to calculate x,y,w,h relative to the size of the loading alert frame, these values will only be non-zero after show.
Link: http://stackoverflow.com/questions/11334247/add-activity-indicator-to-web-view
I made some further changes so the indicator is more visible (by putting it inside an alert popup):
- (void)viewDidLoad { [super viewDidLoad]; loadingAlert = [[UIAlertView alloc] initWithTitle:@"Loading..." message:@"\n" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil]; activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; [loadingAlert addSubview:activityIndicator]; } - (void) showLoadingAlert { [loadingAlert show]; activityIndicator.frame = CGRectMake((x,y,w,h); [activityIndicator startAnimating]; } - (void) dismissLoadingAlert { [activityIndicator stopAnimating]; [loadingAlert dismissWithClickedButtonIndex:0 animated:NO]; } |
Note that I set the frame after "show". This is because if I wanted to calculate x,y,w,h relative to the size of the loading alert frame, these values will only be non-zero after show.
NSTimer Gotchas With Threads/RunLoops
Sometimes when you notice that the NSTimer isn't working (i.e. the scheduled task doesn't fire), it can be caused by runloop issues.
By default, it runs in the current run loop from where it is scheduled. If you schedule it from the wrong loop, it might not fire as the loop could be blocked somewhere else.
Which method you use to initialize the timer also makes a difference. The "scheduledTimerWithTimeInterval" creates a timer that runs in the current loop. If the current loop is not suitable for the timer to run, the timer may not fire and you have no idea why.
If you have a problem with the above, you will have to use the "timerWithTimeInterval" methods. However, you have to remember to add the timer to the run loop that you want to add on.
For example, to schedule a timer on the main loop from another loop:
The various behaviors are documented in the class reference.
Reference: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html
By default, it runs in the current run loop from where it is scheduled. If you schedule it from the wrong loop, it might not fire as the loop could be blocked somewhere else.
Which method you use to initialize the timer also makes a difference. The "scheduledTimerWithTimeInterval" creates a timer that runs in the current loop. If the current loop is not suitable for the timer to run, the timer may not fire and you have no idea why.
If you have a problem with the above, you will have to use the "timerWithTimeInterval" methods. However, you have to remember to add the timer to the run loop that you want to add on.
For example, to schedule a timer on the main loop from another loop:
NSTimer *timer = [NSTimer timerWithTimeInterval:waiTime target:self selector:@selector(fireMethod:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes] |
The various behaviors are documented in the class reference.
Reference: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html
Wednesday, July 11, 2012
iOS: Positioning a View Relative to Parent
This is done via the "frame" property of the View, e.g.
viewObj.frame = CGRectMake(20,20,50,40); |
Tuesday, July 10, 2012
MySQL: Dumping With Users and Privileges
A gotcha when trying to clone an entire MySQL DB is that the user privileges are not completely cloned.
The following command would have resulted in users and privileges being cloned (since the "mysql" database would have been dumped), but they do not take effect until a "FLUSH PRIVILEGES" command has been issued:
This means additional manual step of issuing the "FLUSH PRIVILEGES" command is needed before the DB is usable.
In order to ensure that the "FLUSH PRIVILEGES" command is run during DB restore (so no additional steps needed to get DB up and running), include the "--flush-privileges" option during the dump.
The following command would have resulted in users and privileges being cloned (since the "mysql" database would have been dumped), but they do not take effect until a "FLUSH PRIVILEGES" command has been issued:
mysqldump --all-databases > db.sql |
This means additional manual step of issuing the "FLUSH PRIVILEGES" command is needed before the DB is usable.
In order to ensure that the "FLUSH PRIVILEGES" command is run during DB restore (so no additional steps needed to get DB up and running), include the "--flush-privileges" option during the dump.
mysqldump --all-databases --flush-privileges > db.sql |
Apache Wicket: AjaxSubmitLink No Response
What happens is when you click the AjaxSubmitLink, there is no response, no error messages, and you don't know why there is a problem.
This is potentially a gotcha caused by "setRequired(true)" in your form elements. The form will refuse to act (and won't tell you why) when you leave a required field blank.
This is potentially a gotcha caused by "setRequired(true)" in your form elements. The form will refuse to act (and won't tell you why) when you leave a required field blank.
Monday, July 9, 2012
MongoDB Connection Pooling
It seems the Java Driver handles this already and there is no need for any additional engineering for this:
Link: http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency
Link: http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency
Jackson: From Object to JSON String and Back
This is how it's done:
And the other way round:
ObjectMapper jsonMapper = new ObjectMapper(); String jsonStr = jsonMapper.writeValueAsString(jsonObj); |
And the other way round:
ObjectMapper jsonMapper = new ObjectMapper(); UserAccount result = jsonMapper.readValue(userAccountJson, UserAccount.class); |
MongoDB: Save Raw JSON With Java API
In MongoDB's Java API, most of the functions relating to saving objects into the DB requires you to either provide a map or add each property one by one. In situations where you already have the JSON document (e.g. submitted via Javascript), you'd want to just directly save the JSON document.
To do this in MongoDB:
Where the "JSON" class is "com.mongodb.util.JSON".
Reference: http://www.mkyong.com/mongodb/java-mongodb-convert-json-data-to-dbobject/
To do this in MongoDB:
DBObject dbObject = (DBObject) JSON.parse(jsonStr); |
Reference: http://www.mkyong.com/mongodb/java-mongodb-convert-json-data-to-dbobject/
Sunday, July 8, 2012
Bootstrapping Jersey With POJO / JSON Mapping
Jersey is the JAX-RS reference implementation by Sun / Oracle. The bootstrapping process is relatively straightforward. It is done by declaring Servlet(s) to handle the Jersey requests.
The basic configuration (without POJO / JSON mapping) can be found here: http://www.mkyong.com/webservices/jax-rs/jersey-hello-world-example/
To add POJO / JSON mapping:
The basic configuration (without POJO / JSON mapping) can be found here: http://www.mkyong.com/webservices/jax-rs/jersey-hello-world-example/
To add POJO / JSON mapping:
- Ensure the following jar files are on classpath:
- asm
- jackson-core-asl
- jackson-jaxrs
- jackson-mapper-asl
- jackson-xc
- jersey-core
- jersey-json
- jersey-servlet
- jersey-server
- web.xml should look something like this:
<servlet> <servlet-name>WsServlet</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.xxxxx.ws</param-value> </init-param> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>WsServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> |
Git: Configuring Default Pull/Push Remote Branch
While this is automatically done when you clone from a remote repository, you'll have to configure this yourself when you're the one who shared the repository/branch in the first place.
You'll know you have this problem when you see this error message:
The solution is to add the following (e.g. master branch) to the ".git/config" file.
You'll know you have this problem when you see this error message:
> git pull You asked me to pull without telling me which branch you want to merge with, and 'branch.master.merge' in your configuration file does not tell me, either. |
The solution is to add the following (e.g. master branch) to the ".git/config" file.
[branch "master"] remote = origin merge = refs/heads/master |
MongoDB Basics: Database Creation
In MongoDB, databases are lazily created when the first insert is performed on a database after the "use xxxx" command is issued.
It works similarly with collections. It is lazily created upon the first insert.
It works similarly with collections. It is lazily created upon the first insert.
Saturday, July 7, 2012
Javascript: Convert Object to String
Use the JSON.stringify function i.e.
JSON.stringify(obj); |
Note: Does not work on IE6 and 7
Java Servlet Get Post Body
This is how to get the content of the Post body in a HTTP Request:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BufferedReader reader = req.getReader(); StringBuilder inputStringBuilder = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { inputStringBuilder.append(line); } } |
Thursday, July 5, 2012
Apache Mina: Reading Binary Data
The "messageReceived" callback returns an Object that represents the message. When the data sent is in raw binary form, you'll need to cast the object to an IOBuffer before you can read it.
Reference: http://stackoverflow.com/questions/9916617/how-to-read-binary-data-from-socket-with-apache-mina
Reference: http://stackoverflow.com/questions/9916617/how-to-read-binary-data-from-socket-with-apache-mina
Wednesday, July 4, 2012
MySQL Logging Queries
SQL statements sent to MySQL is logged in the general log file. By default, this log file is disabled. To switch it on, insert into my.cnf the following lines:
Note: you will need to make sure the file/folder is writable by the user MySQL is running on.
general_log=1 general_log_file=/var/log/mysql-general.log |
Note: you will need to make sure the file/folder is writable by the user MySQL is running on.
MySQL Table Name Case Sensitivity
When running MySQL in Linux, the default behavior is for table names to be case-sensitive during table name lookups. This can sometimes cause problems, especially if the developer of an application developed on Mac OS or Windows, where the default behavior can be different.
In order to control MySQL case-sensitive behavior, use the "lower_case_table_names" parameter in the my.cnf file. There are 3 possible values:
0: Case sensitive. Table names are stored on disk using the lettercase specified during creation. Name comparisons are case sensitive. Requires case-sensitive filesystem.
1: Case insensitive. Table names are stored in lowercase on disk. MySQL converts all table names to lowercase on storage and lookup.
2: Case insensitive. Table names are stored on disk using the lettercase specified during creation, but MySQL converts them to lowercase on lookup. Name comparisons are not case sensitive. Use only on case insensitive filesystems.
For Linux, choose "lower_case_table_names =1" if you want case insensitive behavior.
Reference: http://dev.mysql.com/doc/refman/5.5/en/identifier-case-sensitivity.html
Monday, July 2, 2012
Hibernate: Capturing Log Entries Under Log4J
Ever since Hibernate migrated to SLF4J, debug entries from within Hibernate no longer shows up in Log4J log files by default.
In order to see Hibernate log entries in the Log4J log files, you'll need to include the "slf4j-log4j12-1.6.4.jar" file into the classpath.
In order to see Hibernate log entries in the Log4J log files, you'll need to include the "slf4j-log4j12-1.6.4.jar" file into the classpath.
Hibernate: Composite Primary Key Mapping
Here's how to do it:
Use this in place of the usual "id" tag.
<composite-id name="id" class="com.xxx.xxx.xxx.KeyClass"> <key-property name="keyProp1" column="key1" /> <key-property name="keyProp2" column="key2" /> </composite-id> |
Use this in place of the usual "id" tag.
Hibernate: Cache Invalidation Between 2 Separate Apps
Assuming the scenario where you have an admin server managing the database entries and an app server servicing user requests, and the app server is using EHCache for caching, it is possible for the Hibernate/EHCache instances to send cache invalidation messages to each other. This is a particularly useful setup as the entities in the app server might be best configured as "read-only" while the same entity in the admin server might be configured as "read-write".
For the admin server to successfully invalidate the cache on the app servers, just configure both apps to be part of the same JGroups cluster, and take note of the following issue here, and it should work fine. The classes on both ends have to be compatible of course,
For the admin server to successfully invalidate the cache on the app servers, just configure both apps to be part of the same JGroups cluster, and take note of the following issue here, and it should work fine. The classes on both ends have to be compatible of course,
Hibernate EHCache: Cache Invalidation Unable to Find SessionFactory
Using Hibernate 3.6.10 and EHCache 2.5.1, I encountered the following error in the log (in the receiving server) when a cache invalidation message was replicated from one node to another.
failed calling receive() in receiverjava.lang.IllegalArgumentException: java.lang.NullPointerException at org.jgroups.Message.getObject(Message.java:291) at net.sf.ehcache.distribution.jgroups.JGroupsCacheReceiver. receive(JGroupsCacheReceiver.java:62) at org.jgroups.JChannel.up(JChannel.java:1490) at org.jgroups.stack.ProtocolStack.up(ProtocolStack.java:1074) <<<<<<<<<<<<<<<<<<<<< SNIPPED >>>>>>>>>>>>>>>>>>>>>>> at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:662) Caused by: java.lang.NullPointerException at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:768) at org.hibernate.impl.SessionFactoryObjectFactory.getNamedInstance (SessionFactoryObjectFactory.java:159) at org.hibernate.impl.SessionFactoryImpl.readResolve(SessionFactoryImpl.java:753) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25) <<<<<<<<<<<<<<<<<<<<< SNIPPED >>>>>>>>>>>>>>>>>>>>>>> at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350) at org.jgroups.util.Util.objectFromByteBuffer(Util.java:398) at org.jgroups.Message.getObject(Message.java:288) |
The cause of this is Hibernate not being able obtain the SessionFactory instance in the receiving server. In Hibernate, it tries to obtain the SessionFactory instance using the UUID. Since this UUID was being generated randomly in both nodes, there is no chance of both UUIDs being the same. This lookup will therefore fail.
However, the fallback mechanism is to lookup using the JNDI name of the SessionFactory, which I did not set. The solution is to set the JNDI name using the "hibernate.session_factory_name" property on both nodes. After I have done that, this problem doesn't happen anymore and replication/cache invalidation is successful.
Hibernate EHCache: ClassCastException in Cluster
I have 2 Hibernate/EHCache nodes in a cluster (managed by JGroups), and after I've done some transactions, I encounter the following error:
java.lang.ClassCastException: java.util.HashMap cannot be cast to org.hibernate.cache.entry.CacheEntry |
The reason for this is that one node had "hibernate.cache.use_structured_entries" set to "true" while the other node didn't have this setting configured (presumably set to "false" by default).
After ensuring that both nodes had "hibernate.cache.use_structured_entries" set to "true", this error no longer occurred.
Subscribe to:
Posts (Atom)