If you're interested in functional programming, you might also want to checkout my second blog which i'm actively working on!!

Tuesday, February 26, 2013

Debugging circular references in Maps

Today I learned another useful feature to debug circular references which can cause stackoverflows when not handled with caution. The below render method takes a parameter of type Map. In some cases the value is again a HashMap. Invoking entry.getValue() implicitly invokes the toString method in the Log.debug. When there are any circular references, you will get a nice stackoverflow.

    public String render(final String template,
            final Map<String, Object> parameters)
            throws IOException {

        final ST stringTemplate = new ST(template, '$', '$');

        if (parameters == null || parameters.isEmpty()) {
            LOG.warn("There are not any parameters passed to the template.");
        } else {
            for (Map.Entry<String, Object> entry : parameters.entrySet()) {
                stringTemplate.add(entry.getKey().replace(".", "_"),
                        (entry.getValue() instanceof String)
                        ? StringEscapeUtils.escapeXml(
                        entry.getValue().toString())
                        : entry.getValue());

                LOG.debug("Passing pipeline parameter as attribute: key={}"
                        + ", value={}", entry.getKey(), entry.getValue());
            }
        }

        return stringTemplate.render();
   

So you could e.g. write your own routine to find a clue where the problem is located but by following the Cocoon mailinglist I learned from Francesco that Commons Collections has a nice method to print a Map's content verbose. So I decided to experiment myself a bit to see how quickly I would find the issue using this approach and modified the code a bit.
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
    stringTemplate.add(entry.getKey().replace(".", "_"),
        (entry.getValue() instanceof String)
         ? StringEscapeUtils.escapeXml(
         entry.getValue().toString())
         : entry.getValue());

     if (entry.getKey() == "cocoon")   MapUtils.verbosePrint(System.out, "cocoon", (Map) entry.getValue());
}

Now the output that got logged is listed below. I indented it a bit more properly but we can quickly see that "cocoon" has a "controller" which points back to "cocoon". --> (ancestor[0] Map)
cocoon = 
{
  response = org.apache.cocoon.servletservice.HttpServletResponseBufferingWrapper@12b13004
  settings = Settings:
      running mode : dev
      org.apache.cocoon.reload-delay : 1000
      org.apache.cocoon.reloading : false
      org.apache.cocoon.classloader.load.classes : 
      org.apache.cocoon.cache.directory : C:\workspaces\..\target\work\cache-dir
      org.apache.cocoon.work.directory : C:\workspaces\..\target\work
      org.apache.cocoon.formencoding : null
      org.apache.cocoon.containerencoding : UTF-8
  request = org.apache.cocoon.servlet.util.ObjectModelProvider$ObjectModelRequest@77d67cee
  context = org.apache.cocoon.servletservice.ServletServiceContext@7d91ec17
  controller = 
  {
    baseUrl = file:/C:/workspaces/apache/../src/main/resources/COB-INF/
    id = abc
    javax.servlet.http.HttpServletResponse = org.apache.cocoon.servletservice.HttpServletResponseBufferingWrapper@12b13004
    testProperty = test
    source = file:/C:/workspaces/apache/cocoon/cocoon3/trunk/cocoon-sample/src/main/resources/COB-INF/controller/demo.html
    javax.servlet.ServletContext = org.apache.cocoon.servletservice.ServletServiceContext@7d91ec17
    javax.servlet.http.HttpServletRequest = org.apache.cocoon.servletservice.util.ServletServiceRequest@5513fab7
    org.apache.cocoon.configuration.Settings = Settings:
        Running mode : dev
        org.apache.cocoon.reload-delay : 1000
        org.apache.cocoon.reloading : false
        org.apache.cocoon.classloader.load.classes : 
        org.apache.cocoon.cache.directory : C:\workspaces\..\target\work\cache-dir
        org.apache.cocoon.work.directory : C:\workspaces\..\target\work
        org.apache.cocoon.formencoding : null
        org.apache.cocoon.containerencoding : UTF-8
    name = foo
    cocoon = (ancestor[0] Map)
    reqparam = 1
  }
}


Sunday, February 24, 2013

Constraints and Triggers - RDBMS

This article is meant as a quick lookup of constraints and trigger syntax. Besides most RDBMS's don't even implement the full SQL standard. Sqlite should be able to run below statements.

---------------------------------------------------------------------------
-----------------------------  CONSTRAINTS---------------------------------
---------------------------------------------------------------------------

***************************************************************************
create table Apply(sID int, cName text, major text, decision text, 
check(decision = 'N' or cName <> 'Stanford' or major <> 'CS'));


insert into Apply values(123, 'Stanford', 'CS', 'N');
insert into Apply values(123, 'MIT', 'CS', 'Y');
insert into Apply values(123, 'Stanford', 'CS', 'Y');

***************************************************************************
create table Student(sID int, sName text, GPA real, sizeHS int);

