Saturday, March 28, 2009

Hibernate hmm!

I have not had the pleasure of using Hibernate before on a project until now. Recently I needed to retrieve email addresses for certain types of users. The types of users would be sent in from a Flex client. The database tables look similar to this.

Normally I would run a simple query like this to retrieve these email addresses

select email_id from USER, user_type_app_assn
where user.rec_del_ind = 0
and user.user_id = user_type_app_assn.user_id
and user_type_app_assn.app_id = 1
and user_type_app_assn.user_type_cd in (3,4,5)

Since the project uses Hibernate I looked at samples that other team members had done, so I started mimicking what they did. I decided to write a set of criteria with restrictions linking it to the proper objects. The code looked similar to this.

Criteria criteria = session.createCriteria(User.class);
criteria.add(Expression.eq(User.REC_DEL_IND_FIELD_NAME, "0"));
Criteria crit = criteria.createCriteria("userTypeAppAssns");
crit.createCriteria("appCode").add (Restrictions.eq ("appId", new Long (appId)));
crit.createCriteria("userTypeCode").add(Restrictions.in("userTypeCd", userTypeCodes));
tx = session.beginTransaction();
List userList = criteria.list();

You are saying it looks OK based on the database schema, what is your issue. Well, the issue is performance I found that it took forever and was running tons of minor queries and dumping out lots of logging statements. This all caused my Flex client to time out (subject of a future post). I sent my code off to a couple of fellow developers for them to do a code review. They were going to have to research it more not being familiar with the way I was doing things. The did offer up using HQL as this is the primary way that they were trained to use Hibernate.

Cool, I can code SQL how hard can this be. So I rewrote the above code to look like this.

tx = session.beginTransaction();
List userList = session.createSQLQuery("select email_id from UAE_USER, uae_user_type_app_assn" +
" where uae_user.rec_del_ind = 0" +
" and uae_user.user_id = uae_user_type_app_assn.user_id" +
" and uae_user_type_app_assn.app_id = " + appId +
" and uae_user_type_app_assn.user_type_cd in (" + userTypesSQL + ")"
).addScalar("EMAIL_ID", Hibernate.STRING).list();
;
                               
tx.commit();

After deploying and running the above I noticed a huge difference in performance (no time outs and the logs were cleaner). I have some theories as to why this happening. When you are grabbing the User object it is going to all of the other associated tables and pulling back data, thus the minor calls I was seeing and when you are talking 1000s of records this can take time. So I can see that using this second approach when you are not needing all of that data maybe a better approach.

I still have a ton to learn about Hibernate so if there is away to use the Criteria and not have it perform the other searches, I would love to hear about it.

Flex Events – Again

OK I am having some troubles with FLEX events, so being me I decide to write a little project to start to understand them on a smaller scale before throwing them into our huge application. But I wanted to mimic the same “structure” that we have in the application.

Here is the current Structure

So I built the play application similar to this one. I basically wanted to have the Map be notified when the state drop down was changed in any of the Search Types.

I created each of the items above as components with the Search Type having a combo box in it with values. We will call this the SearchTypeComponent.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" >
    <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;
      import events.SearchStateChangeEvent;
   
      [Bindable]
            public var States:ArrayCollection = new ArrayCollection(
                [ {label:"Alaska", data:"AL"},
                  {label:"Arizona", data:"AZ"},
                  {label:"Colorado", data:"CO"} ]);
   
    ]]>
  </mx:Script>

  <mx:ComboBox id="stateCombo" x="45" y="64"
    prompt="Please select a State..."
          dataProvider="{States}"
            />

  <mx:Text x="45" y="130" text="" id="textFld"/>
</mx:Canvas>

Not wanting to complicate the application with all of the map pieces, I created it as a component with a couple of text fields in it. For sake of simplification we will call this the DetailResultsComponent

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300" >
  <mx:Text x="57" y="13" text="Text" width="98" id="state"/>
  <mx:Text x="57" y="65" text="Text" width="98" id="city"/>
  <mx:Label x="10" y="13" text="State:"/>
  <mx:Label x="10" y="65" text="City:"/>
</mx:Canvas>

Now for the actual event I built an event class similar to the one I would need in my application

  import flash.events.Event;
  public class SearchStateChangeEvent extends Event
  {
    public static const SEARCH_STATE_CHANGE_EVENT:String = "searchStateChangeEvent";
 
    public var stateCd:String;
    public var stateName:String;
 
    public function SearchStateChangeEvent(stateCd:String, stateName:String)
    {
      super(SEARCH_STATE_CHANGE_EVENT);
      this.stateCd = stateCd;
      this.stateName = stateName;
    }
  }

