#

Sunday, April 20, 2014

E-Commerce Life Cycle

E-Commerce Life Cycle

Follow more details on this post here
E-Commerce Life Cycle

Wednesday, March 26, 2014

Java E-Commerce platform

Java for the Elite ?

The past decade has seen an explosion of technologies and solutions. On one had we have witnessed popular communities around WORDPRESS, DRUPAL, JOOMLA, MAGENTO and more, on the other hand within the Java community we have witnessed so many advancements in the language, platform, scripting and frameworks. However when you look closer something odd strikes you. The Web and mainly B2C driven solutions are dominated by PHP products and should make one wonder why don't we see a single Java based platform. Specially, with all the advancements and tooling one would wonder where are all these frameworks leading to?

While there are some very interesting advancements in the Java community; I prefer to coin them academic rather than useful. Be it the coming of Scala over Java or frameworks like Play-2. In spite all the innovation within the language, I do feel java developers dwell a lot on code quality (however one may choose to define it), verbosity etc. There is a certain "High", in creating frameworks rather than committing solutions that go the distance. Lets face it, most programmers do not like the noise and the politics of the outside world. I do feel this is a cultural issue rather than an issue with any platform or language. Further, we have survived our arrogance because Java is still desired by the big boys and in the so call "Enterprise" world.

Motivation for a E-Commerce platform

I'm aware of the CMS efforts from the Java community as am aware of the E-Commerce efforts. I won't name them here however Its sufficient to say, when challenged by service competitors from the PHP community competing with the likes of Drupal, Magento etc, ...Java has very little to offer. For all the frameworks we have we lack real world answers and our solace seems to be "Enterprise Development, Custom Development ". As if, we were never good enough for the average web developer on the street or maybe the average web developer isn't good enough to be writing and extending frameworks all his life. Somewhere the elitist attitude faded for me to just writing something useful to help the guys on the front line (guys like myself); catering to small to enterprise Business users from a shared Web Server instance without even SSH access to an Enterprise on multiple nodes. One size fits all! Something that can run by a client without needing a team of technical experts to maintain it. Something that packs in all the features needed to compete and do better than the solutions offered on the PHP front line and yet offer the platform benefits that Java has to offer. Not that I have anything against PHP (I actually admire things about the community), but as a java developer I do feel handicapped and loss for answers. Within JAVA we have fragmented ourselves so much that little comes out that is truly less boiler plate and more progressive. I won't mention all the Java based CMS's/Solutions I tried here, but its sufficient to prove that nothing in the Java community matches the success of DRUPAL, WORDPRESS, JOOMLA, MAGENTO to name a few, and you need to ask yourself "why" !

What's different ?

The above motivations my seem abstract. In reality how it translates is that there are many by-products of E-Commerce. Like Search, ETL, CMS etc. These not only find their way to contribute to E-Commerce but also other areas of development that are application specific. The issue with "framework" mindset is you are always providing a tool and nothing more. The higher order glues are left to the developers. That is a good thing, but in today's world these tools are not good enough. The GAP between polished services and what frameworks provide is getting larger. E-Commerce demands solutions and a lot of these "solutions" can be shared, improved, modularized or even exposed as services. Furthermore it results in leaner code bases and also better utilization of memmory, lower learning curves, lower investment in writing business ready applications.

When I look @ companies selling Enterprise versions, and giving Community edition's they seem just a little more than frameworks. But if you had to pitch it to a client, you fall very short with almost no community help from the companies that provided then Open Source solutions. We all want to make money, however what I'm against is monopoly of what the community contributes back. This is causing a dilemma for me in terms of licensing (separate topic)

