Wednesday, April 17, 2013

Vaadin Charts add-on showing custom properties in tooltip hover

Recently I had to investigate if it is possible to show other data than the X and Y value when hovering over a stacked bar graph in the Vaadin Charts add-on. And yes it is possible!
Nowhere I could find an example on how to do this, so that's why I wrote this blogpost. Hope it helps some people :)

Setup:
- Vaadin 7.0.1
- Charts add-on 1.0.1. In version 1.0.0 you can't set the color of the stacked bars using PlotOptions and ContainerDataSeries. This version has a fix for that.
- Note: I had to manually modify some labels of the hover in the screenshot since I can't use the real data used in the project. Same goes for the code, did not check if it still compiles. Let me know if something essential is missing :) Oh yeah and this is all demo-code so no quality complaints please....

Goal:
- Be able to add a custom field to the hover. And even better: be able to add an array to the hover tooltip.

Here's a screenshot of what the goal was. Click on it for a larger image:



The code:
Notice the Grapes ok: 7 Total: 16 in the hover text. These are the standard x and y values you can show easily via:




        Tooltip tooltip = new Tooltip();
        tooltip.setFormatter("function() { return ''+ this.x +'"+ " '+ this.series.name +': '+ this.y 
+' '+'Total: '+ this.point.stackTotal;}");

        conf2.setTooltip(tooltip);



But also note the extra this.point.custom = 708. That's an example of adding a custom value. The tooltip code then looks like:




tooltip.setFormatter("function() {"return ''+ this.x +'"+ " '+this.series.name +': '+ this.y +' '+
'Total: '+ this.point.stackTotal + ' this.point.custom = ' + this.point.custom + "''"



And then below that line you see a set of table-like data: Quality 1: 2 Stored: 3 Interesting: 4. This is the data that comes from three arrays. The tooltip code then looks like this:




tooltip.setFormatter("function() { var qualityValuesArray = JSON.parse(this.point.qualities); " +
        "var storedValuesArray = JSON.parse(this.point.stored); " + 
        "var interestingValuesArray = JSON.parse(this.point.interesting); " + 
        "return ''+ this.x +'"+ " '+this.series.name +': '+ this.y +' '+
        'Total: '+ this.point.stackTotal + ' this.point.custom = ' + this.point.custom + " +
        "'
Quality 1: ' + qualityValuesArray[0]  + " + "'Stored: ' + storedValuesArray[0]  + " + "'Interesting: ' + interestingValuesArray[0]  + " +
        "'
Quality 2: ' + qualityValuesArray[1]  + " + "'Stored: ' + storedValuesArray[1]  + " + "'Interesting: ' + interestingValuesArray[1]  + " +
        "'
Quality 3: ' + qualityValuesArray[2]  + " + "'Stored: ' + storedValuesArray[2]  + " + "'Interesting: ' + interestingValuesArray[2]  + " +
        "'
Quality 4: ' + qualityValuesArray[3]  + " + "'Stored: ' + storedValuesArray[3]  + " + "'Interesting: ' + interestingValuesArray[3]  + " +
        "'
Quality 5: ' + qualityValuesArray[4]  + " + "'Stored: ' + storedValuesArray[4]  + " + "'Interesting: ' + interestingValuesArray[4]  + " +
        "'
Quality 6: ' + qualityValuesArray[5]  + " + "'Stored: ' + storedValuesArray[5]  + " + "'Interesting: ' + interestingValuesArray[5]  + " +
        "'
Quality 7: ' + qualityValuesArray[6]  + " + "'Stored: ' + storedValuesArray[6]  + " + "'Interesting: ' + interestingValuesArray[6]  + " +
        "'
Quality 8: ' + qualityValuesArray[7]  + " + "'Stored: ' + storedValuesArray[7]  + " + "'Interesting: ' + interestingValuesArray[7]  + " +
        "'.';}");



The span can also be replaced by a HTML b tag of course.
Too bad you can't use the setHTML() for better formatting, like putting in a HTML table tag. This is a known issue, see here.

Essential in constructing the data is to use the BeanItemContainer, ContainerDataSeries and the addAttributeToPropertyIdMapping() in which you can put custom class (bean) OrderChartItem:



 /**
  * Class with custom value and 3 arrays to be displayed in tooltip
  */
    public class OrderChartItem {

     private static final int NR_QUALITIES = 8;
     
     private final String name;
  private final int x;
  private final Number y;
  private final int someValue;
  
  private final Number[] quality = new Number[NR_QUALITIES];
  private final Number[] stored = new Number[NR_QUALITIES];
  private final Number[] interesting = new Number[NR_QUALITIES];

  public OrderChartItem(String name, int x, Number y, int someValue) {
   this.name = name;
   this.x = x;
   this.y = y;
   this.someValue = someValue;
   
   for (int i = 0; i < NR_QUALITIES; i++) {
    quality[i] = i + 2;
    stored[i] = i + 3;
    interesting[i] = i + 4;
   }
  }

  public String getName() {
   return name;
  }

  public int getX() {
   return x;
  }

  public Number getY() {
   return y;
  }

  public int getSomeValue() {
   return someValue;
  }

  public List getQualities() {
   return java.util.Arrays.asList(quality);
  }
  public List getStored() {
   return java.util.Arrays.asList(stored);
  }
  public List getInteresting() {
   return java.util.Arrays.asList(interesting);
  }
    }


I made the arrays the same size because of its table data, but that doesn't have to be of course.

The basic mechanism is:
  1. Set up a BeanItemContainer with values of OrderChartItem. Take special care when putting in 0 values. The graph then shows the number 0. To avoid that, put in 'null' as a value.

    
    
    BeanItemContainer containerGood = new BeanItemContainer(OrderChartItem.class);
    containerGood.addBean(new OrderChartItem("some name good", 1, null, 701));
    
    


     So the OrderChartItem has the properties that can be reached from the tooltip Javascript. Note the OrderChartItem just gets some name, later it is overwritten by setting the ContainerDataSeries names:

    
    
    seriesGood.setName("good");
    
    

  2. Then wrap each BeanItemContainer in a ContainerDataSeries:

    
    
    ContainerDataSeries seriesGood = new ContainerDataSeries(containerGood);
    
    

  3. Then add the custom properties for each container. First the one value:

    
    
    seriesGood.addAttributeToPropertyIdMapping("custom", "someValue");
    
    

    Then the arrays:
    
    
    seriesGood.addAttributeToPropertyIdMapping("qualities", "qualities");
    
    

  4. And add the series to the configuration:

    
    
    conf2.addSeries(seriesGood);
    
    


In summary: the OrderChartItem is used as data-provider by adding them to the ContainerDataSeries. The properties-mappings of the custom OrderChartItem are then added to the series, after which they are accessible in the tooltip Javascript. Note the "trick" of using JSON.parse() in the formatter and the List getQualities() to get the arrays in the correct format.

Full source code can be found here.
The widgetsets directory has been cleared out because of distribution issues.





Wednesday, February 27, 2013

Vaadin add-on Timeline vs Vaadin Charts add-on comparison


Introduction

For a recent project I had to evaluate the Vaadin Charts and Timeline add-ons for their capabilities.

Setup
- Vaadin 7.0.1
- Vaadin Charts 1.0.0
- Vaadin Timeline which is included in Vaadin Charts since Vaadin 7.0

Requirements
- Be able to see data for 90 days, and the same data but then per week (same graph, just other view).
- Be able to click on a bar and perform some action like retrieving other data based on the selected bar.
- Customizable three code coloring stacked bars.
- Display more details when hovering over a bar.


Comparison

Timeline

This type of graph is very flexible and elaborate in the ways it can display data. It has a "selection bar" below the actual graph so you can determine the values being displayed in the graph above it. See below for a screenshot:



You can try it out yourself in an online demo here and here.

Pros

- The graph is scrollable thus no worries about the bars/lines getting too close to each-other.
- You can zoom in and out, also with your mouse.
- Different charts (graph modes) provided by default, changeable in one click: line, bar and scatter.
- A quick zoom per period (1d, 5d, 1w, 5m etc).

Cons

- Can't attach any action to clicking on a bar. What you can do is react on the area selected with the selection bar, so a work-around might be to have the user select exactly one bar to mimic a kind of "clicking" on that bar. And then take the appropriate action.
- You can only show days on the x-axis it seems. You can't show a bar per week for example (thus one bar representing 1 week). A work-around might be to create your own Zoom period for 1 week, which is quite easy to do.
- Currently as of this writing there are at least two bugs regarding hovering: the timeline moves down a few pixels when hovering for the first time, and the stacked bars have a hovering problem.


Untested

- Can you also add an hover-over tooltip to the bars?


Chart
This type of graph does not have the fancy zooming possibilities, but has more possibilities regarding customization and reacting to events. See below screenshot for an example:


You can try it out yourself here.

Pros

- The bars are clickable and that event can be handled, indicating the x and y of the item clicked.
- The graph is more customizable; for example the numbers in the bars can be removed.
- Different values (like week number) on the x-axis is probably possible (still out for investigating).
- All data is always visible in the current view.
- Customizable hover-over tooltip.
- Does not have the two (smaller) timeline bugs.

Cons

- No horizontal scrollbar or similar, thus for example showing 90 days looks quite "cramped", see the above screenshot. When making the browser smaller, day numbers start to overlap. Do-able, but not optimal. A horizontal scrollbar would be great!
- No space for showing a full date at the bottom. As a work-around the actual date could be added to the tooltip when hovering over a bar (in the screenshot it only says 26).
- No zooming.
- No out-of-the-box other graph modes (i.e like in the Timeline those are provided with it always).


Conclusion

For the project we chose the chart because it is a bit more customizable and the ability to click on a bar and do something with that event was most important requirement.


What's crap about my new Dell Precision M4700 laptop (+ the few good things)

Just got my new Dell Precision M4700 laptop in, which is the top model of their range for 15" screens.
My last laptop was also a Dell Precision, the M4400. Having looked around to see if there's another brand I'd rather take, I still came to the conclusion that a Dell seems to be the best fit for heavy development.

So online I ordered it, with changing the default low 4G or 8G RAM to a more reasonable 16G. That's the first place where I noticed they are really overcharging for the additional RAM: 200 euro (about 261 dollars) for having put in 16G of RAM, while if you buy it seperately it's only about 100 euro. But since I don't like messing around with a brand new laptop (mainly because of warranty) I decided to pay the extra.

Here's a list of pros and cons of the laptop after using it for a few weeks:

Pros
- The power plug is straight, so it fits better in a block of power plugs, see the image below:


- It feels sturdy and solid.


Cons
- The power cord is still quite short. Why not just add 1 meter more?
- The plug that goes into the laptop is straight and at the back. Lots of times when you've got the laptop on your lap it will just fall out. Much better solution: an angled plug and plug it in on the side of the laptop.
- The keyboard has a numeric keypad. Why would you need that on a laptop? How often will data entry people use such a high end laptop? And it forces me to sit more to the left of the keyboard to be able to type... And I know I'll never ever use that numeric keypad... See image below:


- The Page Up and Page Down are placed at such a weird position. And it feels like they should be the other way around anyway: Page Down left, Page Up right...


- Right after I started it up for the very first time, I wanted to search in the Windows configuration screen. The whole machine just froze, I couldn't do anything else but hard-shutdown the machine via the power button. Ok this might be a Windows problem but still it shouldn't happen within 5 minutes...


- It's really hard to turn off the built-in webcam. Out of the box it will switch on automatically if a video stream comes in (or something like that). This should be the other way around by default. You can only turn it really off via system devices, not via the annoying pre-installed webcam control app.

- For creating a VMWare image of the same Windows 7 Professional OS as on this new laptop, you have to enter the Windows COA product key. And guess where they put it on the laptop? No not on the side or the bottom..... it is inside the battery compartment!! So when you're right in the middle of installation, you have to shutdown the laptop, take out the battery, write down the long key, put the battery in, start it all up again.... Djeezzz!!

- Multiple times I've had now that I put a VMWare guest in suspend-mode and that after that the light of the harddisk stays on "forever". I can hear it spin too. Even if after that I close the VMWare application, the harddisk keeps on going. When after that I put the laptop to sleep via the power button, it stops spinning. When I then turn it on again, the harddisk directly starts spinning again. In Windows Task Manager I can't find any process that is supposed to be reading or writing. So what is going on? Who is reading and/or writing? Is the disk crappy? After running diagnostics (during bootup) no problems are found. Is VMWare causing it? I can't reproduce it everytime, so can't really make a support call for it. But all 'n all it doesn't give me much confidence in the machine + setup combinatino.... I'm planning on re-installing the whole OS, so no Dell Recovery manager and other Dell software is on it anymore. Hope that makes it more stable...


Well, that about sums up this "rant".... Next time I'll definitely re-consider whether I should purchase a Dell again....







Saturday, February 2, 2013

Lessons learned Spring 3.0 project

Another quick post with some bullet points of lessons learned during my last Spring 3.0 project.
Tools used were:

  • Spring 3.0 (3.1.2 when moving to Hibernate 4)
  • Spring MVC
  • Spring WebFlow 2
  • Spring Batch
  • Spring Agent Framework
  • Hibernate 3.2.6
  • Apache CXF
  • JBehave (Behavior Driven Development)
  • Tiny bit of GXT, which is a Google Web Toolkit extension based on GWT and ExtJS technology. Formally known as Ext GWT, GXT is a Java library for building rich internet applications with the Google Web Toolkit (GWT)
  • JBoss jBPM 5.2.0
  • JBoss Drools 5.3.1
  • Jenkins for CI
  • Crucible for code reviews
  • Jira for issue tracking en sprint user stories and tasks and progress tracking
  • SpringSource Tool Suite 2.9.1 as Eclipse based IDE
  • JUnit 4.8
  • EasyMock 2.5.2, EasyMockSupport
  • Java 6
  • Cargo-itest (introduction here) for integration testing
  • Tomcat 6
  • Oracle SQL Developer (free version)
Besides learning new tools like JBehave an Cargo-itest, below are some things picked up using above tools.

Spring MVC
Had some issues getting REST-like services available, mainly from inexperience, but good to know what's working and what not:

    @GET
    @Path("some-path/?role={roleId}")
    Response getSomeOtherUrlParams(@PathParam(value = "roleId") final String roleId);
    // Unable to call it, because PathParam is not existing (it's not really part of the path)

    @GET
    @Path("some-path2/role/{roleId}")
    Response getSomeOtherUrlParamsNotAsRequest(@PathParam(value = "roleId") final String roleId);
    // Works

    @GET
    @Path("some-path3/")
    Response getSomeOtherUrlParamsAsQueryParam(@QueryParam("role") final String roleId);
    // Works, will have clients of this service (like SoapUI) already generate a ?role= parameter

    @GET
    @Path("some-path4/")
    Response getSomeOtherUrlParamsAsRequestParam(@RequestParam("role") final String roleId);
    // Won't generate a ?role= parameter for clients, the WADL also looks different for this method/parameter

Don't use @FormParam for submitting XML because if the mediatype is text/xml for example, the mapping on the REST method fails because JAXRS expects HTML (default if not specified at the service definition).
So suppose the service is defined as:

    @POST
    @Path("message/{messageCode}/send")
    Response sendMessage(@PathParam(value = "messageCode") final String messageCode, 
                                         @FormParam("moduleName") String moduleName,
                                         @FormParam("userId") String userId, 
                                         final MessageContentsRequest messageContents);

When invoking the above method by POSTing to 

http://localhost:8080/webservice/v1/message/SECRET_MESSAGE_CODE/send 

with as POST body parameters moduleName and userId + the MessageContentsRequest XML, that gives the following error in the log:

2013-01-05 11:24:38,491 WARN  [http-8890-1] JAXRSUtils#processFormParam - An application/x-www-form-urlencoded form request is expected but the request media type is text/xml;charset=UTF-8. Consider removing @FormParam annotations.
2013-01-05 11:24:38,493 WARN  [http-8890-1] WebApplicationExceptionMapper#toResponse - WebApplicationException has been caught : no cause is available

The same error occurs when invoking: ..../send/?moduleName=abc&userId=ttl  (so adding them as POST URL name/value parameters).

So make sure you use in that case:

    @POST
    @Path("message/{messageCode}/send")
    Response sendMessage(@PathParam(value = "messageCode") final String message ode, 
                                         @QueryParam("moduleName") String moduleName,
                                         @QueryParam("userId") String userId, 
                                         final MessageContentsRequest messageContents);

The moduleName and userId can then be passed in via the POST URL name/value parameters.


EasyMock
Use replayAll() and verifyAll() instead of replay(mock) and verify(mock) for each mock seperately. Requires extending EasyMockSupport.
 


SQL Developer
The free SQL Developer can't export clob column values. Nor can it import clob values larger than 4K.




 

Saturday, January 12, 2013

Got my Kickstarter BERO remote controlled robot in

Last year I funded one of the BERO robots via Kickstarter. And last week the matte finish black Basshead arrived! This is wat it finally looks like:

Quite a sturdy little robot, remote controllable via an Android and iOS app. Biggest challenge was to switch it on! In the supplied instructions it said to turn it on and off, but I just couldn't find the on/off switch! Almost sent out a question for this to the support, but then I found it! Below a picture, should you come across the same problem.
And some Android app screenshots with which you can control the Bero: Splash screen
Home screen
Control screen to let Bero react (dance) to sound/music
Eight programmable modules for its movement/lights/sound
So, quite funky!

Wednesday, October 24, 2012

How to remote debug PL/SQL with Oracle SQL Developer

There are quite a few posts (see the References section at the bottom) on how to debug PL/SQL remotely. That is when you want to step through another session that is running some PL/SQL procedure. Still I didn't find it obvious to get it working. Mainly because none of the blog posts have a diagram on how all components are connected and which component tries to connect with the other component(s). Therefore this post, including..... a diagram! :)

Setup
- on a Windows 7 desktop PC running SQL developer with IP xxx.yyy.19.84
- remote database running in VM with IP xxx.yyy.19.104. This one actually is running on the above desktop machine, but that should not change much if it would be on a separate machine, except there might be some firewall(s) in between.

In short this is what we are trying to achieve:


  1. Start up the remote debug listener on port 4000 on the desktop machine
  2. Start up SQl*Plus connecting to the remote database
  3. Connect to the remote debug listener from the database. This might be the tricky part for some: SQL*Plus is connected to the remote database, so the DBMS_DEBUG_JDWP.CONNECT_TCP call is executed from that database! So that machine (.104) needs to be able to get to the machine *.84) with the remote debug listener listening on port 4000
  4. Execute the stored procedure from the package you want to debug and SQL Developer will stop at the set breakpoints

