Monday 17 September 2012

Ant Contrib Try/Catch magic! How to Print Exception Messages in a Catch Block

Hello Readers!

This post will cover how to print exception messages in ant using means provided by ant-contrib.  Apologies for the terrible code formatting..  Will get around to fixing it!


The following examples assume you have antcontrib imported into your build file etc.  Here's a silly example of where you might want to use a try catch block; you're zipping up a folder and want to handle any problems that might occur in doing so:

<target name="try.catch.test" >
    <sequential> 
        <antc:trycatch>
            <try>
                <zip destfile="testzip.zip" basedir="testzipdir"/>
            </try>
            <catch> </catch>
        </antc:trycatch>
    </sequential>
</target>
If say, the "testzipdir" folder does not exist, the code above will swallow the exception and allow the build file to continue execution.  Perhaps we want to print this exception out instead.  To do this we need to specify the ant object that the exception will be stored in, then reference this exception and print it out in the catch block.  To specify the exception object we can add the "reference" attribute to the trycatch element e.g.
<antc:trycatch reference="exception">.
In the catch block, we can create a property that references this exception object and echo that out, e.g.
<catch>
    <property name="exceptionprop" refid="exception" />
    <echo>Exception: ${exceptionprop}</echo>
</catch>




as the antcontrib trycatch documentation seems to suggest.  However using a property to store exceptions is pretty inflexible.  What if your try/catch block is inside a for loop?  Once a property is set, it can't be set again, so if more than one exception occurs the exception message becomes useless.

Luckily, you can pull out the String value of objects referenced in ant using the ${toString:} syntax.  In our case, "${toString:exception}" would call the toString method of whatever object is referenced by "exception".  Our catch block becomes:

<catch>
    <echo>Exception: ${toString:exception}</echo>
</catch>
Putting this all together, the following example loops through all directories specified by the "dir.list" property, and attempts to zip them up.  If any of the listed directories do not exist, the zipping fails and an exception is echoed out.




<target name="try.catch.test"> 
  <sequential>
   <antc:for list="${dir.list}" param="dir">
    <sequential>
     <antc:trycatch reference="exception">
      <try>
       <zip basedir="@{dir}" destfile="@{dir}.zip">
      </zip></try>
      <catch>
       <echo>Exception: ${toString:exception}</echo>
      </catch>
     </antc:trycatch>
    </sequential>
   </antc:for>
  </sequential>
 </target>






Calling this target using ' ant try.catch.test -Ddir.list="bleh,build,Test" ' where directories "build" and "Test" exist but "bleh" does not, will result in the following output:





try.catch.test:
[echo] Exception: C:\Work\build.xml:118: C:\Work\bleh not found.
[zip] Building zip: C:\Work\build.zip 
[zip] Building zip: C:\Work\Test.zip




Hope you've found this useful!

Sunday 5 August 2012

Handy use of Oracle Metadata

Need to run an sql statement on multiple tables in your database?  Nauseous about having to copy/modify/paste/run again and again?  Using an Oracle database?!  Well perhaps the following will help to significantly mitigate your woes.

The idea is to use Oracle Metadata to select the tables of interest inside a string containing the SQL you wish to run.  The output of this query will be the list of SQL statements that you otherwise would have had to painstakingly construct by means of copy/pasting.  You can then copy this output, paste it back into sqldeveloper, hit run and kick back.

Consider the following example.  I wish to grant Select permissions on every table under my user name to another user:

  1. Run the following:
    • SELECT 'GRANT SELECT ON ' || TABLE_NAME || ' TO Other_User;' FROM USER_TABLES;
    • "Other_User" is the name of the database you wish to grant select permissions to.
  2. Copy the output of the above run into SQLDeveloper and hit run again.
Simple and useful.  Cheers to Renae Carr for the example.

Sunday 24 June 2012

Jasper Report Server - Hyperlinks to Subreports!

Dearest potentially non-existent readers,

My first post here will be a small note on how to configure Jasper Reports running on Jasper Report Server to contain hyperlinks to subreports.  This may seem simple and intuitive but it really isn't.  I've witnessed a lot of confusion and red-herring chasing on the net about this so I figured it's worth writing a rough set of instructions for how to do this.  Here it is:

Sub Report

  1. In Jasper Reports Server, Create a separate Jasper Report for the subreport of choice.
  2. Create an Input Control that matches every parameter you expect to be passed to the subreport through the hyperlink.

Parent Report

  1. Right click on a text field of choice and select 'Hyperlink'.
  2. Set 'Hyperlink target' to "Self".
  3. Set 'Hyperlink type' to "ReportExecution".
  4. Click on 'Link parameters'. 
    1. Create a report parameter called '_report'. 
    2. Set its expression to a repository location using the "repo:" syntax.  This part is strange.. it seems the url you provide here should be relative to two parent directories above the current report... e.g. for parent report  at "/organizations/organization1/reports/parent", subreport at "/organizations/organization1/reports/subreport", set '_report' parameter to "repo:/reports/subreport" (with quotes).
  5. Set all the report parameters required.  Ensure that the names of these parameters match the parameter names of the Input Controls defined for the sub report.
  6. Upload the report to Jasper Server
The way I trial and error'd my way through figuring out what to set for the '_report' parameter was to view the hyperlink created in the parent report (using firebug) and copy its value into a text file, then open the subreport by itself and copy its url into a text file.  Observing the &reportUnit parameter:



 URL:  
  &reportUnit=%2Forganizations%2Forganization1%2Freports%2Fsubreport  
 Hyperlink:  
  &reportUnit=repo%3A%2Forganizations%2Forganization1%2Freports%2Fsubreport  

.. it became clear that tweaking the "_report" parameter until the 'reportUnit' parameters were identical (save for the "repo:" prefix in the hyperlink) made for a working hyperlink.
For your reference, the error you get when clicking on a hyperlink that isn't correctly set is the following:
 java.lang.NullPointerException at   
 com.jaspersoft.jasperserver.war.action.ResourceTypeMappingAction.doPreExecute(ResourceTypeMappingAction  
 .java:53) at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:186) at   
 org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51) at   
 org.springframework.webflow.action.EvaluateAction.doExecute(EvaluateAction.java:79) at   
 org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188) at   
 org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145) at   
 org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51) at   
 org.springframework.webflow.engine.ActionState.doEnter(ActionState.java:101) at   
 org.springframework.webflow.engine.State.enter(State.java:194) at   
 org.springframework.webflow.engine.Flow.start(Flow.java:535) at   
 org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:364) at   
 org.springframework.webflow.engine.impl.RequestControlContextImpl.start(RequestControlContextImpl.java:234)   
 at org.springframework.webflow.engine.SubflowState.doEnter(SubflowState.java:101) at   
 org.springframework.webflow.engine.State.enter(State.java:194) at   


Also, it's worth noting that it isn't possible to pass parameters of any type other than those defined by the Input Controls in the subreport :(.  Perhaps there's a way around this?  I dunno...


Hope this helps someone!