Overview of what I did about. I created a basic event class that extends flash.events.Event. Let’s go over the basics of the SearchStateChangeEvent class. I created a public static const because you will need this when you add an event listener, which we will go over a bit later.

The constructor for the an event looks like this public function eventName(type:String, bubbles:Boolean=false, cancelable:Boolean=false). However, mine looks different than that. The reason is that because cancelable and bubbles have a default I do not need to pass them in. I do however; need to pass in a couple of parameters so they are in the constructor. I am calling super passing in the event name and since the other items (bubbles, and cancelable) default to false I am not passing them in.

The basic setup has been completed; from here I will go back and edit the two components. First the pitcher component, we will need to update to fire off the SearchStateChangeEvent event. The first thing we want to do is add a change property to the ComboBox.

<mx:ComboBox id="stateCombo" x="45" y="64"
    prompt="Please select a State..."
          dataProvider="{States}"
            change="onChange(event)" />

The change will call onChange method passing it the event. So now we will want to create a function to intercept the event.

      private function onChange(event:Event):void
      {
        var searchEvent:SearchStateChangeEvent = new SearchStateChangeEvent(ComboBox(event.target).selectedItem.label,
          ComboBox(event.target).selectedItem.data);
        dispatchEvent(searchEvent);
      }

The method above will create an instance of the SearchStateChangeEvent and pass in the Label and Data from the combo box to the constructor. This conforms to the constructor we created, normally we would also have the bubbles and cancelable Booleans; but as we discussed earlier we are not using them. We then will need to dispatch the event by calling the component’s dispatchEvent. According to Adobe LiveDocs all components that extend the UIComponent have this method.

The syntax for the dispatchEvent() method is as follows:

objectInstancedispatchEvent(event:Event):Boolean

Now for the DetailResultsComponent we will need to update this to “catch” the event and perform any action that we want based on this event. First we will need to set the creationComplete on the component. I have put in creationComplete=”init()” this will call the init function.

private function init():void
{
   addEventListener(SearchStateChangeEvent.SEARCH_STATE_CHANGE_EVENT, handleEvent);
}

Here we use the addEventListener the function signature is

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

When we create it we will pass in the event name, I use the static constant that was declared in the SearchStateChangeEvent earlier and a function name that will be called when this event is fired off.

private function handleEvent(event:SearchStateChangeEvent):void
{
   state.text = event.stateCd;
   city.text = event.stateName;
}

I called this function handleEvent and the parameter is the event we created earlier SearchStateChangeEvent. This is a simple method that updates the two text fields on the screen with the values we placed inside the Event earlier.

After running this simple application it does not work correctly. WHAT! You went through all of this and it does not work. Yes that is correct as this is what I went through with learning a little about events in Flex.

So I started reading and realized that I needed to bubble up the event because the event when dispatched seems to dispatch to the component. I went back and hard coded the bubbles to true. So in the SearchStateChangeEvent I updated the call to the super to look like this now:

public function SearchStateChangeEvent(stateCd:String, stateName:String)
{
   super(SEARCH_STATE_CHANGE_EVENT, true);
   this.stateCd = stateCd;
   this.stateName = stateName;
}

So after running this again it did not work at all, which had me really frustrated so after a little reading and some trial and error. I figured out that the while the event is bubbling up the stack it does bubble across or down. With the DetailResultsComponent component we see it is at the same level as the SearchTypeComponent so when the event is dispatched the DetailResultsComponent never sees it. So when I call the addEventListener it is only looking inside that component, so what I need to do is get the event listener up to the same level where the event is at. Since this is simple I do not have any components inside of components so in this case I need to go up two levels. So in the DetailResultsComponent’s init function we will update it

private function init():void
{
   parent.parent.addEventListener(SearchStateChangeEvent.SEARCH_STATE_CHANGE_EVENT, handleEvent);
}

Now the listener will listen above this component and fire off the handleEvent function. After running the application again it runs perfectly. Hooray!!!!

Now when I put this same solution back into our big application it did not work, the reason was that I did not take into account the VBox and Canvas components.

This approach does not seem to be very clean as there is no decopling of the listener and the event. Since I have to know where my component is at relative to the event and then add the parent….addEventListener statement.

A possible solution to this that a coworker pointed out was to have a variable set in like a session and then a changewatcher placed on it but that is a story for another post.

I hope that this has been informative and helpful.

Converting PDFs for Flex