Detailed steps
  1. As mentioned in all the referenced blog posts, right-click on the connection and select Remote Debug....
  2. In that popup enter:

    If done correctly, you should see something like:

    If you get a message saying "The debugger is not able to listen for JPDA using the specified parameters." then there is something wrong with the parameters you entered. Yes that's all I could figure out too... Potentially you entered the wrong Local address or maybe there's already something listening on the specified port.
    Note that the Local address is the IP of the machine SQL Developer is running on. Unless your database is running on that same machine, you can't use 127.0.0.1 (localhost). You have to use the full IP address.
  3. Since the database (which is on xxx.yyy.19.104) needs to connect to the SQL Developer remote debugger listener, it must be able to get to that machine (xxx.yyy.19.84). You can test this by trying to telnet to it and the port the listener is listening on from the .104 machine:
    
    
    $ telnet xxx.yyy.19.84 4000
    Trying xxx.yyy.19.84...
    Connected to MyPC (xxx.yyy.19.84).
    Escape character is '^]'.
    JDWP-Handshake
    ^]quit
    
    

    Look for the JDWP-Handshake string. If you get that, you know it can get to the remote debug listener on the .84 machine. Also note that when you quit the telnet session, the listener is stopped, so make sure to start it again!
  4. Start up an SQL*Plus session from the .84 machine to the remote database. For example:
    
    
    sqlplus user/passwd@xxx.yyy.19.104/oracle
    
    

  5. Connect to the remote lister on the .84 machine:
    
    
    SQL> set serveroutput on;
    SQL> execute DBMS_DEBUG_JDWP.CONNECT_TCP('xxx.yyy.19.84',4000);
    
    

    Note it is the .84 machine and of course port 4000 where the remote debugger is listening on.
  6. In SQL Developer, set a breakpoint in a procedure you want to debug, e.g test_me. Tip: as a first try, set it at the first line of code in the method test_me, then you know for sure that if it gets called, it should stop there definitely.
  7. Now call that procedure from the SQL*Plus commandline, e.g:
    
    
    DECLARE
      P_ANR VARCHAR2(25);
      P_RESULT VARCHAR2(4000);
    BEGIN
      P_ANR := 666;
    
      SOME_PCK.test_me(
        P_ANR => P_ANR,
        P_RESULT => P_RESULT
      );
      DBMS_OUTPUT.PUT_LINE('P_RESULT = ' || P_RESULT);
    END;
    /
    
    

    Note the test_me method has an IN and an OUT parameter.
  8. Your SQL Developer should now stop in the breakpoint you've set, see below SQL Developer screenshot of the Remote Debug session log window:


Remarks
I did not seem to need to run:


GRANT DEBUG CONNECT SESSION TO some_user;
GRANT DEBUG ANY PROCEDURE TO some_user;
/



You might still need to execute these commands if you get the permission errors you see in Step 5 here.

If you have a firewall on the .84 machine or between the two machines, you might need it to allow port 4000 to be accessed from the (other) DB machine...

References
Using SQL Developer to debug your anonymous PL/SQL blocks
Remote debugging with SQL Developer revisited
Application Express Community - Remote debugging
Sue's Blog... again... - Remote debugging with SQL Developer
Barry McGillin - Remote debugging with SQL Developer
Debug ApEx App with SQL Developer
Use Oracle SQL Developer to aid Oracle Application Express development
OTN Discussion Forums - Remote Debugging

Wednesday, October 17, 2012

Lessons learned Seam 2.2 project

Quick post with some bullet points of lessons learned during my last (and first) Seam project:

  • Seam 2.2
  • Hibernate 3.3.1
  • JEE 5
  • EJB 3.0
  • JSF 1.2
  • Richfaces 3.3
  • JBoss 5.1
  • Drools 5
  • SQLServer 2008
  • MySql 5.x
  • TestNG
  • Hudson
Seam
- To have a navigation for a method with a parameter like exportSelected(String value): see Seam navigation based on a function with parameters
- If your Seam app keeps re-deploying (restarting) when using JBoss within Eclipse: delete all files that end with 'dia' in your WEB-INF dir. See: Seam keeps redeploying For example, I modified pages.xml, which apparently created a pagesdia (or similar) file... after removing that one, it worked fine again.