There is also a lot of emphasis on reduced number of entities and Data Models. The entire CMS, ECOM, User data, etc .. you name it, can be put down in 8 Database Tables without any loss of functionality. I don't want to get into a technical discussion yet, however compare that number to some elephant you install. As features grow, so do their data needs. There are ramifications of blatant abuse of entities that most platforms adopt. These are exponential and not just limited to hardware. I feel these concerns are conveniently ignored in most projects. There are many other concepts that I won't dive into yet and let the code, architecture do the talking. Reducing and reusing entity objects (definitions and instances), does imply drastic improvement in many ways.

Structure

There are many things that go into making a CMS and more so an E-Commerce platform. Hence, all these services have been broken into Libraries. ETL, Reporting, Searching, Content Handling Services, Admin UI, Authorization, Authentication, Carts, etc etc. I have developed each as a standalone library so that people can use them independently. A lot of things useful in a CMS & E-Com can be leveraged in some other projects also. I feel existing CMS definitions are very single focused and hence limited.

The idea is that people don't have to look @ it as a monolithic project and can create or contribute to parts that are of interest, and each module can grow as its own project.

The liability of learning a new Framework

Shifting away from JAVA & PHP; furthermore if something is designed as a CMS then it is only a CMS. Its hard to extend it to being an E-Commerce platform and so on. This is not just about providing a JAVA's alternative but providing something that offers more flexibility for developers to build like LEGO blocks. Spring, Apache Wicket are beautiful example where they make this possible. This also offers a lower learning curve to adopters with no DSL or additional learning curve needed as such. However, as mentioned below we have plenty of frameworks. When you put together an E-Commerce site you do realize the gaps and the mammoth effort of putting all these together. And what you dont want is a "CUSTOM" glued solution that's a curry of all frameworks. You want solutions and services that have been tested and optimized in a domain specific environment and validated by business users and consumers.

A frustrating point of adopting new frameworks or alternatives is the knowledge curve required. The aim of any platform should be to allow people familiar with the core frameworks to dive right in. In addition, providing an independent module for each type of service allows which aspects people would like to use, customize, contribute. Solutions demand answers and the ability to replace frameworks if need be over time. However, there is a masochist in every good developer. For me learning Scala was not about a better language but was just about getting to learn a new alternative. This does not always imply we will be more productive and yet when a new framework comes out, no matter how productive, we always like the fact we can be Elite. Nothing wrong with that, but from a platform developers perspective the idea should be to allow and welcome as many people onboard and thus weed out core dependencies that are not standard practice. make it simple and useful and let people decide what works for them.

I do hope the motivation is well placed and look to hearing views. Strong opinions are welcome. I do also hope to back this up with the platform soon...

Current Status & Direction

The project has matured and achieved sufficient functionality for any small to medium enterprise to use it. However I am now to focus on the following. Worth noting I'd be looking @ a community to help me grow this:
  1. Licensing - Big, tough one!
  2. Documentation
  3. Creating the user Forum
  4. Creating a sample application for the community to demonstrate base usage and ability backed by videos and tutorials
  5. Providing OOB integration's with existing popular cloud services
  6. Additional Unit and integration test automation


Site(s) developed on this platform

https://lemillindia.com
https://nurhome.in

CMS only based sites:
http://wrap.co.in

more in the pipeline ...

Thursday, April 11, 2013

MySQL, UTF-8, Java - Data Imports

I had a terrible time translating my UTF-8 data which I wanted to import from an backend process into my webapp and display it as is without any hiccups. Turns out, this is one of those things if you get right, you will never know but if you dont .. then you are perhaps going to wanna write a blog like this one :)

So in my endeavor, I did some research and found posts like : Character Encoding UTF-8 with JPA/Hibernate, MySql and Tomcat

While the stuff there is apt, it does not hit the problem I had. Which was not just about your data but to ensure you import your data in a pure UTF-8.
Turns out no my.cnf and no mysqld param stuff was required. Neither was any complicated JDBC connection string required like &useUnicode=true&characterEncoding=UTF-8

