Showing posts with label DataPower. Show all posts
Showing posts with label DataPower. Show all posts

Thursday, June 20, 2013

DataPower: Setting the Content-Type header in an Error Rule

I learned a new trick today. This has been haunting me for many months now but I've managed to avoid implementing it for my customer. Today, being pressured by deadlines, I learned a cool new trick with DataPower: setting the Content-Type in an error rule.

The reason why this has eluded me for sometime is that no matter how much effort I do setting it inside an XSL in a transform action using either <dp:set-http-response-header name="'Content-Type'" value="'application/json'" /> or <dp:set-response-header name="'Content-Type'" value="'application/json'" /> and even if I do a <dp:freeze-headers /> after that, it still didn't work. I've also tried doing a set-var action setting "var://service/set-response-header/content-type" to application/json and placing it before the result action, it still does not work (this was what most of my Google search said to do). And I've been trying and trying every now and then to make it work but to no avail.

Finally, this afternoon, pressured to meet a tight deadline, I did one final Google search and found a link that I haven't read before simply because it did not exist prior to June 19, 2013. I tried it out and it worked perfectly!

How it was done was quite unusual actually, I got the part where you specify the value of var://service/set-response-header/content-type right but what I did wrong was were I placed it. Prior to June 19, my quick searches say that the set var action should be placed before the result action. But the link to a developerWorks forum post says that it should be set AFTER the result action.



When I tried it out for myself, I jumped in complete joy (the geek side of me kicking-in) and amazement. I was like: WOW! Finally!

Thursday, June 6, 2013

Date Comparison using XSLT and XPath in DataPower

It was a brain-draining day at work. I had to implement a customized SLM policy enforcement for a customer where we pull a meta-data of policies from an xml and enforce it inside an XSL transform action. The trickiest part of the day was implementing the Allowed Time of Day policy. From the parameters defined in the xml snippet we had to reject transaction if the current time is beyond the start and stop times. This is the element that we are retrieving the start and stop time from:
<Daily StartTime="08:00:00+08:00" StopTime="17:00:00+08:00"/>

After hours of attempts, below is the solution I've came up with.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
 version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 xmlns:dp="http://www.datapower.com/extensions" 
 xmlns:func="http://exslt.org/functions" 
 xmlns:df="http://lmls.ph/date_func" 
 xmlns:date="http://exslt.org/dates-and-times"
 extension-element-prefixes="dp slm func" 
 exclude-result-prefixes="dp slm func">
 
 <!-- removes the padded zero in front of HH or mm or ss -->
 <func:function name="df:removeFrontPaddedZeroes">
  <xsl:param name="pad_num" />
  <xsl:if test="starts-with($pad_num, '0')">
   <func:result select="substring($pad_num,2)" />
  </xsl:if>
  <func:result select="substring($pad_num,1)" />
 </func:function>
 
 <!-- converts the time format 00:00:00+00:00 into numbers for comparison -->
 <func:function name="df:convertTimeToNumber">
  <xsl:param name="zTime" />
  <xsl:if test="substring($zTime,9,1) = '+'">   
   <func:result select="((number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2))) * 100) + number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))) + ((number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2))) * 100))" />   
  </xsl:if>
  <func:result select="((number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2))) * 100) + number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))) - ((number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2))) * 100))" />  
 </func:function>

 <!-- function that evaluates if the current time is within the start and stop time bounds -->
 <func:function name="df:testTimeOfDay">
  <xsl:param name="start_time" />
  <xsl:param name="stop_time" />  
  <xsl:variable name="current_time" select="date:time()" />

  <xsl:variable name="start_time_c" select="df:convertTimeToNumber($start_time)" />
  <xsl:variable name="stop_time_c" select="df:convertTimeToNumber($stop_time)" />
  <xsl:variable name="current_time_c" select="df:convertTimeToNumber($current_time)" />

  <xsl:if test="(number($current_time_c) &gt;= number($start_time_c)) and (number($current_time_c) &lt;= number($stop_time_c))">
   <func:result select="true()" />
  </xsl:if>
  <func:result select="false()" />
 </func:function>
<xsl:stylesheet>

There are three functions in this XSL namely: df:testTimeOfDay, df:converTimeToNumber, and df:removeFrontPaddedZeroes the comments explain their purposes. The converTimeToNumber is where bulk of the logic goes and before I arrived to this code I had the split it up into smaller and more easy to understand pieces:
# The input parameter is called zTime, this comes in the format of 00:00:00+00:00
zTime = "00:00:00+08:00"