Hibernate
- To see which validator fails on a persist():


    try {
        entityManager.persist(verbinding);
    } catch (InvalidStateException e) {     
        for (InvalidValue invalidValue : e.getInvalidValues()) {         
            System.err.println("--------------> create(): exception Instance " +
               "of bean class: " + 
               invalidValue.getBeanClass().getSimpleName() +                  
               " has an invalid property: " + invalidValue.getPropertyName() +
               " with message: " + invalidValue.getMessage());     
        } 
	throw new RuntimeException(e);
    }




MySql
- To see data in better format in MySQL: show engine innodb status\G (so add the \G to a query)

Hibernate/JPA
- NamedQueries are loaded and parsed at startup time, so that's an advantage above em.createQuery() which are only parsed and evaluated at runtime. So with NamedQueries you get the errors sooner.

Drools
To solve this error in Drools decision table .XLS spreadsheet:


   [testng] DEBUG [test.service.drools.DroolsHandling] getKnowledgeBase: getting path info from settings service
   [testng] DEBUG [test.service.drools.DroolsHandling] getting test.service.drools.DroolsHandling ruletable file: HandlingModelTest.xls
   [testng] DEBUG [test.service.drools.DroolsHandling] getKnowledgeBase: Trying to open a File
   [testng] WARN  [jxl.read.biff.NameRecord] Cannot read name ranges for Excel_BuiltIn__FilterDatabase_1 - setting to empty
   [testng] WARN  [test.service.drools.DroolsHandling] There are errors in the decision table file
   [testng] WARN  [test.service.drools.DroolsHandling] Decision table error: message=[ERR 102] Line 9:16 mismatched input '"DroolsHandling6"' expecting ']' in rule "DroolsData_12" in pattern stringDataset
   [testng] WARN  [test.service.drools.DroolsHandling]     line: 9
   [testng] WARN  [test.service.drools.DroolsHandling] Decision table error: message=[ERR 102] Line 9:35 mismatched input '"Prefab"' expecting ']' in rule "DroolsData_12" in pattern stringDataset
   [testng] WARN  [test.service.drools.DroolsHandling]     line: 9
   [testng] WARN  [test.service.drools.DroolsHandling] Decision table error: message=[ERR 102] Line 22:16 mismatched input '"DroolsHandling6"' expecting ']' in rule "DroolsData_12" in rule "DroolsData_13" in pattern stringDataset
   [testng] WARN  [test.service.drools.DroolsHandling]     line: 22