Only the following steps need to be kept in mind:
  1. Ensure clean Data import:  This is the most critical step. NEVER copy/paste your data. Ensure the file that contains your data is saved in the proper encoded format, in our case UTF-8
  2. Ensure Schema and Table definitions follow the same encoding:  
    create database my_schema_name character set utf8 DEFAULT COLLATE utf8_general_ci;
  3. Import via prompt:  
    mysql -u root -p -h localhost dbname --default-character-set=utf8 < filename.sql


Some other Misc notes:
  • If you decide to use connection params in your JDBC string to MySQL, use UTF-8 instead of utf8. Refer to MySQL Char Set Ref for details
  • If you are using the String directly in an XML use CDATA or replace & with &amp;. If you import them say from a properties file into a Spring config, ignore this.
  • When rendering your HTML ensure the page character set supports UTF-8 and further you may convert text by using a function like:
    function replaceEncodedChars(elementHTMLId) {
       $(elementHTMLId).each(
        function( intIndex ){
         $(this).attr('innerHTML', $(this).text());
        }
       );
    };
    
    Sample Usage:

Wednesday, April 25, 2012

Scala, JPA and annotations

I've been trying to get onto the Scala Bandwagon and have been diligently reading some books that cover core scala well. However, like every programmer I'm enthusiastic to apply my acquired black arts to my work and justify to myself that this truly is productive.

While trying to apply my skills immediately is admittedly been a bit clunky, I finally managed to get a JPA, Scala piece of work in place. So as usual lets dive into the code.

