Saturday, June 29, 2013

JSF caching of javascript, css, etc

In order to have static resources cached change in web.xml from
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>
to
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Production</param-value>
    </context-param>
This will allow caching of static resources fro 10 minutes;in order to change the default value add another context parameter: com.sun.faces.defaultResourceMaxAge (the default value of this parameter is 604800 ~ 10 mins)

Wednesday, April 17, 2013

JasperReports

iReports

After installing add the JDBC DataSource jar in iReports Classpath through Tools->Options-Classpath (be sure to add the jar, not the folder); restart iReports
Create a DataSource (no menu option available, just click the plug-in socket icon); be sure you add the database name at the end of the URL
Now you can create a new report and modify the report query. You can define report default values for parameters as follows (please notice that parameters are strong typed so you must create an instance of the java class):

  • String: enclose the desired value in double quotes
  • Date:
  1. new Date()
  2. new Date(113,0,1)
The second expression will initialize the default value to 1st of January 2013 (!):year+1900,month+1

Formatting dates:

  • add an expression in the report
  • change the expression text with something like this:
  • "From "+(new SimpleDateFormat("yyyy/MM/dd")).format($P{DateStart})+" to "+(new SimpleDateFormat("yyyy/MM/dd")).format($P{DateEnd})

JSF and JasperReports

Add the required jars (found in jasper reports distribution in dist and lib sub-directories) as project references. Minimal (depending on used functionality):
  • jasperreports
  • all commons
  • iText
  • groovy-all
Deploy compiled report in resources/jsrep (for instance) project sub-directory.
In managed bean you can use the following code to show the report in PDF format (the sample code uses PrimeFaces file download component, see the showcase):

      InputStream stream = ((ServletContext)FacesContext.getCurrentInstance().getExternalContext().getContext()).getResourceAsStream("/resources/jsrep/Report.jasper"); 
       JasperReport report = (JasperReport) JRLoader.loadObject(stream);
       Map<String, Object> params = new HashMap<String, Object>();
       params.put("Param", 494);
       JasperPrint jasperPrint = JasperFillManager.fillReport(report, params, ds.getConnection());
       ByteArrayOutputStream baos=new ByteArrayOutputStream();
       JasperExportManager.exportReportToPdfStream(jasperPrint,baos );
       ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
       return new DefaultStreamedContent(bais, "application/pdf", "report.pdf"); 
The data source can be obtained through injection, like
@Resource(name="jdbc/MyDataSource")
DataSource ds;
In order to export to XLS add poi jar to solution and use the following code:

        InputStream stream = ((ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext()).getResourceAsStream("/resources/jsrep/Report.jasper");
        JasperReport report = (JasperReport) JRLoader.loadObject(stream);
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("Param", 123);
        JasperPrint jasperPrint = JasperFillManager.fillReport(report, params, ds.getConnection());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JRXlsExporter exporterXLS = new JRXlsExporter();
        exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT, jasperPrint);
        exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, baos);
        exporterXLS.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);
        exporterXLS.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
        exporterXLS.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
        exporterXLS.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
        exporterXLS.setParameter(JRXlsExporterParameter.PASSWORD, null);
        exporterXLS.exportReport();
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        return new DefaultStreamedContent(bais, "application/vnd.ms-excel", "report.xls");

Creating reports that will be exported to XLS can be tricky: be sure that fields are top aligned pixel-perfect otherwise they will not be shown or shown in an unexpected manner in resulting XLS



Monday, April 8, 2013

Configure MySQL jdbc resource


  1. Copy the MySQL jdbc driver (jar file) in Glassfish lib directory and restart Glassfish
  2. In the glassfish administration console (site) go to Resources\JDBC\JDBC ConnectionPools
  3. Create a new pool of type javax.sql.DataSource and choose MySQL as the database vendor
  4. Fill in: server, user, password, database and, very important, check the URL to contain the database name (for some reason or under some circumstances it is not correctly filled in)
  5. Try Ping, should be successfull
  6. Now create the jdbc Resource, etc

Friday, March 15, 2013

JEE 6, my first web application

IE10:

  • use <!DOCTYPE html>
  • include in head section:
        <f::facet name="first">
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        </f::facet>

Date format:
JSF dispalys by defaut UTC dates while Prime faces display date as stored. Add context param in web.config:

    <context-param>
        <param-name>
javax.faces.DATETIMECONVERTER_DEFAULT_TIMEZONE_IS_SYSTEM_TIMEZONE
</param-name>
        <param-value>true</param-value>
    </context-param>

Specific theme:
  • Add context param in web.config:
    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>bootstrap</param-value>
    </context-param>
  • Copy theme (expanded) in web\resources\primefaces-bootstrap
CSS load order
In order to load your theme after primefaces.css add a facet in <h:body> (yes, body!!!)section:

        <f:facet name="last">
            <h:outputStylesheet name="css/mycss.css"/> 
        </f:facet>
Adding it in <h:head> section does not work. 

You could also use (this time in head section!) :
        <f:facet name="last">
            <link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/css/mytheme.css" />
        </f:facet>
but this will prevent you from using #{} type constructs in mytheme.css