Make sure your definition has all the cells merged that contain a condition! For example, check the red arrow pointing at the border of the cells between G9 and H9.
The last cell for the condition Prefab is not merged (i.e one cell) with all the other conditions. Here's now how it should be: see again the red arrow, there's no cell separation anymore, all condition columns are now merged into 1 cell.


- A space in a condition in a decision spreadsheet can cause a non-match! E.g GATE VALVE is not matched. Fixed it by always replacing a ' ' with an '_'.

Sunday, May 20, 2012

BlackBerry Playbook Tablet for Android porting

Houston, we got it in the mail: a free RIM Blackberry Playbook Tablet because I submitted on time an Android app to the BlackBerry App World. The Android app runs within the Playbook Android emulator (yes so the app is native Android! Pretty cool I'd say!

Booting
Below a few bootup screenshots:

The bootup time for the device is quite long, definitely longer than the Samsung Galaxy Tab 10.1 for example.

Home-screen and taskmanager
This is what the home-screen looks like:
This is what the taskmanager looks like:
The way to go back to the home-screen or switch to another app is by swiping from the button of the screen up.

The simpel app running
And the app runs fine on the real device too :) Those Android figures are also checking it out as you can see...
Those four buddies are called: Don Pablo Calaveroid, Longevity, Fortune and Blessing. The last three were released because of the chinese Year of the Dragon. Too bad they sent one with still the USA power plug attached to it. Luckily I had a converter (as the globetrotter I am ;)...
This is how the tablet 7" screen compares to the Samsung 10.1 (note both screens are very clear, the picture is only trying to show the difference in size of 10" vs 7"):
Tetris just runs fine on it (but that's a native app), the screen is very clear:


Some generic feedback:
  • The tablet smells rubbery because it has rubber on the back. Probably done as anti-slip, but even your fingers start to smell like it.
  • A bit annoying was that you have to watch the Basics tutorials when doing the setup.
  • Like the virtual keyboard, feels like lot less typos than similar sized touch screens


Porting
During converting the app to the PlayBook Android 2.3.3 or higher runtime, I ran into a few issues:
  • For emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, emailBody) statements needed to add .toString() to emailBody because otherwise you get an exception telling that EXTRA_TEXT is not a String.
  • After each re-install of the app on the emulator, nothing seems to be remembered of the preferences. E.g had to accept the EULA each time after a new deploy, while this does not happen on the "regular" Android emulator. Also works fine on the real Playbook device.
  • In my app the user can swipe left to right and vice versa to browse through tips. On the Playbook emulator the text on bottom of the screen was not always correctly updated. It was lagging behind.
  • When trying to open the browser with an Intent and URL in the simulator, it says 'No network connection'. Strange, the pre-installed browser on the home screen works just fine... Seems similar to this reported issue.