# Now in the format HH:mm:ss[\-\+]Hz:mz
HH = number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) 
mm = number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2)))
ss = number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))
op = substring(string($zTime),9,1)
Hz = number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2)))
mz = number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2)))

# Then logically we get HHmmss by doing (HH * 10000) + (mm *100) + (ss)
# And, Hzmz by doing (Hz * 10000) + (mz * 100)
HHmmss = (number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2))) * 100) + number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))
Hzmz = (number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2))) * 100)

# Then our if condition should be which provides the final output in HHmmss + or - Hzmz
if op = '+'
 result = ((number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2))) * 100) + number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))) + ((number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2))) * 100))
else 
 result = ((number(df:removeFrontPaddedZeroes(substring(string($zTime),1,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),4,2))) * 100) + number(df:removeFrontPaddedZeroes(substring(string($zTime),7,2)))) - ((number(df:removeFrontPaddedZeroes(substring(string($zTime),10,2))) * 10000) + (number(df:removeFrontPaddedZeroes(substring(string($zTime),13,2))) * 100))

Finally we can call the the df:testTimeOfDay to return true() when current time when current time is greater than or equal to start time AND current time less than or equal to stop time. See snippet below:
<xsl:variable name="start_time" select="$sla_snippet/Daily/@StartTime" />
<xsl:variable name="stop_time" select="$sla_snippet/Daily/@StopTime" />

<xsl:if test="df:testTimeOfDay($start_time,$stop_time) = false()">
 <dp:xreject reason="'Time of Day policy violated.'"/>
</xsl:if>

I haven't really done much testing and error handlings with this but I was able to test it making happy paths. This at least gives an idea of how you can perform comparison between dates.

Wednesday, September 26, 2012

Serving static files using DataPower

I was customizing Login and Request Permission forms for implementing OAuth with DataPower when I encountered a road-block where I need to host my CSS, JPEG, and other Web Resource files. The first solution that came to mind is to use an HTTP Server, but, since the current architecture of our client does not have an HTTP Server in the DMZ along with DataPower, I needed to find a way to host the files in DataPower.

A few Google searches later and I found this blog post from HermannSW where it says: define a local HTTP service listening on 127.0.0.1:8888 with base directory "logtemp:///". I figured that this could probably apply to my current situation.

First thing I did was to define a local:/// sub-directory to contain all my files:


Then, I created an HTTP Service with base directory pointed at "local:///WEB-CONTENT".

**Remember to assign the correct Local IP Address (or Alias) and Port Number to fit your configuration.

After defining the HTTP Service, I can now access the files via http://local_ip_address:port_number/full_path/file_name. I then defined my custom Login and Request Permission forms to use the files hosted in the HTTP Service.

Wednesday, August 15, 2012

Work Around: Copying Files from a Windows Local Machine to DataPower via CLI

I encountered a situation with DataPower where we can't access the WebGUI and the quickest way to fix it was to reinitialize the box and restore from backup. To be able to do this, I needed to copy a firmware image into the box via CLI, execute reinit <image_file_name>, reconfigure the appliance, and then restore from backup.

I had a problem copying the firmware image from one of the RHEL servers to DataPower and found out that there is a known issue when copying via SCP. Because of this, I thought of placing the firmware image inside an HTTP server. Then, instead of using SCP/SFTP, I copied using HTTP protocol.

1. Install WAMPServer or any HTTP server that your familiar with.
2. Configured the httpd.conf to grant all access to the www folder where I placed the firmware image (do something similar to your choice of HTTP Server)
3. Restarted the WAMPServer
4. The file should be located under http://{YOUR_IP}/{FILENAME}
5. Run the following commands via SSH in DataPower

test tcp-connection {YOUR_IP} 80 //make sure DataPower can communicate with your machine
config
copy http://{YOUR_IP}/{FILENAME}  image:///{FILENAME}

After copying the firmware image, I just followed the guide for resetting DataPower. As long as you have a RJ45 to USB cable, it should be easy-as-pie to reinitialize.

Tuesday, July 17, 2012

DataPower Version Upgrade from 4.0.2 to 5.0.0

