Tuesday, July 31, 2012

Skinning in JSF


Why Skinning?

CSS is the tool for webdevelopers (or more likely designers) to customize sites without having to alter code. This allows for visual variability without the need to compile/test/deploy/... things. It also allows user-specific theming where the user can decide which theme looks best.
However there is one thing notably lacking in css: variables. They may be introduced in CSS3 but it will be a ways before they are actually picked up by all major browsers. Until then we can look at other frameworks to see how they achieve skinning in JSF, most notably Richfaces. This document is written using richfaces as a guideline but does not actually require any richfaces components to be present so it can be used with any JSF framework.

Richfaces skinning

Richfaces supports skinning by using a simple properties file to represent the variables. The properties file must:
  • be located in META-INF/skins
  • have the extension "skin.properties"
For example you might create a skin "META-INF/skins/test.skin.properties". To tell richfaces to use this skin, you have to configure a context parameter in the web.xml file:
<context-param>
      <param-name>org.richfaces.skin</param-name>
      <param-value>test</param-value>
</context-param>
You can take an existing skin file to see which variables exist or you can browse the component pages to see which variables they reference. Additionally richfaces will by default (you can turn this off) style regular jsf components as well in order to create a single theme for the entire application.

Using the variables yourself

Of course you don't only want to skin existing richfaces components, you may want to use the variables in the css of your own components/pages. In order to do this, you need to create a file with an extension ".ecss" instead of ".css". This will be automatically picked up by richfaces and the variables inside it will be replaced with the properties available in the skin file. Each variable must be written like this:
'#{richSkin.myParam}'
The quotes are mandatory. There are however a number of caveats.

Library lookups are wonky

Richfaces will translate your ecss outputStylesheet to something like this:
<link type = "text/css" rel = "stylesheet"
      href = "/app/rfRes/myStyleSheet.ecss.xhtml?db=eAHb-CCOEQAGJQHx" />
Which is fine unless you add the style sheet to a library, then it will generate this (note the escaped ampersand):
<link type = "text/css" rel = "stylesheet"
      href = "/app/rfRes/myStyleSheet.ecss.xhtml?db=eAHb-CCOEQAGJQHx&amp;ln=style" />
I'm not entirely sure if the problem lies with richfaces (I don't really see an obvious bug in the code with regards to URI encoding) or with jsf in general but either way it is a bit off. This may work depending on the browser, not sure how well supported this is though. Anyway, you can easily sidestep this by not putting it in a resource library and simply adding stuff on the root.

Eclipse does not like ecss files

Eclipse does not always like the variable format ecss uses. Depending on your level of bad luck you either get badly highlighted css or continuous parsing errors resulting in error popups.

Custom css properties are dropped

It is a long standing tradition to introduce new css features in browsers with a prefix for said browsers. For example take this bit of css which includes a chrome/firefox gradient and a firefox/general box-sizing declaration:
.menu .main a {
      background: -webkit-gradient(linear, left top, left bottom, from('#{richSkin.menuGradientLight}'), to('#{richSkin.menuGradientDark}'));
      background: -moz-linear-gradient(top, '#{richSkin.menuGradientLight}', '#{richSkin.menuGradientDark}');
      padding: 0px 10px;
      padding-top: 8px;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
}
When I browsed the resulting compiled ecss, I got this:
*.menu *.main a {
      background: webkit-gradient(linear,lefttop,leftbottom,from(rgb(64,64,64)),to(rgb(43,43,43)));
      background: webkit-gradient(linear,lefttop,leftbottom,from(rgb(64,64,64)),to(rgb(43,43,43)));
      padding: 0px 10px;
      padding-top: 8px;
}
As you can see, it dropped the mozilla gradient and both the mozilla and default box-sizing properties. This is likely because richfaces actually interprets the css instead of merely replacing the variables. The colors were also defined as hexadecimal and converted to their rgb equivalent. Apart from validation, I'm not entirely sure why richfaces bothers parsing the css.