AD authentication:
From com.sun.enterprise.security.auth.realm.ldap.LDAPRealm source code:
Realm wrapper for supporting LDAP authentication.
See LDAPLoginModule documentation for more details on the operation of the LDAP realm and login module.
The ldap realm needs the following properties in its configuration:
  • directory - URL of LDAP directory to use
  • base-dn - The base DN to use for user searches.
  • jaas-ctx - JAAS context name used to access LoginModule for authentication.
Besides JDK Context properties start with java.naming, javax.security, one can also set connection pool related properties starting with com.sun.jndi.ldap.connect.pool. See http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html for details. Also, the following optional attributes can also be specified:
  • search-filter - LDAP filter to use for searching for the user entry based on username given to iAS. The default value is uid=%s where %s is expanded to the username.
  • group-base-dn - The base DN to use for group searches. By default its value is the same as base-dn.
  • group-search-filter - The LDAP filter to use for searching group membership of a given user. The default value is uniquemember=%dwhere %d is expanded to the DN of the user found by the user search.
  • group-target - The attribute which value(s) are interpreted as group membership names of the user. Default value is cn.
  • search-bind-dn - The dn of ldap user. optional and no default value.
  • search-bind-password - The password of search-bind-dn.optional and no default value.
  • pool-size - The JNDI ldap connection pool size.

