Archive for August, 2010

If you are going to the trouble of designing mobile sites for different devices and screen sizes, then you should be taking into account that many smartphones have the abilitiy to change orientation from portrait to landscape, giving a much wider screen width.

You can use Javascript to register the change in orientation, but how can you deliver a different user experience when the user flips the phone?

With bemokoLive, it’s very easy to use the context rules to change the behaviour of your site when the user flips the device.

Context rules allow you to change the behaviour of the bemoko rendering engine with parameters on the URL.  In this case we can use some javascript to note the change in orientation and call a URL with the relevant parameters set.  The javascript looks like this:

<script type="text/javascript">
 var landscape = isLandscape();
 function updateOrientation(){  
   var landscapeToUpdate = isLandscape();
 [#--
 Only redirect if landscape flag has changed
 --]
   if (landscape != landscapeToUpdate) {
     landscape = landscapeToUpdate;
   if (landscape) {
     window.location = "${intent.serverRelativeSiteEndPoint}/landscape/${intent.name}"
   } else {
     window.location = "${intent.serverRelativeSiteEndPoint}/${intent.name}"
   }            
  }
 }

 function isLandscape() {
   switch(window.orientation) {  
   case -90:  
   case 90:  
      return true;  
      break;  
   default:
      return false;  
  }
 }
</script>

The important piece in this script are the lines where the window.location is changed.  Note the addition of the landscape parameter.  As this parameter is before the intent in the URL it acts as a context rule.

To get bemokoLive to recognise the context rule, it has to be registered in the site-config.xml

<context>
 <rules>
     <rule name="landscape">
         <param action="add" name="type">l</param>
     </rule>
 </rules>  
 </context>

This makes bemoko add a parameter called “type” to the context if the landscape context rule is present.  We can use this parameter to change the device category recognition for the device, again in the site-config.xml

<uigroup>
    <ui name="landscape" expr="intent.get('type') == 'l'" fallback="ajax" />
</uigroup>

This change has the effect of overidding the standard device identification, adding the landscape category into the fallback chain.  This means that any files or fragments in the landscape category will be delivered to the device, allowing you do do anything from simply delivering wider images to changing the whole look and feel of the page.

You can find more on context rules at http://bemoko.com/wiki/Context_Rules

For a live demo showing one use of context rules, take a look at http://bemoko.com/addons/imagetranscoder/test/i – the alternative rendering links at the bottom of the page use context rules to change the way the device is recognised.

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks

One of the joys of using the bemokoLive development framework is the ease with which you can integrate with external content services.  I’ve recently been working on a site which needs consume a .NET generated webservice.

For this integration, I decided to use GroovyWS which provides a very nice interface to the world of Apache CXF.    Setting up the webservice is simplicity itself:

proxy = new WSClient(WSDL URL, this.class.classLoader)
proxy.initialize()

This was all going well until I tried to use the login webservice call.  The login provides a token which is needed to authenticate all further calls to the webservice.  The XML returned from the webservice is:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <AuthHeader xmlns="https://app.restaurantdiary.com/webservices/ReservationService/">
      <Token>string</Token>
    </AuthHeader>
  </soap:Header>
  <soap:Body>
    <LoginResponse xmlns="https://app.restaurantdiary.com/webservices/ReservationService/" />
  </soap:Body>
</soap:Envelope>

Notice that the token is returned in the SOAP header, not the SOAP body.  It seems that CXF is geared up for reading the body of the message only, getting to the headers is not simple.  So my problem was being able to get the token and add it to further calls.

I tried many searches of the internet, but it seems that either no one has ever had to do this or they have and didn’t write about it.  Hopefully the following example will help if you ever need to do this.  The following example is in Groovy.

Before I get to the actual example, let me take a quick diversion, but useful, diversion on logging.

I spent hours trying to see the SOAP request and response that was being sent and received, using network sniffers and the like.  Communicating over SSL also meant I was doomed to failure.  Then I discovered interceptors, notably the LoggingInInterceptor and the LoggingOutInterceptor.  This simple piece of code allowed me to log the incoming and outgoing requests

proxy.client.getInInterceptors().add(new org.apache.cxf.interceptor.LoggingInInterceptor())
proxy.client.getOutInterceptors().add(new org.apache.cxf.interceptor.LoggingOutInterceptor())

I still didn’t have my AuthHeader though.  After a lot of experimenting, I found I could access the headers with this piece of code

def headerList = proxy.client.getResponseContext().get(Header.HEADER_LIST)

This was good.  Accessing the auth token was fairly simple after that:

SoapHeader sh = headerList[0]
 def doc = sh.getObject()
 def list = doc.getElementsByTagName("Token")
 token = list.item(0).getFirstChild().getNodeValue()
 log.debug("Token = " + token)

Yay, token now safely stored in my variables…. Now to add the token to future headers

List<Header> headers = new ArrayList<Header>();
SOAPFactory sf = SOAPFactory.newInstance()
def authElement = sf.createElement(new
QName(namespace, "AuthHeader"))
def tokenElement = authElement.addChildElement("Token")
tokenElement.addTextNode(token)
SoapHeader tokenHeader = new SoapHeader(new QName(namespace, "AuthHeader"), authElement);
headers.add(tokenHeader);
proxy.client.getRequestContext().put(Header.HEADER_LIST, headers)

This code adds the auth header with the token into the SOAP headers for every future request.

Hopefully if you are trying to use SOAP headers with CXF, this post will save you some time.

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
Posted in: java, mobile 1 Comment