Thursday, April 12, 2012

JBoss exception Transaction is not active: javax.transaction.RollbackException: The transaction is not active!

Sometimes you get this exception when using JBoss (5.1.0 and Seam 2.2 in my case):



14:08:17,312 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TransactionReaper_18] - TransactionReaper::check timeout for TX -3f57fd63:6ae:4f5df31e:b7in state RUN
14:08:17,312 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.BasicAction_58] - Abort of action id -3f57fd63:6ae:4f5df31e:b7 invoked while multiple threads active within it.
14:08:17,312 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.CheckedAction_2] - CheckedAction::check - atomic action -3f57fd63:6ae:4f5df31e:b7 aborting with 1 threads active!
14:08:17,343 WARN [JDBCExceptionReporter] SQL Error: 0, SQLState: null
14:08:17,343 ERROR [JDBCExceptionReporter] Transaction is not active: tx=TransactionImple < ac, BasicAction: -3f57fd63:6ae:4f5df31e:b7
status: ActionStatus.ABORTING >; - nested throwable: (javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: -3f57fd63:6ae:4f5df31e:b7 status: ActionStatus.ABORTING >)
14:08:17,359 ERROR [TxPolicy] javax.ejb.EJBTransactionRolledbackException: org.hibernate.exception.GenericJDBCException: Cannot open connection
14:08:17,375 ERROR [TxPolicy] javax.ejb.EJBTransactionRolledbackException: org.hibernate.exception.GenericJDBCException: Cannot open connection
14:08:17,453 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TransactionReaper_7] - TransactionReaper::doCancellations worker Thread[Thread-10,5,jboss] successfully canceled TX -3f57fd63:6ae:4f5df31e:b7
14:08:17,500 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.BasicAction_40] - Abort called on already aborted atomic action -3f57fd63:6ae:4f5df31e:b7
14:08:17,515 ERROR [AsynchronousExceptionHandler] Exception thrown whilst executing asynchronous call javax.ejb.EJBTransactionRolledbackException: Transaction rolled back at org.jboss.ejb3.tx.Ejb3TxPolicy.handleEndTransactionException(Ejb3TxPolicy.java:54)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:175)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.tx.NullInterceptor.invoke(NullInterceptor.java:42)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.security.RoleBasedAuthorizationInterceptorv2.invoke(RoleBasedAuthorizationInterceptorv2.java:201)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.security.Ejb3AuthenticationInterceptorv2.invoke(Ejb3AuthenticationInterceptorv2.java:186)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:41)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.BlockContainerShutdownInterceptor.invoke(BlockContainerShutdownInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.aspects.currentinvocation.CurrentInvocationInterceptor.invoke(CurrentInvocationInterceptor.java:67)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:176)
at org.jboss.ejb3.session.SessionSpecContainer.invoke(SessionSpecContainer.java:216)
at
org.jboss.ejb3.proxy.impl.handler.session.SessionProxyInvocationHandlerBase.invoke(SessionProxyInvocationHandlerBase.java:207)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22)
at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32)
at org.jboss.seam.intercept.ClientSideInterceptor$1.proceed(ClientSideInterceptor.java:76)
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
at org.jboss.seam.async.AsynchronousInterceptor.aroundInvoke(AsynchronousInterceptor.java:52)
at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.seam.util.Reflections.invoke(Reflections.java:22)
at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:144)
at org.jboss.seam.async.AsynchronousInvocation$1.process(AsynchronousInvocation.java:62)
at org.jboss.seam.async.Asynchronous$ContextualAsynchronousRequest.run(Asynchronous.java:80)
at org.jboss.seam.async.AsynchronousInvocation.execute(AsynchronousInvocation.java:44)
at org.jboss.seam.async.QuartzDispatcher$QuartzJob.execute(QuartzDispatcher.java:243)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:529)
Caused by: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.inactive]
[com.arjuna.ats.internal.jta.transaction.arjunacore.inactive] The transaction is not active! at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1414)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:137)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:170)
... 47 more



For 99% sure this is caused by a timeout. Unfortunately you can't immediately see that from the exception.

The fix
Increase the timeout in transaction-jboss-beans.xml in your JBoss deploy dir. For example if you have JBoss installed in:

C:\jboss-5.1.0.GA\server\default\deploy


then open transaction-jboss-beans.xml and set the field transactionTimeout much higher. E.g at 3000 (default is 300).
In older JBoss version this setting used to be in default/conf/jboss-server.xml, see here.
The official documentation can be found here.

Saturday, April 7, 2012

Why cancel-button now also first on Android?

Just wondering about this big time...

Why is Android switching the standard buttons order for Android 4.0 and higher? See for example this screenshot, the cancel button is now the first button!
I was always taught that what the user most likely wants to do should be first, and so the dismissive button last.
And Cancel is usually not what to user wants to do!

Apple is doing it also in their iOS, is Android now just plainly copying it?
Definitely prefer Cancel at the end, (western) reading occurs from left to right, so now one always has to read/skip the dismissive button!

From the expert the conclusion is just to be consistent. That means at least within the Android platform it is not consistent between pre 4.0 and 4.0+... I think an unneeded and unnecessary change.