Add  security realm through Glassfish administration site (Configuration->server-config->Security->Realms):
  • JAAS Context: ldapRealm (check login.conf in config subdirectory of target domain)
  • Directory: URL of LDAP directory (like ldap://mycompany.local:389)
  • Base DN: Search sarting point in LDAP structure (like OU=Users,OU=mycompany,DC=totalsoft,DC=local )
  • Assign Groups: additional groups (apart from those retrieved from LDAP) the user will be assigned to

Add additional properties, as described by above mentioned source code. A sample of domain.xml below:

        <auth-realm name="MyRealm" classname="com.sun.enterprise.security.auth.realm.ldap.LDAPRealm">

          <property name="directory" value="ldap://mycompany.local:389"></property>

          <property name="assign-groups" value="users"></property>

          <property name="base-dn" value="OU=Users,OU=mycompany,DC=mycompany,DC=local"></property>

          <property name="group-base-dn" value="OU=Groups,OU=mycompany,DC=mycompany,DC=local"></property>

          <property name="jaas-context" value="ldapRealm"></property>

          <property name="search-filter" value="(&amp;(objectClass=user)(sAMAccountName=%s))"></property>

          <property name="group-search-filter" value="(&amp;(objectClass=group)(member=%d))"></property>

          <property name="search-bind-dn" value="mycompany\dummy"></property>

          <property name="search-bind-password" value="DummyPwd"></property>
        </auth-realm>


You might have also to add the following property in domain.xml: 
<jvm-options>-Djava.naming.referral=follow</jvm-options>


In order to find the right values for above mentioned properties you might use LDAP Browser from Softerra.
In order to check the actual search parameters sent to LDAP or the response received use WhireShark filtering by the LDAP port (389 usually):

Search DN:OU=Groups,OU=mycompany,DC=mycompany,DC=local
Filter: (&(objectClass=group)(member=CN=First Name LastName,OU=Users,OU=mycompany,DC=mycompany,DC=local))


Web service on HTTPS:
You will find plenty samples but all fail to say that if using EJB to expose a web service than the configuration must not be done in web.xml but in server specific ejb configuration file (with a different schema than web.xml); for instane for Glassfish use glassfish-ejb-jar.xml

Calling MS SQL stored procedures:
Sine there is no support fr calling stored procedures in JPA you can use the following approach.

Define a named query containing the stored procedure call

@NamedNativeQuery(name = "CallStoredProcedure", 
query = "DECLARE @P1 int;DECLARE @P2 int;
EXECUTE @P1 = usp_MyUSP @P2 OUTPUT;SELECT @P2")

In the apropriate EJB declare the method:


public List runNamedQuery(String namedQuery) {
        Query cq = getEntityManager().createNamedQuery(namedQuery);
        return cq.getResultList();
    }

And finally call it from the controller:


List rez = getFacade().runNamedQuery("CallStoredProcedure");Integer p2=(Integer) rez.get(0));


If you need parameters you can use the regular JPA syntax in the named query and pass the values to the Query object (using setParameter method)





Wednesday, February 9, 2011

Hello Mule

So, you are a sort of Java programmer (meaning you can develop simple applications using NetBeans or Eclipse), you are looking for an open source ESB and Mule looks promising; you do not want to waste your time reading tons of documentation but just start in the most effective way evaluating Mule, addressing your concerns about being able to solve yourself the problems (inevitably) you will  face in real life. Then this post might be helpful.
As I also did I suppose you started reading the book ("Mule in Action") . After 20 pages you gave up and changed strategy: downloaded latest Mule distribution, along with source code (of course, we are programmers and "code is the model") and start analyzing samples. Surprise, samples look very different from what you already learned from the book so you go on Mule site: of course, latest major release changed the approach going for flows instead of services (looks familiar for open source projects?). At this point you run out of ideas how to tackle the problem in an effective way but you are still confident in Mule, so let me provide  some help!
Let's start defining the approach: we will try to extend some Mule functionality so that we get familiar with code and concepts; for some reason I don't remember I choose to focus on FTP transport so I quickly wrote a sample using ftp endpoint to read files from Microsoft site (!) and store it on local HDD:
<flow name="FTP input">
               <ftp:inbound-endpoint user="anonymous" password="123456"
                                host="ftp.microsoft.com" path="/developr/rfc/wfw" port="21">
                        <file:filename-wildcard-filter pattern="*.386,*.xml" />

              </ftp:inbound-endpoint>

             <file:outbound-endpoint path="c:\temp"
                    outputPattern="#[header:originalFilename]__#[function:datestamp].txt">
            </file:outbound-endpoint>
  </flow>
(In order to run the sample install Mule, Eclipse and Mule IDE).
Running the sample we face our first problem: an IO exception is thrown, stating that Mule it's unable to delete the source file (of course, MS site is read only); thus we found out several facts:
  • by default the ftp transport deletes the source file after successfully processing it
  • some options that looks very valuable in real life projects are not available in community edition (like fileAge and moveTo..)
OK, finally we found a real challenge: extending community edition transport with functionality from enterprise edition. To be able to do this we will have to setup our development environment (this might by no means be the ideal solution but it was the quickest I found):
  • Install also NetBeans
  • Create a project using Maven Project template
  • Edit pom.xml and add the flowing XML snippet:
    <dependency>
      <groupId>org.mule.transports</groupId>
      <artifactId>mule-transport-ftp</artifactId>
      <version>3.1.0</version>
      <scope>compile</scope>
    </dependency>
By compiling the project you will get added all the Mule and depending on jars ; after that you can use the "Download Source" option (right click on Libraries folder)to have access to source code.
First thing we have to do is define the schema for our extension; we will use ftpext as our target namespace. We will add the three missing attributes:
  • fileAge
  • moveToDirectory
  • moveToPattern
Yes, you are right, I forgot to tell you where from you can download sources: https://mule-ftpext.googlecode.com/svn/trunk/
The schema must  be located in src\main\resources\META-INF directory together with spring.handlers and spring.schemas property files (we will briefly describe them lately).
Since the schema must be located somewhere Mule can read it I choose to host it in IIS (yes, I am am using Windows...) at http://localhost/schemaftpext/mule-ftpext.xsd. In order for Mule to know about our extension we have to edit accordingly:
  • spring.handlers, that associates with our schema URI the namespace handler (we'll speak about later)
  • spring.schemas that specify the location for the XSD
Mule uses Spring Beans (former Spring Configuration?) to parse configuration files and, based on attached schemes populate Java Beans properties; in order to be able to carry out this task it needs schema handlers to be registered in spring.handlers property files included in jars that need to benefit from this service (see \src\org\mule\config\spring\handlers\MuleNamespaceHandler.java for a more complex sample). Our namespace handler (aka org.mule.transport.ftpext.config.FtpExtNamespaceHandler) will be used to parse ftpext namespace constructs. Since we are targeting inbound endpoint (so far) we will need to have our own specialised calsses as follows:

  • FtpExtConnector extending FtpConnector; this class will host the properties for the newly attributes we have defined (fileAge and so on); also getProtocol method needs overriden in order to return our schema (ftpext) and not ftp as base class does;
  • FtpExtMessageReceiver extending FtpMessageReceiver; this class will overide some methods in order to cope with added functionality;
  • FtpExtUrlEndpointURIBuilder extending FtpUrlEndpointURIBuilder; we need setEndpoint method overriden in order to generate addresses with ftp:// protocol prefix (the default implementation uses the schema as protocol specification and we will end up with addresses like ftpext://..)
The mail logic of our extension is located in FtpExtMessageReceiver:
  • listFiles will return only files obeying the fileAge condition (if specified)
  • postProcess method will deal with file moving if moveTo... attributes are specified
Let's switch to our test environment, Eclipse. I suppose you have already created a test Mule project )also adding a configuration file). At this point you can add reference to our ftpext jar (built with NetBeans).

Several tricks:
  • you can associate sources to classes we have mentioned above (FtpExt...) by double clicking on the class name (in library content) and then selecting the sources folder (this worked differently every time I used it but finally you will be able to pick up the right folder :-)); after rebuilding jar in NetBens  close all sources related to FtpExt you suppose to debug, refresh the library (by pressing F5 for instance) and reopen the desired source (otherwise you will not be able to see latest changes);
  • When doing changes to XSD file(s) go to Window->Preferences->General->Network Connections->Cache and remove the modified entries; unless you do this Eclipse will not see the changes;
  • You can also navigate into Mule source code from Eclipse by just opening the Mule Libraries tree, locating the class and double clicking on it; you can set breakpoints or jump to definitions by highlighting (selecting) items and pressing F3;
So, enough for now! In some next post we will analyze problems we will face in real life projects as well as the solutions we can adopt (as you can see the sources are far more complex than the extension we have talked requires); fortunately it proves that Mules has been designed for extensibility so our programming capabilities will not rust (in peace...if you know what I mean).