Note: I'm still a learner, so if anyone has a better approach or feels I'm wrong somewhere or have misunderstood/misinterpreted something, please feel free to shoot.

  1. Ensure your Dependencies are right. For this check your JPA & Scala dependencies. If you are self sufficient "good for you", if not; this is what I used :
        ...
          
            2.9.2
            ...
            5.1.18        
            2.0.0
            1.4        
            1.0.1.Final
            3.3.2.GA
            3.4.0.GA
            3.3.0.ga
            3.4.0.GA 
            0.9.1.2
          
        ...
          
            ...
     
            scala
            Scala Tools
            http://scala-tools.org/repo-releases/
            
                true
            
            
                false
            
        
          ...
          
    
      
        
            scala
            Scala Tools
            http://scala-tools.org/repo-releases/
            
                true
            
            
                false
            
        
      
            
         ....
        
      
      
       org.hibernate.javax.persistence
       hibernate-jpa-2.0-api
       ${hibernate.jpa2.version}
      
      
      
            org.hibernate
            hibernate-core
            ${hibernate.core}
            
        
         commons-collections
         commons-collections     
        
               
         
      
       org.hibernate
       hibernate-commons-annotations
       ${hibernate.commons.annotations.version}
       
        
         javax.persistence
         persistence-api     
           
        
         hibernate
         org.hibernate     
            
       
      
      
       org.hibernate
       hibernate-annotations
       ${hibernate.annotations.version}
        
        
      
       org.hibernate
       hibernate-entitymanager
       ${hibernate.em.version}
       
        
              
                net.sf.ehcache
                ehcache
                  
       
      
            
                mysql
                mysql-connector-java
                ${mysql.java.connector.version}
            
            
                org.hsqldb
                hsqldb
                ${hypersonic.db.version}
                test
            
            
      
       c3p0
       c3p0
       ${pooling.c3p0.version}
      
            
            
                javax.validation
                validation-api
                1.0.0.GA
                compile
            
    
     
     
      org.scala-lang
      scala-library
      ${scala.version}
     
        
       
  2. Setup your Entity manager and DB connection Pool. I hooked mine to MySQL. Am assuming Connection Pool details not required. Plenty of articles for that. I use Spring with org.springframework.orm.jpa.JpaTransactionManager, com.mchange.v2.c3p0.ComboPooledDataSource, org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.
    Note: My dependencies also rely on Spring, but I have omitted those in my POM config sample above for brevity as they are standard Spring dependencies.
  3. In the source folder : src/main/scala. I created two Files:
    package com.neurosys.quizapp.domain
    
    import javax.persistence.Entity
    import javax.persistence.OneToMany
    import javax.persistence.GeneratedValue
    import scala.annotation.target.field
    import javax.persistence.Id
    import javax.persistence.GenerationType
    import javax.persistence.CascadeType
    import javax.persistence.FetchType
    import javax.persistence.OneToOne
    
    /**
     * @author Arjun Dhar, NeuroSystems Technologies Pvt. Ltd.
     */
    @Entity(name="questions")
    case class Question(text: String) {   
        //def this() = this(null)
            
        @(Id @field)
        @(GeneratedValue @field)(strategy = GenerationType.AUTO)    
     var id:Long = 0L 
     def setId(id:Long) =  {this.id = id}
        def getId:Long = this.id    
        
        def getText = this.text
     
        @OneToOne(optional=false)
     var correctAnswer:Answer = null
     def setCorrectAnswer(correctAnswer:Answer) =  {this.correctAnswer = correctAnswer}
        def getCorrectAnswer:Answer = this.correctAnswer
    
        @OneToMany(fetch=FetchType.EAGER, mappedBy="question")
        var answers : java.util.List[Answer]= _
        def setAnswers(answers:java.util.List[Answer]) =  {this.answers = answers}
        def getAnswers:java.util.List[Answer] = this.answers   
    }
    

    and
    package com.neurosys.quizapp.domain
    import javax.persistence.Entity
    import javax.persistence.OneToOne
    import javax.persistence.GeneratedValue
    import scala.annotation.target.field
    import javax.persistence.Id
    import javax.persistence.GenerationType
    import javax.persistence.ManyToOne
    
    /**
     * @author Arjun Dhar, NeuroSystems Technologies Pvt. Ltd.
     */
    @Entity(name="answers")
    case class Answer(text:String, sequence:Int) {
        //def this() = this(null, "", 0)
        def this(question:Question, text:String, order:Int) = {
          this(text, order);
          this.question = question;
        }
      
        @(Id @field)
        @(GeneratedValue @field)(strategy = GenerationType.AUTO)    
     var id:Long = 0L
     def setId(id:Long) =  {this.id = id}
        def getId:Long = this.id 
        
        @OneToOne(optional=false)
        var question:Question = null
        //def setQuestion(question:Question) = this.question = question
        def getQuestion = this.question
        
        //var text:String = null
        //def setText(text:String) = this.text = text
        def getText = this.text
        
        def getSequence = this.sequence;
    }
    
  4. What does the above do?

    I wanted to create a simple question bank as a sample exercise.

    I created a model where one Question can have only one correct answer which the question object is aware of. Also, the answers know which question they belong to.
    Interesting points to note:
    • In Scala, though you can define your members within the constructor arguments itself, Annotating them there does not work -- took a lot of my time. Frankly a bit annoyed it did not work, but I did expect magic!
      Example: case class Answer(@OneToOne question:Question, text:String, sequence:Int) will not work.
    • Notice the style@(GeneratedValue @field)
    • I adopted the use of Scala case class; helps in scala taking care of the euqals and hashCode methods which from an OR framework perspective deserves attention.
    • You do not have to have your Scala Entity look like a total Java Bean, have the constructor do as much of the hard work and simply implement getters (leave the setters / optional)
    • In the Questions entity, the last field called answers has to be a traditional Java Collection. i.e. You cannot use the Scala Trait Seq or List. I would be interested to see the JPA flavour for Scala support these things.
...voila, it worked!

Thursday, February 9, 2012

Junit with Jetty & RESTful CXF

Recently I fitted my JUnits, to work with a self starting & dying Jetty embedded server. So this tutorial will show you how to Hook in your CXF WebService Unit with a self sustaining Jetty Server as a bonus ;)