Yesterday, I had the opportunity to upgrade a DataPower XB62 appliance from version 4.0.2 to version 5. I followed the steps specified in the product documentation and simplified it:


  1. Download the images in Fix Central
  1. ENSURE that you have  a working privileged user ("admin") and that you have access to it (meaning the password you're using is recent)
  1. Login as admin in default domain
  1. Backup the appliance's configuration
    1. Export Configuration
    1. Select Create a backup of the entire system 

  1. Backup files from local:/// on all domains
    1. Login to application domain
    1. Export configuration
    2. Check "Export all local files" option
    3. Download
    4. Repeat step 3.a for other domains
    5. Delete all files in local:///  on all domains to free up space (do this if there's little space left in your appliance)
    1. Save Configuration
  1. Disable application domains
    1. Configuration > Application Domain
    1. Disable domains other than the default domain
    2. Save configuration
  1. Reboot to free up resources
    1. System Control
    2. Set mode to Reboot System
    3. Click shutdown button
  1. Wait for reboot
  1. Upload the firmware image
    1. System Control
    2. Boot Image > Upload or Fetch
  1. Verify  the firmware upgrade version
  1. Enable Application Domains and Restore the local:/// files you backed up if there were any.

Well, that's about it. This is just a short version of the procedure I recommend that you still checkout the product documentation.

Tuesday, June 19, 2012

Configure WebSphere DataPower SQL Data Source with Oracle Real Application Clusters (RAC)

I've been banging my head lately trying to figure out how I would configure an SQL Data Source for DataPower for this Oracle connection string:

MYDB =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (LOAD_BALANCE = yes)
      (ADDRESS = (PROTOCOL = TCP)(HOST = MYDB01)(PORT = 1521))
      (ADDRESS = (PROTOCOL = TCP)(HOST = MYDB02)(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = mydb.mycompany.com.ph)
      (FAILOVER_MODE =
        (TYPE = SELECT)
        (METHOD = BASIC)
        (RETRIES = 180)
        (DELAY = 5)
      )
    )
  )

Since I don't know anything about Oracle, I have no idea how to use this connection string for DataPower. I do know, however, how to configure an SQL Data Source given an Oracle SID at a single database host. But, since the connection string given to me is a "load balanced" one, I didn't know anymore how to configure a data source for that.

I did a little research and found the following;

I overlooked them quite many times simply because I do not know what Oracle Real Application Clusters mean. I did some reading on them but I wasn't sure if it was what the client is using. I did more readings until finally, I had to ask the only question left unanswered: "Are we using Oracle Real Application Clusters for this?". And, when the answer was a definitive 'YES', I knew by then that the solution was just under my nose.

I followed the steps mentioned in the first link but after saving my configuration my log messages indicate:

Connection error message: Unicode converter truncated character


I then checked the second link at pages 10-11 and noticed that the AlternateServers value here was enclosed in parenthesis. I tried that again and, voila, it worked!

Here's my final configuration:



This situation reminded me of what one of our IT Architects told me when I was still very new in IBM:
Never hesitate to ask questions, it will save you a lot of time
 Now, I have something to add to that saying:
Ask the right question and you'll get the answer you seek.

Wednesday, June 13, 2012

Retrieving the original Content-Type in WebSphere DataPower response Processing Rule

I ran into a situation with DataPower today where the Content-Type of the responses from DataPower is altered from the original Content-Type of the backend service into text/plain. I have a Multi-Protocol Gateway with an HTTP front-side handler and configured to have a Non-XML request and response type. I have multiple processing policies for accepting and sending requests to a number of backend services but only one processing policy for all the incoming responses from the bakend services. This processing rule has an xformbin transform as the first action so that the response payload is treated as a consumable string for the Log action that follows it. The last action in the processing rule is an xform action that sets the original HTTP status phrase from the backend.

The responses DataPower gets from the backend should be the same response the invoker receives. What happened is, since I have an xformbin action which transformed the response payload to text, the Content-Type was transformed into text/plain automatically. To solve this, I added a few lines in the last xform action in my proceasing rule which retrieves the original content type via var://context/INPUT/content-type.

My original intent was to set this variable in the first xformbin action so that I will retrieve it later in tha last xform action. But, when I tested it, I was surprised to see that I have successfully reassigned the original Content-Type already.

Here's a segment of the last xform:
<xsl:variable name="content_type" select="dp:variable('var://context/INPUT/content-type')" />
<dp:set-http-response-header name="'Content-Type'" value="$content_type" />
DISCLAIMER: I'm no expert in DataPower. In fact, it's just a recently acquired skill that is a few months old so please bare with me if my solutions seem stupid.