Custom variable styling

To work around the issues mentioned above, I wrote my own stylesheet compiler. It requires a few things to function:
  • stylesheets must use the extension ".compiled.css" instead of ".css", so for example "mystyle.compiled.css" will be picked up by the stylesheet compiler
  • it currently uses the richfaces web.xml property mentioned above to determine which skin file you want and also scans for the "META-INF/skins/<name>.skin.properties" file, in that respect it is compatible with richfaces
The variable format is slightly more lightweight, it uses "$", the css fragment in the above would become:
.menu .main a {
      background: -webkit-gradient(linear, left top, left bottom, from($menuGradientLight), to($menuGradientDark));
      background: -moz-linear-gradient(top, $menuGradientLight, $menuGradientDark);
      padding: 0px 10px;
      padding-top: 8px;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
}
The compiler does not actually parse the stylesheet, it simply replaces all the variables it finds in the skin properties file.

Bits and pieces

The stylesheet compiler is a standalone jar file which can be plugged into any war file. It contains the following things.

CSSResourceHandler.java

First off you need to provide a custom implementation of the jsf resource handler. Based on this tutorial and the richfaces implementation it looks like this:
public class CSSResourceHandler extends javax.faces.application.ResourceHandlerWrapper {
      private Logger logger = LoggerFactory.getLogger(getClass());
      
      private Properties skinProperties;
      
      private ResourceHandler wrapped;
      
      public CSSResourceHandler(ResourceHandler wrapped) {
            logger.debug("Creating custom resource handler with parent {}", wrapped);
            this.wrapped = wrapped;
      }
      
      @Override
      public ResourceHandler getWrapped() {
            return wrapped;
      }
      @Override
      public Resource createResource(String resourceName, String library, String contentType) {
            logger.trace("createResource(" + resourceName + ", " + library + ", " + contentType + ")");
            // get the resource in the conventional way
            Resource resource = super.createResource(resourceName, library, contentType);
            // if the resource is a ".compiled.css" file, compile it
            if (resourceName.endsWith(".compiled.css"))
                  return new CompiledCSS(resource, getSkinProperties());
            else
                  return resource;
      }
      @Override
      public Resource createResource(String resourceName, String library) {
            return createResource(resourceName, library, null);
      }
      @Override
      public Resource createResource(String resourceName) {
            return createResource(resourceName, null, null);
      }
      
      @Override
public String getRendererTypeForResourceName(String resourceName) {
            if (resourceName.endsWith(".compiled.css"))
                  return "javax.faces.resource.Stylesheet";
            else
                  return super.getRendererTypeForResourceName(resourceName);
      }
      
      private Properties getSkinProperties() {
            if (skinProperties == null) {
                  // we need to figure out which skin is configured
                  FacesContext context = FacesContext.getCurrentInstance();
                  // get the richfaces skin parameter
                  String skin = context.getExternalContext().getInitParameter("org.richfaces.skin");
                  // the default skin
                  if (skin == null)
                        skin = "DEFAULT";
                  // in richfaces, the context class loader is used, not the faces context method of resource discovery
                  // note that the path must follow the below convention as per richfaces documentation & implementation
                  InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/skins/" + skin + ".skin.properties");
                  if (input != null) {
                        logger.debug("Loading skin " + skin);
                        skinProperties = new Properties();
                        try {
                              try {
                                    skinProperties.load(input);
                              }
                              finally {
                                    input.close();
                              }
                        }
                        catch (IOException e) {
                              throw new RuntimeException(e);
                        }
                  }
                  else
                        logger.error("Could not find skin " + skin);
            }
            return skinProperties;
      }
}
As you can see, it simply delegates most resource calls to the wrapper that it was initiated with. Only when the extension ".compiled.css" is found does it kick in. If the web.xml context parameter is not set, it will fall back to the richfaces default.

CompiledCSS.java