/* check constraints are not supported currently and neither are subqueries in constraints */
create table Apply(sID int, cName text, major text, decision text, 
  check(sID in (select sID from Student))); 
 
/* But this is an example of referential integrity */
  
  
***************************************************************************
/* Using assertions -- Currently not supported by RDBMS's */

create assertion Key
check ((select count(distinct A) from T) = (select count(*) from T)));

create assertion ReferentialIntegrity
check (not exists (select * from Apply where sID not in (select sID from Student)));

check assertion AvgAccept
check (3.0 < (select avg(GPA) from Student where sID in (select sID from Apply where decision = 'Y')));


***************************************************************************
create table College(cName text primary key, state text, enrollment int);
create table Student(sID int primary key, sName text, GPA real, sizeHS int);
create table Apply(sID int references Student(sID), cName text references College(cName), major text, decision text);

//using cascading update
create table Apply(sID int references Student(sID) on delete set null, 
                   cName text references College(cName) on update cascade, 
                   major text, decision text);
***************************************************************************


---------------------------------------------------------------------------
-----------------------------  TRIGGERS  ----------------------------------
---------------------------------------------------------------------------
***************************************************************************
create trigger R1
after insert on Student
for each row
when New.GPA > 3.3 and New.GPA <= 3.6
begin
  insert into Apply values (New.sID, 'Stanford', 'geology', null);
  insert into Apply values (New.sID, 'MIT', 'biology', null);
end;  
***************************************************************************
create trigger R2
after delete on Student
for each row 
begin
  delete from Apply where sID = Old.sID;
end;
***************************************************************************
create trigger R3
after update of cName on College
for each row
begin
  update Apply
  set cName = New.cName
  where cName = Old.cName;
end;
***************************************************************************
create trigger R4
before insert on College
for each row
when exists (select * from College where cName = New.cName)
begin
  select raise(ignore);
end;
***************************************************************************
create trigger R5
before update of cName on College
for each row 
when exists (select * from College where cName = New.cName)
begin
  select raise(ignore);
end;
***************************************************************************
create trigger R6
after insert on Apply
for each row
when (select count(*) from Apply where cName  = New.cName) > 10
begin
  update College set cName = cName || '-Done'
  where cName = New.cName;
end;  

***************************************************************************
create trigger R7
before insert on Student
for each row 
when New.sizeHS < 100 or New.sizeHS > 5000
begin
  select raise(ignore);
end;
***************************************************************************
create trigger AutoAccept
after insert on Apply
for each row 
when (New.cName = 'Berkeley' and
      3.7 < (select GPA from Student where sID = New.sID) and
      1200 < (select sizeHS from Student where sID = New.sID))
begin
  update Apply
  set decision = 'Y'
  where sID = New.sID
  and cName = New.cName;
end;
***************************************************************************
create trigger TooMany
after update of enrollment on College
for each row
when (Old.enrollment <= 16000 and New.enrollment > 16000)
begin
  delete from Apply where cName = New.cName and major = 'EE';
  update Apply
  set decision = 'U'
  where cName = New.cName
  and decision = 'Y';
end;
     

Thursday, February 21, 2013

Using sqlite with Firefox sqlite-manager extension

The Stanford database course is using sqlite to experiment with SQL, Constraints, Triggers and so on. As the downloadable executable from this site only has a command line interface I decided to search for a GUI manager for sqlite. I am currently trying the firefox add-on which seems to work just fine.

/* First we create a table with a tuple constraint */
create table Apply(sID int, cName text, major text, decision text, 
check(decision = 'N' or cName <> 'Stanford' or major <> 'CS'));

/* next we try to insert a few tuples but the 3rd one should throw a constraint violation exception */
insert into Apply values(123, 'Stanford', 'CS', 'N');
insert into Apply values(123, 'MIT', 'CS', 'Y');
insert into Apply values(123, 'Stanford', 'CS', 'Y');

Friday, February 15, 2013

Merging CSV and XML data with fast performance

This blogpost will show a simple demo of how you can merge XML data with additional data coming from a Comma Separated File. Again I just made up some testdata for demo purpose. But just to give some numbers, my real use case merged data from a 242MB XML file and a CSV file in less than 5 seconds using of course Saxon.
nxp10009@NXL01366 /c/xsltdemo
$ ls -la
total 4786
drwxr-xr-x    6 nxp10009 Administ        0 Feb 15 16:35 .
drwxr-xr-x    1 nxp10009 Administ    12288 Feb 15 16:19 ..
-rw-r--r--    1 nxp10009 Administ  9788993 Oct 30 13:42 Saxon-HE-9.4.jar
drwxr-xr-x    4 nxp10009 Administ        0 Feb 15 16:34 input
drwxr-xr-x    4 nxp10009 Administ        0 Feb 15 17:18 output
drwxr-xr-x    4 nxp10009 Administ        0 Feb 15 17:03 xslt