The context of our example is a bit of code I am currently working on. A generic Query service that can query any entity based on custom annotations that supplement JPA. The Domain & JPA part is out of scope, so I'm not going to define the core domain model here but focus on the Unit Test & related Springs configs.

Before I get into the code, I'd like to futher illustrate the folder structure of the project so that you know where our Self instantiated Jetty server can pick things from; and adapt this to your requirements. The project I am working on is packaged as a JAR and has no WAR structure to begin with so it makes for an interesting use case to begin with.

Project Structure (Standard Maven with a test/webapp to support our cause)


1. Setup a Server

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import org.mortbay.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A Self Server to Start & stop
*
* Code help taken from:

* How to start and stop Jetty – revisited
*

* Run Jetty Web Server Within Your Application
*
* @author Arjun Dhar
*/
public class SelfServer {
private static Logger log = LoggerFactory.getLogger(SelfServer.class);

private Server server;

private int port = 9091;
private int stopPort = 9092;
private String contextPath = "/testContext";
private String webPath = "src/test/webapp/WEB-INF";
private String host = "127.0.0.1";

public SelfServer() {}
public SelfServer(String host, int port, String contextPath, String webPath) {
this.host = host;
this.port = port;
this.contextPath = contextPath;
this.webPath = webPath;
}

/**
* This is a Blocking call and will wait till the server is Started
* @throws Exception
*/
public void start() throws Exception {
Thread t = new Thread() {
public void run() {
server = new Server();
SocketConnector connector = new SocketConnector();
connector.setPort(port);
server.setConnectors(new Connector[] { connector });

WebAppContext context = new WebAppContext();
context.setServer(server);
context.setContextPath(contextPath);
//context.setWar(warFilePath);

//Note: Set WAR assumes all resources etc in place like genuine WAR,
//in our case resources scattered across so use the following instead:
context.setResourceBase("src/main/resources");
context.setDescriptor(webPath + "/web.xml");
server.addHandler(context);

Thread monitor = new MonitorThread(host, stopPort, server);
monitor.start();

try {
server.start();
server.join();
}
catch(Exception e) {
throw new RuntimeException(e);
}
}
};

t.setDaemon(true);
t.start();

while(server==null || !server.isStarted()) {/* Block till started */}

log.info("[start] Started Server @ " + host + ":" + port );
log.info("[start] Server Ready & Running - " + server.isRunning());
}

public void stop() throws Exception {
Socket s = new Socket(InetAddress.getByName(host), stopPort);
OutputStream out = s.getOutputStream();
log.info("[stop] sending jetty stop request @ " + host + ":" + stopPort );
out.write(("\r\n").getBytes());
out.flush();
s.close();

if (server!=null && server.isStarted()) {
server.stop();
}
}


private static final class MonitorThread extends Thread {

private ServerSocket socket;
private Server server;
private int stopPort;
private String host;

public MonitorThread(String host, int stopPort, Server server) {
this.server = server;
this.stopPort = stopPort;
this.host = host;

setDaemon(true);
setName("StopMonitor");
try {
socket = new ServerSocket(stopPort, 1, InetAddress.getByName(host));
} catch(Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void run() {
log.info("[run] Running Jetty Stop Thread");
Socket accept;
try {
accept = socket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
reader.readLine();
log.info("[run] Stopping embedded Jetty Server");
server.stop();
accept.close();
socket.close();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}

}



2. Create the JUnit Test Case

This test case, assumes a Domain model (irrelevant to our conversation), and a Web Service that has a simple test method getTestString(), that returns a String. (text/plain) type.


One important thing to note is that the Service being used directly as proxy here.

In amore complicated scenarios, where parameters need to be marshaled and more
explicit Header type information is required, then you need to refer to
CXF JAX-RS Client API


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.neurosys.selfserver.SelfServer;

/**
* Test CXF REST services
*
* @author Arjun Dhar
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:com/neurosys/amorphous/applicationContext.xml",
"classpath:com/neurosys/amorphous/rest-test-client.xml"
})
public class RESTServicesTest {
private static Logger log = LoggerFactory.getLogger(RESTServicesTest.class);

@Autowired
@Qualifier("testclient")
protected GenericObjectQueryService proxy;

@Before
public void init() throws Exception {
/* please note, in actuality, for multiple tests you will have
to ensure a single version of the server is running only.

For each test case, it will invoke start and will give an error.
This is simplified for Blog consumption here only. */
SelfServer server = new SelfServer();
server.start();
}

@Test
public void testConnect() throws Exception {
/* Note: Service being used directly as proxy here.
In more complicated scenarios, where parameters need to be marshalled and more
explicit Header type information is required, then you need to refer to
http://cxf.apache.org/docs/jax-rs-client-api.html
*/
Response response = proxy.getTestString();
Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus());

BufferedReader r = new BufferedReader(new InputStreamReader(((ByteArrayInputStream)response.getEntity())));
StringBuilder sb = new StringBuilder();
while(r.ready()) {
sb.append(r.readLine());
}
log.info("[testConnect] Result = " + sb.toString());
Assert.assertEquals(GenericObjectQueryService.test, sb.toString());
}

}


3. Next you need to ensure your Spring config for your CXF is up



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">







































4. Define the CXF Test Client Proxy

You would have noticed in the test case the inclusion of rest-test-client.xml. Additionally, we are using a property that should be injected via your Spring applicationContenxt.xml.

Variable : ${webservice.address.genericobjectservice} = genericobject-query in this example.


xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">


serviceClass="com.neurosys.amorphous.service.jaxrs.GenericObjectQueryService">









...and thats it!

- Arjun Dhar
My Company NeuroSys

Wednesday, February 1, 2012

Expresso Shots!