The compiled css class extends resource and much like the handler, delegates nearly all calls. It intercepts the request for content though and performs a replace on the original content before sending it back:
public class CompiledCSS extends Resource {
      private Resource original;
      private String cached;
      
      private Properties skinProperties;
      
      public CompiledCSS(Resource original, Properties skinProperties) {
            this.original = original;
            this.skinProperties = skinProperties;
      }
      
      /**
       * This is where we actually convert the css
       */
      @Override
      public InputStream getInputStream() throws IOException {
            if (cached == null) {
                  // copy to string
                  ByteArrayOutputStream output = new ByteArrayOutputStream();
                  byte [] buffer = new byte[102400];
                  int read;
                  InputStream source = original.getInputStream();
                  try {
                        while ((read = source.read(buffer)) != -1)
                              output.write(buffer, 0, read);
                  }
                  finally {
                        source.close();
                  }
                  cached = new String(output.toByteArray());
                  for (Object key : skinProperties.keySet())
                        cached = cached.replaceAll("\\$" + key.toString(), skinProperties.get(key).toString());
            }
            return new ByteArrayInputStream(cached.getBytes());
      }
      
      @Override
      public String getRequestPath() {
            return original.getRequestPath();
      }
      @Override
      public Map<String, String> getResponseHeaders() {
            return original.getResponseHeaders();
      }
      @Override
      public URL getURL() {
            return original.getURL();
      }
      @Override
      public boolean userAgentNeedsUpdate(FacesContext context) {
            return original.userAgentNeedsUpdate(context);
      }
      @Override
      public String getContentType() {
            return "text/css";
      }
}

META-INF/faces-config.xml

You need to tell JSF to use your custom resource handler, you can do this in the faces-config file:
<faces-config
xmlns = "http://java.sun.com/xml/ns/javaee"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version = "2.0">
      <application>
            <resource-handler>com.example.web.common.CSSResourceHandler</resource-handler>
      </application>
</faces-config>
At this point I'm not entirely sure how this works. Apart from the mandatory faces-config.xml file in your main war, you can apparantly have faces-config.xml files in your libraries as well. Richfaces registers its own resource handler and since both frameworks still work, JSF must register both instead of having a "the last setting wins" policy. How this plays out at runtime (are all the handlers stacked in order of appearance? Is it a flat list of handlers that is looped through?...) is unclear at this point.

Putting it together

Suppose you have a separate jar which defines some templates/components and most notably: some styling. The jar layout is as follows:
  • META-INF: everything must be in meta-inf for jsf to pick it up
    • resources: all jsf-related resources including templates must be available in the resources folder
      • style: the library "style"
        • default.compiled.css
      • templates
        • layout.xhtml
    • skins
      • custom.skin.properties
Suppose we define a very simple layout.xhtml:
<html xmlns = "http://www.w3.org/1999/xhtml"
      xmlns:h = "http://java.sun.com/jsf/html"
      xmlns:f = "http://java.sun.com/jsf/core"
      xmlns:rich = "http://richfaces.org/rich"
      xmlns:a4j = "http://richfaces.org/a4j"
      xmlns:ui = "http://java.sun.com/jsf/facelets">
      <h:head>
            <title>
                  <ui:insert name = "title"/>
            </title>
            <h:outputStylesheet name = "default.compiled.css" library = "style"/>
      </h:head>
      <h:body><ui:insert name = "main"/></h:body>