Well as many of you know Flex can not display a PDF so I you basically need to either create a SWF or an image. Because the project I am working on the PDFs are retrieved from the database as the user performs a search. I ran across PDF Renderer this pure java tool written in Java 1.5. This is the only downside as we are running WebSphere 6 which is Java 1.4. The source code was easily updated to remove the Annotations.

Beyond that we also did not want to write a single file to the file system so that is where the trick came into play. So based on research, trial and error I give you a converter from PDF to an ArrayList of byte arrays.

private static ArrayList convertImage(byte[] fileBytes) throws Exception {
  ArrayList images = new ArrayList();
  ByteBuffer buf = ByteBuffer.wrap(fileBytes);
  PDFFile pdffile = new PDFFile(buf);
  // draw the first page to an image
  int numberOfPages = pdffile.getNumPages();
  System.out.println("NUMBER OF PAGES:" + numberOfPages);
  for (int i = 0; i < numberOfPages; i++) {
    PDFPage page = pdffile.getPage(i);
    // get the width and height for the doc at the default zoom
    int width = (int) page.getBBox().getWidth();
    int height = (int) page.getBBox().getHeight();
    Rectangle rect = new Rectangle(0, 0, width, height);
    int rotation = page.getRotation();
    Rectangle rect1 = rect;
    if (rotation == 90 || rotation == 270)
      rect1 = new Rectangle(0, 0, rect.height, rect.width);
    // generate the image
    BufferedImage img = (BufferedImage) page.getImage(rect.width,
        rect.height, // width & height
        rect1, // clip rect
        null, // null for the ImageObserver
        true, // fill background with white
        true // block until drawing is done
        );
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    ImageIO.write(img, "png", output);
    images.add(output.toByteArray());
  }
  return images;
}

ANT for Flex Library

I am trying to build a flex library project that I can reuse in a couple of projects that we have. Hey this beats the normal let me copy this file over and such that I have been seeing. So I first of course copied over the files that were common removed anything not common and started doing the normal cleanup. Then I started working on the build script. So I created the normal ANT script items and a clean-up target. Then I started on my build target, first I realized that I need to read up on this since it is not the normal MXML compiler.

So after reading several items about COMPC I realize that I need to pass in a space delimited list of file names. For example: com.eric.util.Converter com.eric.util.Utils. At first I was like what you have to be kidding me there is no way, what if someone on the team adds or deletes and file and forget to do this what a maintenance nightmare. I thought this must be wrong so I dug a bit deeper and tried a trick or two with no luck at all. So I Googled and chanted a bit to which I found numerous sites referring to ANT tasks that look for file names and then create this. Hallelujah the heavens open up and all is right in the world. So after a bit of playing around here is what I came up with thanks to numerous sites and a guy at work.

<target name="-resolve-class-path" depends="clean">
    <path id="list_1">
      <fileset dir="${basedir}/src">
        <include name="**/**"/>
        <exclude name="**/.copyarea.db"/>
        <exclude name="**/**.bak"/>
        <exclude name="**/**.keep"/>
        <exclude name="**/**.contrib"/>
      </fileset>
    </path>
    <pathconvert property="project_classes_property" pathsep=" " dirsep="." refid="list_1">
      <map from="${basedir}/src/" to=""/>
      <mapper>
        <chainedmapper>
          <globmapper from="*.as" to="*"/>
        </chainedmapper>
        <chainedmapper>
          <globmapper from="*.mxml" to="*"/>
        </chainedmapper>
      </mapper>
    </pathconvert>
    <echo>
      ${project_classes_property}
    </echo>
  </target>
 
  <target name="compile" depends="clean,-resolve-class-path"">
    <compc output="${basedir}/CommonLibrary.swc" include-classes="${project_classes_property}">
      <source-path path-element="${flex-src.dir}"/>
      <compiler.include-libraries dir="${flex-libs.dir}" append="true">
        <include name="Cairngorm.swc"/>
        <include name="Degrafa_.2.11.swc"/>
        <include name="flexlib.swc"/>
      </compiler.include-libraries>
     
      <compiler.library-path dir="${flexsdk.dir}/frameworks" append="true">
        <include name="libs" />
      </compiler.library-path>
     
      <include-file name="BarLoader.swf" path="${flex-src.dir}/assets/swf/barLoader.swf"/>
      <include-file name="main.css" path="${flex-src.dir}/assets/css/Portal.css"/>
 
    </compc>
  </target>






The –resolve-class-path target basically looks in the src folder and gets a list of all the files minus a few of them that we do not need. It then strips off the .mxml and .as and also breaks it down to the package name without the src on it.







From there it is a normal build script.