  • org.apache.commons.beanutils.BeanUtils are nice but they return almost everything as a String which is annoying.

    To get the value of a field use this or a variant of it: BeanUtilsBean2.getInstance().getPropertyUtils().getSimpleProperty();


  • c3Po Configurations for shared hosted environments


    Connection Pooling on Production Infrastructure


    On a shared hosted 3rd party environment, sometimes Connections Pooling can be a big mess to deal with. One more often than not ends up with dropped connections (inspite of reconnect=true). Connections that are in the Pool but no longer honoured by the database itself, which results in such situations also among others. The issues with DBCP are worse than c3po, but they exist everywhere. Worse, in a shared hosted environment you do not have access to the Database as root and you don't have access to anything but whats in your application.

    Exceptions


    Some of the exceptions are of the following nature:

    Caused by: org.hibernate.TransactionException: JDBC begin failed:
    ...
    Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
    ...
    INFO [com.mchange.v2.c3p0.impl.NewPooledConnection] [c3p0] Exceptions occurred while trying to close a PooledConnection's resources normally.
    INFO [com.mchange.v2.c3p0.impl.NewPooledConnection] [c3p0] NewPooledConnection close Exception.
    com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communications link failure during rollback(). Transaction resolution unknown.


    Solution
    I wrote a script that automated the process of testing various combination's (certain key params), and then I fine tuned it manually. It was heuristic, and there may be other combination's but this really works well and fast. It is reliable and has proven good on several projects of that nature. I have my theory on why it works, but because the nature of determination was heuristic, I don't think its worth delving into.





























    true
    false

    ${db.credential.username}
    ${db.credential.password}






Tuesday, July 19, 2011

Spring 3.1 & EhCache Integration

Context: How to integrate EhCache via Spring 3.1 (At the time of Writing Spring ver:3.1.0.M2)


1. Setup your library dependencies correctly

PSEUDO CONFIG : Maven config for reference and not to be copied as is :
  
    3.1.0.M2
  
  
  
 
 