</html>
As you can see, we can reference the compiled stylesheet as we would a normal stylesheet. Now suppose we have this bit in the stylesheet:
.menu .main a {
      background: -webkit-gradient(linear, left top, left bottom, from($menuGradientLight), to($menuGradientDark));
      background: -moz-linear-gradient(top, $menuGradientLight, $menuGradientDark);
      padding: 0px 10px;
      padding-top: 8px;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
}
Then we need to add the properties to the custom.skin.properties file:
menuBorderColor=#666666
menuGradientLight=#404040
menuGradientDark=#2b2b2b
When you open the css as it is retrieved by the browser, you will see:
.menu .main a {
      background: -webkit-gradient(linear, left top, left bottom, from(#404040), to(#2b2b2b));
      background: -moz-linear-gradient(top, #404040, #2b2b2b);
      padding: 0px 10px;
      padding-top: 8px;
      -moz-box-sizing: border-box;
      box-sizing: border-box;
}
If you package this as a "theme" library for your jsf applications, you can create an index.xhtml in your main war file that contains:
<ui:composition xmlns = "http://www.w3.org/1999/xhtml"
      xmlns:h = "http://java.sun.com/jsf/html"
      xmlns:f = "http://java.sun.com/jsf/core"
      xmlns:rich = "http://richfaces.org/rich"
      xmlns:a4j = "http://richfaces.org/a4j"
      xmlns:ui = "http://java.sun.com/jsf/facelets"
      template = "templates/layout.xhtml">
      <ui:define name = "main">
            <p>the main content comes here!</p>
      </ui:define>
</ui:composition>

Author: Alexander Verbruggen

Tuesday, July 24, 2012

Resending Idocs Not Using Transaction WE19

Problem:

When testing an interface in SAP PI I wanted to resend some idoc's to PI. Resending a succesfully processed idoc in SAP PI is not possible from SXMB_MONI.


You can use transaction WE19 from your backend system to do this, but I was not authorized to use this transaction. So I had to look for an other way to do this instead of always disturbing other colleagues who had the authorization to use transaction WE19.

Solution:

1. Use the transaction code SE38 in your SAP backend system and enter RC1_IDOC_SET_STATUS. Click on Display.




2. Click Direct Processing or press F8.

3. Enter the following fields in the Report for Converting IDoc Status:
   A.     Enter the IDoc Number in the field or click the button to the right to enter multiple IDocs.
   B.     Enter the current Status of the IDoc under Status. Looking up the status can be done using transaction code WE05.  
   C.     Now enter New Status as 30 meaning the IDoc ready for dispatch
   D.     Uncheck Test.
   E.     Click Execute.


4. Use the transaction code /nSE38 to go back to SE38. Now enter RSEOUT00. Click Display.

5. Click Direct Processing or F8.

6. Enter fields for Process All Selected IDocs.
   A.     Enter the IDoc Number in the field or click the button to the right to enter multiple IDocs.
   B.     Optional: If you want to send the IDoc to a different port then originally specified, update the field Port of Receiver with that port information.
   C.     Click Execute.


7. Check the result in SXMB_MONI.


Author: Vaast L.

Wednesday, July 18, 2012

Prince2 and integration projects

A couple of weeks ago I attended to the Prince2 practitioner course. Main driver to attend this training was to find out how it could help me in managing several simultanous B2B & EAI projects (called integration projects from here on). I want to share some reflections on what I learned and experienced in real life.

What is Prince2 (in short)?
Prince2 is a structured project management approach that was designed by the British government. It can be applied to any type of project and is not only focussed on IT-projects. Prince2 is based around 7 themes, 7 processes and 7 principles and is often seen as the approach of common sense. Because every project manager has its own idea of common sense and its own approaches to project management a lot of time is wasted in reinventing the wheel over and over. Having projects managed by external project managers is also not convenient if no common known approach is used.

For more background information on Prince2:
Official site:http://www.prince-officialsite.com/
Dutch user group: http://www.bpug.nl/prince2.html

First reflection:
The integration (EAI or B2B) requirements are often a part of a larger IT- or business project.
It is unusuall that the integration requirements are defined as a stand alone project.
That's why integration projects managers (who manage the different requests for integration solutions coming from different other projects) often have to cope with several simultanous integration projects.
Can Prince2 help in this case?
It would be great if the overal project is managed using Prince2, but if not it would mean a lot of overhead to apply Prince2 for only to the integration projects.
You could however reuse some techniques from Prince2.
For example: the Product Breakdown Structure technique of Prince2 is a vary handy visual technique for breaking down requirements and defining dependencies.
This can help a lot in visualising the scope of your integration project, especially when you have a lot of them in parallel.

Second reflection:
Knowing the above, is it usefull for integration project managers to learn Prince2?
Yes, having a good knowledge of the different themes, processes and principles that are used in Prince2 would allow you to estimate how well the projects you're integration team is working for are managed.
This knowledge allows you to foresee problems or risks in your own planning.
For example if you're being asked to implement integration requirements for a project that has no quality management strategy at all it is likely that you'll have to free some resources for the post-go live bugfixing.
If another project has no clear defined products (Prince2 word for requirements), you can foresee timing issues, changing scope and a prosponed go-live.

Third reflection:
Prince2 doens't tell me how to manage multiple (sub-)projects at the time.
It is really focussed how to manage a single project.
To address this it seems to me that it is more usefull to learn how to work with good management tools (e.g. MS Project, Issue and task tracking tools, etc).

Author: Laurenz

Saturday, July 14, 2012

WS-Security mustUnderstand in webmethods

WS-Security mustUnderstand

Environment: webmethods 8.0.1

Problem

A client has asked us to enable ws-security when using a particular webservice he exposes (webmethods policy "Consumer policy for Username"). However when we call his webservice with the appropriate message level authentication, we receive the following soap fault:

Unprocessed 'mustUnderstand' header element: {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security

Analyzing the problem

Using wireshark/fiddler/.. you can inspect the soap that webmethods sends along and you see this:

...
<wsse:Security xmlns:wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
      xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:mustUnderstand="1"
      xmlns:wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsse:UsernameToken wsu:Id = "UsernameToken-123456">
            <wsse:Username>user</wsse:Username>
            <wsse:Password Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pass</wsse:Password>
      </wsse:UsernameToken>
</wsse:Security>
...

As you can see, the "mustUnderstand" header is indeed set. Transmitting the entire soap sans mustUnderstand via soapUI works. A quick google showed us that we are not the only ones experiencing this but no solutions were forthcoming. A succinct explanation of mustUnderstand can be found here.

The most likely cause of the issue is a bug in the client webservice implementation where he does interpret the security header but does not clear the mustUnderstand attribute which would result in the error we are seeing.

Solution

The simplest solution is of course for us not to send along the attribute but unfortunately we found no reference in the documentation regarding this particular functionality. Instead we opted to write a custom soap handler which strips the attribute when found. The webservice functionality has been subjected to a large overhaul in 8.0.1 so instead of extending javax.xml.rpc.handler.GenericHandler to add some functionality, you can work with actual services. This makes it much easier to test changes on the fly.

We create a handler service that implements the spec pub.soap.handler:handlerSpec:

The java service DgCommon.admin.utils:removeMustUnderstand uses the public org.w3c.dom api to strip the mustUnderstand:

IDataCursor cursor = pipeline.getCursor();
org.w3c.dom.Element element = (org.w3c.dom.Element) IDataUtil.get(cursor, "header");
element.removeAttribute("mustUnderstand");
IDataUtil.put(cursor, "header", element);
cursor.destroy();

This will however not work and give you a rather vague error:

com.wm.dom.DOMExceptionImpl: [ISC.133.8] Bundle:com.wm.dom.resources.DOMMessageBundle Key:133.8
      at com.wm.lang.xml.ElementNode.removeAttribute(ElementNode.java:606)
...

The exception is not entirely according to the spec so I assume this is an error in the webmethods implementation. Anyway, removing it with a fully qualified namespace does work:

element.removeAttributeNS("http://schemas.xmlsoap.org/soap/envelope/", "mustUnderstand");

You can register the handler using pub.soap.handler:registerWmConsumer (note that this must be re-registered on reboot, so do it in a startup service).

The last step is to actually add it to your list of handlers:

Author: Alexander Verbruggen