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)