  spring-maven-release
  Spring Maven Release Repository
  http://maven.springframework.org/release
 
 
  spring-maven-milestone
  Spring Maven Milestone Repository
  http://maven.springframework.org/milestone
 

      ehcache-repo
      EhCache Repository
   https://oss.sonatype.org/content/repositories/sourceforge-releases
      
          false
      
      
         true
      
     
 
    
...

    
      
    

    
      net.sf.ehcache 
      ehcache-core
      2.4.3
    


NOTE: An important point to note is that many a time an Old Spring Library or worse, a conflicting EhCache Library (from say a Hibernate) dependency will give errors. The errors will looks like "Spring <init> method failures". To avoid this, please do a mvn dependency:tree on your modules and do any <exclusions> to other versions of EhCache.


2. Define You interface (Method Caching) : We are effectively ensuring all method operations are cached to cache publishContent. Furthermore, the identifier key is based on the URI.getLocation(). The cache can be applied on the interface or an Impl. You can write a default implementation for your interface and wire it via Spring (@Component)



For brevity, we will skip details of Method Caching. There are several articles on it. Note the use of SpEL. Can be also used for doing conditional caching. For example, in the sample interface below we are interested in caching only Content that is PUBLISHED.
/**
 * An adapter to extract the content from a specified location. Piped with {@link ContentLocationResolver} this
 * can locate and extract content from any Data Source.
 * 
 * @author Arjun Dhar
 *
 */
public interface ContentExtractor { 
 /**
  * Get Content. PUBLISHED Content is cached
  * 
  * @see {@link Cacheable}
  */
 @Cacheable(key="#location.path", 
      condition="(#location!=null and #context!=null and " +
          "T(com.neurosys.pms.content.domain.Status).PUBLISH == #context.status)" , value="publishContent") {
 public String getContent(URI location, EditableContentContext context);
}


Important Note:
From http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/cache.html In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case.


3. Define Spring Binding/Config for EhCache

  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:cache="http://www.springframework.org/schema/cache"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

    

  
         p:config-location="classpath:com/neurosys/pms/modules/content/ehcache.xml"
      p:shared="false"
      >
     
      
     

  


4. Define the Caching configs in ehcache.xml
             xsi:noNamespaceSchemaLocation="ehcache.xsd"
             updateCheck="false" monitoring="autodetect"
             dynamicConfig="true">

  
  
  
    
  
                                
  


5. Sanity Unit test to ensure all the bindings etc are correctly setup
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
  "classpath:*applicationContext.xml" //Assumes the Spring config is in or imported via your applicationContent.xml
 }) 
public class ContentLocateFetchTest {
 @Autowired
 private ContentExtractor contentExtractor;
 
 @Test
 public void testCache() {
  //No context status, hence it will fetch the data twice. One for each call.
  //If you put a Debug Statement in contentExtractor.getContent(), you will see it called twice for google.com
  contentExtractor.getContent(new URI("http://google.com"), null);
  contentExtractor.getContent(new URI("http://google.com"), null);
  
  EditableContentContext cntx = new EditableContentContext() {
   @Override public Authorization getAuthorization() {return null;}
   @Override public Status getStatus() {return Status.PUBLISH;}   
  };
  
  //If you put a Debug Statement in contentExtractor.getContent(), you will see it called only once for yahoo.com
  //since it detects that the context has a Status=PUBLISH and caches it.
  contentExtractor.getContent(new URI("http://yahoo.com"), cntx);
  contentExtractor.getContent(new URI("http://yahoo.com"), cntx);  
 }
}


You may also want to programatically refer to the cache to refresh or clear it etc:
 @Autowired
 @Qualifier("cacheManageName")
 private EhCacheCacheManager cacheManager; .... 
...
Cache cache = cacheManager.getCache("cahceName");
    cache.clear();
..In the above the cache name is that is supplied in <cache name="chacheName"...

- Arjun Dhar
My Company NeuroSys