Tuesday, April 26, 2011

Moving to Siena from Play Framework JPA

I Recently built a REST service using the Play Framework and once complete I started looking for a place to deploy the app. Not having a hosted server that runs Java meant I needed a cloud solution and the first to come to mind was GAE. I have used GAE before but this was the first time with Play. (Play and GAE go great together btw.)

Having done little deployment planning from the beginning, it wasnt until a blew through the coding and did a successful deploy that I realized that JPA just doesn't seem to work well with Play's JPA (nothing against Play, GAE just does JPA differently). After a bit of reading that I had skipped past the first time it became evident that I needed to use the Play Siena Module with my GAE app. This turned out to be easier then I though but, I had to hunt around a little to piece together the details so I wanted to share the migration here. This should also be helpful if you are planning to use Siena from the start and already know Play's JPA.

Moving to Siena from the Play JPA was surprisingly simple, I spent more time thinking over weather I wanted to mess with it and looking up the details then actually doing it!

1. Install Siena into Play. (I'm assuming you have Play set up and GAE already installed.)
play install siena-1.5

2. Include in App.conf. Add Siena right under the GAE module like so.

# ---- MODULES ----
module.gae=${play.path}/modules/gae-1.4
module.siena=${play.path}/modules/siena-1.5


3. Change your Models from play.db.jpa.Model to siena.Model. Your just changing an import statement here.

//import play.db.jpa.Model;
import siena.Model;


4. Add an ID field. Play takes care of this for you in the Model but you'll have to add it in for Siena, or make a new Object to inherit from.

  @Id
  public Long id;


5. Update method calls. A few methods have slightly different names but they are pretty obvious and should slow you down.
  1. Model.save() calls become Model.insert()
  2. You'll need to change up your searching, I usually just code methods in the Model to wrap the search queries which means I only have to change the search code in one spot, the Model. Here's a sample of a new search:
  3. Model.all(MonitoredFeed.class).filter("suspended", false).fetch();
  4. Change findAll(), all() calls to Model.All(Your.class) or simply provide a helper method like below.(This could again go in some type of BaseModel reducing your code changes.)
  5. public static Query all() {     return Model.all(MonitoredFeed.class); }
6. Update your Test Fixtures! Of course you have to update the Tests! If your using Fixtures you'll just have to change your imports from Fixture to SienaFixture.

That's all there its to it! Now you can deploy your app on GAE!

Saturday, April 16, 2011

Serve Up Static Content Even When Mapping /* to a FrontController Servlet.

I am blogging this to share the info as much as to remind myself in the future how simple setting this up really is. It's the easy solutions that can be the hardest to remember..

Say you have a RESTful services framework running in a web app and all of your requests get routed to CXF or some other Framework for supporting such implementations. Simply put, there isn't a UI for the app and the Controller Servlet does't support a UI. Now say that you really want to be able to serve up say.. a JS file and some css to style generated API documentation for your services. No problem since this is Tomcat except you have a /* url-pattern routing all traffic to a REST Servlet.

Here's the solution: Most Java servers have a default servlet of some sort which will simply handle HTTP requests. If you set up a url-pattern to /static or some other path you can direct that request to your static files. One note, you'll be requesting /static/js/jquery-min.js but, the fiel will reside at /js/jquery-min.js this is because the /static is really acting as a indicator to rout to the default servlet. It's almost like a query string in the path.. no it makes since, really.


<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

Thursday, April 14, 2011

Scripting Groovy to process csv files.

I have a lot of experience with um, "manhandling" flat file data into usable formats. Usually this "data" comes to me in the form of excel spreadsheets, crafted with presentation in mind. They look great but, have little flexibility when it comes to importing the data into relational databases. There are hundreds of solutions for doing this sort of manipulation in bulk and if that's your lot in life by all means beg the IT department to buy you a good data transformation tool!

For some reason my situations are frequently one offs of user data that is begging to get into a database but, as of yet is still running in the wild. My solution has come down to quick Groovy scripts and splicing spreed sheets into multiple CSV files Groovy to chew through. This can be done with Python and many other script languages but, I'm fully fluent in Java so Groovy is my fastest path to a database at this point in time. This is a great place to learn a new scripting language if you have the time but, I usually want this over in a flash. On that note, if you would like to just grab the code and run jump to the bottom to grab My CsvUtils code which takes care of this whole process in a more formal utility object.

Reading a file and working with it is pretty darn simple in Groovy, the following code will open up a CSV and move all the data into nicely structured arrays. (This provides the same results as calling CSVUtils.csvToList())

 //load room types from file
def f= new File('roomtypemap-min.csv');

//set up a List of 'Rows' which will contain a list of 'columns' or you can think of it as array[][]
roomTypes = [];
def lines = 0;
f.splitEachLine(',') {
    def row = [];
    row = it;
    roomTypes << row;
    lines++
}
println "Processed $lines Lines"

The above chewed through a CSV file with name,value pairs of data and placed them in a multi-dimensional array types as a Java list. If your not up on Java collections, it's a whole lot like an array but, better.

Now lets say we did the above code with a few files then process all that data into a new CSV file ready for your code. The code below shows the building of the final results. You'll notice that along with the roomTypes list imported from a CSV file there are now a few others resortList and amenities. All these were pulled from random table dumps and such and I turned them in to usable data.


def aId = 0;    
roomTypes.each{
  def indx = roomTypes.indexOf(it);
  def resortList = roomResortMap[indx];
  def roomType  = it[0];
  
  resortList.each() {
    def facIdx = it.toInteger();
    def facilityId = resorts[it.toInteger()];
    
    amenities.each() {
      def ai = amenities.indexOf(it);
      def avail = values[ai];
      if(avail[facIdx] == true) {
        def description = it;
        println "\"$facilityId\",$roomType,$aId,\"$description\"";
      aId++;
      }
    }
  }

There are a couple things to point out if your new to Groovy. While there is a whole lot of Java in Groovy it also looks a lot like JavaScript making Groovy pretty easy for JavaScript developers to pick up despite deep Java knowledge.

The first thing to note is the iteration I am performing with the .each callback. Personally, I think it looks a good bit like a JavaScript closure. Your simply passing in code to the .each(){} iterator to execute on each item in the List. OH the () is optional when creating this closure so add if you wish.

Second, in the version of Groovy I am using, 1.7.10, you have to do a little bit of work to get the current index position of the for loop. To do this simply call yourListName.indexOf(it). It looks like the upcoming 1.8 is going to have an additional closure called eachWithIndex() which will provide you it and i variables where the i will be the current index. I'm looking forward to that feature!

Finally I just want to point out one of my favorite things for keeping life simple, string replacement. Notice on the next to list line before the braces cascade I'm calling println but, the cool part is the replacements in the string using $fieldName. When your trying to print out complicated strings nothing is worse for readability and bugs then concatenating or calling tons of append() methods. It just leads to errors. You can do simple string replacement with variables using the $fieldName inside your string or for more complicated inserts ${} will work for things like ${Object.field}.

Hope this will help you to simplify the tedious task of data mining text files!

My CSVUtils Object:

/**
 * CSVUtils is released into the public domain, do what ya want with it.
 * By Lee Clarke
 */
public class CSVUtils {  
 
  /**   
   * Removed quotes from around imported csv values if present.
   */
  public static String stripQuotes(String strIn) {  
    def valOut = strIn;  
    if(valOut==null)  
      valOut == "";  
    if(valOut.startsWith("\""))   
      valOut = valOut.substring(1);  
    if(valOut.endsWith("\""))   
      valOut = valOut.substring(0,valOut.length()-1);  
    return valOut;  
  }
    
  /**   
   * Load the csv into a Map using indexed position of values for key and value. 
   * @param keyPos - col index of the key value in a row
   * @param valPos - pull value data from index/col position in row
   * @param csvFilePath - full path to file
   */  
  public static Map csvToMap(int keyPos, int valPos, String csvFilePath) {  
    def fp= new File(csvFilePath);  
    def rtnMap = [:];  
  
    def palines = 0;  
    fp.splitEachLine(',') {  
      if(palines > 0)//skip col header line  
      {  
        def row = [];  
                row = it;  
        def key = CSVUtils.stripQuotes( row[keyPos]);  
        def val = CSVUtils.stripQuotes( (valPos < 0)?row.last():row[valPos]);  
        rtnMap.putAt(key, val);  
      }  
      palines++  
    }  
    return rtnMap;  
  }  
  
  /**
   * loads values in csv file into multi-dimentional like List of rows and cols.
   * @param csvFilePath - full file path.
   * @param skipFirstRow - skip first row if it contains column names.
   */
  public static List csvToList( String csvFilePath, boolean skipFirstRow) {
    def fr= new File(csvFilePath);
    def rtnList = [];
    def rlines = 0;
    fr.splitEachLine(',') {
      if(!(skipFirstRow && rlines == 0)) {
        println "row= $it"
        def row = [];
        row = it;
        rtnList << row;
      }
      rlines++
    }
    return rtnList;
  }
  
  /**
   * loads values in csv file into multi-dimentional like List of rows and cols.
   * @param csvFilePath - full file path.
   */
  public static List csvToList( String csvFilePath) { 
    return csvToList(csvFilePath,true);
  }
}  

Friday, April 8, 2011

New hRecipeHelper for Web Browsers released!

Do you like to blog recipes but don't use Chrome? No problem! Now you can use my new web version of hRecipeHelper in any moder browser. I know it works with FireFox 3.6 and up as well as IE8, I can only assume it works with IE9 if IE8 works. I haven't tested on IE9 and Safari because I don't have them and can't even run IE9. If you trying it out and find bugs please post a comment here and I'll have it fixed asap.

Just like the Chrome Extension its free, Enjoy!