nxp10009@NXL01366 /c/xsltdemo/input
$ ls -la
total 1
drwxr-xr-x    4 nxp10009 Administ        0 Feb 15 16:34 .
drwxr-xr-x    6 nxp10009 Administ        0 Feb 15 16:35 ..
-rw-r--r--    1 nxp10009 Administ       47 Feb 15 16:46 studentinfo.csv
-rw-r--r--    1 nxp10009 Administ      576 Feb 15 17:13 students.xml

studentinfo.csv
1, m, developer
2, m, developer
3, f, model

students.xml
<?xml version="1.0" encoding="UTF-8" ?>
<students>
  <student>
    <firstname>Robby</firstname>
    <lastname>Pelssers</lastname>
    <dateofbirth>1977-02-07</dateofbirth>
    <studentid>1</studentid>
  </student>
  <student>
    <firstname>Ivan</firstname>
    <lastname>Lagunov</lastname>
    <dateofbirth>1987-04-30</dateofbirth>
    <studentid>2</studentid>
  </student>
  <student>
    <firstname>Pamela</firstname>
    <lastname>Anderson</lastname>
    <dateofbirth>1967-07-01</dateofbirth>
    <studentid>3</studentid>
  </student>  
</students>

So the first thing I did was creating an XML representation of that CSV file using below xslt.
studentinfo.xslt
<?xml version="1.0" encoding="UTF-8"?>
<!--
Author: Robby Pelssers

Transforms studentinfo.csv into XML representation

Usage from DOS-Shell:
java -jar Saxon-HE-9.4.jar -o:C:/xsltdemo/output/studentinfo.xml -it:main -xsl:C:/xsltdemo/xslt/studentinfo.xslt studentinfoCSV=file:/C:/xsltdemo/input/studentinfo.csv

-->

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:param name="studentinfoCSV" />
  

  <xsl:variable name="linefeed" select="'\r?\n'"/>
  <xsl:variable name="csv" select="unparsed-text($studentinfoCSV)"/>  

  
  <xsl:template match="/" name="main">
    <info>
      <xsl:for-each select="tokenize($csv, $linefeed)">
        <xsl:variable name="fields" select="tokenize(., ',')"/>
        <studentinfo id="{normalize-space($fields[1])}">
          <gender><xsl:sequence select="normalize-space($fields[2])"/></gender>
          <profession><xsl:sequence select="normalize-space($fields[3])"/></profession>
        </studentinfo>  
      </xsl:for-each>
    </info>
  </xsl:template>

</xsl:stylesheet>

So after the transformation a new file studentinfo.xml gets generated as below.
<?xml version="1.0" encoding="UTF-8"?>
<info>
   <studentinfo id="1">
      <gender>m</gender>
      <profession>developer</profession>
   </studentinfo>
   <studentinfo id="2">
      <gender>m</gender>
      <profession>developer</profession>
   </studentinfo>
   <studentinfo id="3">
      <gender>f</gender>
      <profession>model</profession>
   </studentinfo>
</info>

So now we need to execute a second transform using as input students.xml and studentinfo.xml.
student_addinfo.xslt
<?xml version="1.0" encoding="UTF-8"?>
<!--
Author: Robby Pelssers

java -Xmx1024m -jar Saxon-HE-9.4.jar -s:C:/xsltdemo/input/students.xml -o:C:/xsltdemo/output/students-full.xml -xsl:C:/xsltdemo/xslt/student_addinfo.xslt studentinfoXML=file:/C:/xsltdemo/output/studentinfo.xml
-->

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:param name="studentinfoXML" />

  <xsl:variable name="studentinfoDocument" select="document($studentinfoXML)"/>

  <xsl:key name="student-lookup" match="studentinfo" use="@id"/>

  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="student">
    <student>
      <!-- we copy all present attributes and children -->
      <xsl:apply-templates select="@* | node()"/>
      <!-- now we also want to add the additional information as children --> 
      <xsl:apply-templates select="key('student-lookup', studentid, $studentinfoDocument)/*"/>
    </student>
  </xsl:template>
 
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template> 


</xsl:stylesheet>


And finally we get the merged result:
<?xml version="1.0" encoding="UTF-8"?>
<students>
  <student>
      <firstname>Robby</firstname>
      <lastname>Pelssers</lastname>
      <dateofbirth>1977-02-07</dateofbirth>
      <studentid>1</studentid>
      <gender>m</gender>
      <profession>developer</profession>
   </student>
  <student>
      <firstname>Ivan</firstname>
      <lastname>Lagunov</lastname>
      <dateofbirth>1987-04-30</dateofbirth>
      <studentid>2</studentid>
      <gender>m</gender>
      <profession>developer</profession>
   </student>
  <student>
      <firstname>Pamela</firstname>
      <lastname>Anderson</lastname>
      <dateofbirth>1967-07-01</dateofbirth>
      <studentid>3</studentid>
      <gender>f</gender>
      <profession>model</profession>
   </student>  
</students>