Wednesday, March 12, 2014

Quick recap of JVM in context of weblogic

This is probably an age old concept that was discussed many times since the beginning of java but it seems like many programmers struggle or often lose track of these trivial but important basics.This post is to just refresh that knowledge. Specially the people who are working on weblogic server often encounter issues such as "OutOfMemoryError" , "PermGenSpace Out of memory" and end up tweaking these settings with no or less real understanding.

Lets see what different JVM settings are-( not full list)

1. Xms - Initial heap space.
2. Xmx - Maximum heap space.
3. XX (or) XX:PermSize  - Permenant Generation heap space.


Initial heap space - The amount of heap space allocated to the JVM heap at the time of server start.

Maximum heap space - Once server is started and applications/instances are deployed / redeployed , the available (initial) heap space is utilized( free space decreases) and also is fragmented to some extent.
Fragmented means that the heap memory is available as not one big chunk at one place but rather is scattered at various multiple places.The problem with the fragmentation is that in order to write / create a object in heap , the amount of memory at one location of heap space may not be sufficient to store the object entirely. As a result the object is created at two different places. This causes a same instance data / application data to be scattered across different parts in the heap making it very time consuming while reading.
Now lets come back to what maximum heap space is about. Because of rapid use of applications if the increase of heap space becomes equal to the initial heap space we allocated , the operating system allocates more heap space based on need upto the max heap space.

How do I set these two parameters for better perforamce ?
Answer : Depends on your need. Lets consider two cases a) Where you know that you are going to run huge load on the server that needs much heap space. b) Where you ddont know how heap space is needed initially. In case of former(first case), you should allocate initial heap pace = max heap space ( -Xms equals to Xmx), as this would avoid an unneccassary allocation of memory by operating system once the initial heap space threshhold is reached. But as in this case initial heap is set maximum high OS doesnt intevene in between and hence can save good time.But setting a high heap right from the beginning is also not good for applications that fall into the second category where the growth of instance beyond initial heap space is unsure.However,when you allocate more initial heap space, the server may take more time to start.

PermGen space - There are three kinds of racks( or Generations) with in the Java Heap.
a) Young Generation b) Old Generation c) Permanent generation( PermGen)
Young Generation - most recently created and running objects use this.
Old Generation - Old objects which are still live will be moved to Old generation heap space. They are not frequently used but are still live.
Perm Generation - The space allocated with in the java heap to store the classes and other permanent static files that needs to be always there in heap.The space allocation completely depends on the number of applications used( classes that you deploy) and on the way programming is done ( ie., usage of static functions).
Few other memory jargon -

Eden Space (heap - young generation):pool from which memory is INITIALLY allocated for most objects.
Survivor Space (heap - young generation):pool containing objects that have survived GC of eden space.
Tenured Generation (heap - old generation):pool containing objects that have existed for some time in the survivor space
Permanent Generation (non-heap - stack):holds all the reflective data of the virtual machine itself, stores class level details, loading and unloading classes (e.g. JSPs), methods, String pool
Code Cache (non-heap):HotSpot JVM also includes a "code cache" containing memory used for compilation and storage of native code.

In order to set custom memory arguments for each of the servers (Admin and/or Managed) , you need to set the USER_MEM_ARGS in each the respective servers env script ie., setSOADomainEnv.cmd / setOSBDomainEnv.cmd / setOEREnv.cmd respectively

set USER_MEM_ARGS=-Xms256m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=768m

However doing so poses a problem - 
setDomainEnv calls the respective Env' files of the managed servers in the same domain.
- lets say setSOADomainEnv.sh , setOSBDomainEnv.sh , setOERDomainEnvsh in the same order.
Now each of these env scripts have their own USER_MEM_ARGS set. As USER_MEM_ARGS is a common variable across it holds the value updated by the last(latest) script in the order. In this case for eg : setOERDomainEnv.sh. So now all server's get started with the same memory arguments which is very bad.

For the same , I have written a very small tweak / custom script inside the setDomainEnv.cmd/sh. This will read the server name being started and then sets the memory parameters accordingly

 @REM **********START CUSTOM SCRIPT**************  
 @REM This script is needed to set the right memory parameters to the JVM based on the server being started.  
 if "%SERVER_NAME%" == "AdminServer" (  
  set USER_MEM_ARGS=-Xms256m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 if "%SERVER_NAME%" == "soa_server1" (  
  set USER_MEM_ARGS=-Xms256m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 if "%SERVER_NAME%" == "oer_server1" (  
  set USER_MEM_ARGS=-Xms256m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 if "%SERVER_NAME%" == "osb_server1" (  
  set USER_MEM_ARGS=-Xms256m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 if "%SERVER_NAME%" == "bam_server1" (  
  set USER_MEM_ARGS=-Xms256m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 if "%SERVER_NAME%" == "osr_server1" (  
  set USER_MEM_ARGS=-Xms256m -Xmx512m -XX:PermSize=256m -XX:MaxPermSize=768m  
 )  
 @REM Set the memory args in the same way above for any other servers apart from the above those participate in the same domain  
 @REM ********END CUSTOM SCRIPT*********************  

With this script you need not bother about setting the memory arguments in the individual scripts at all as this overwrites all of them.

Note :  This script has to be placed before the below lines in the setDomainEnv.bat

if NOT "%USER_MEM_ARGS%"=="" (
set MEM_ARGS=%USER_MEM_ARGS%
)

Update : I came across this blog by Antony Reynolds explaining the same issue for which he had a similar solution.

Garbage Collection:

The other option we can use to produce higher throughput is to garbage collection.
GC algorithms are of two types:
a) Parallel,Serial and b) Concurrent.
Parallel GC stops the execution of all the application and performs the full GC, this generally provides better throughput but also high latency using all the CPU resources during GC.Its mostly called as "Stop the world" GC where everything else stops while it runs.The reason it is named parallel because Multiple threads in parallel are allocated for GC. The only difference between this and serial GC is that in serial there is only single thread allocated for GC.

Concurrent GC on the other hand, produces low latency but also low throughput since it performs GC while application executes ( not in all phases of GC though).

The Hot spot JVM provides following options for GC
-XX:-UseParallelGC
-XX:-UseSerialGC

The JRockit JVM provides some useful command-line parameters for Garbage collection -

-XgcPrio:pausetime (To minimize latency, parallel GC)
-XgcPrio:throughput (To minimize throughput, concurrent GC )
-XgcPrio:deterministic (To guarantee maximum pause time, for real time systems)

Force Garbage collection:

I have found a great simple program over net that forces garbage collection. Below is the snippet of the below code that can be run
1. Go to your weblogic home and ie., eg: Oracle\Middleware\wlserver_10.3\common\bin
2. Run the command wlst forceGC.py.
The forceGC.py can be placed under the common\bin folder and its contents as below


 forceGC.py  
 # WLST script which calls GC.  
 from java.util import *  
 from javax.management import *  
 import javax.management.Attribute  
 print 'starting the script .... '  
 # please replace userid and password with your AdminServer userid and password  
 # plz change the IP adresss and port number accordingly  
 connect('weblogic','weblogic123',url='t3://localhost:7001')  
 state('AdminServer')  
 # For Force GC ....  
 domainRuntime()  
 cd('/ServerRuntimes/AdminServer/JVMRuntime/AdminServer')  
 print ' Performing Force GC...'  
 cmo.runGC()  
 disconnect()  
 print 'End of script ...'  
 exit()  


Imp Note : If you want to run the force gc for your managed server, then just change the state('AdminServer') to state('WLS_SOA1') where WLS_SOA1 is the managed server name. Make sure that Node managers are accessible and running.

Weblogic DMS spy a war deployed on weblogic admin server at url http://adminhost:port/dms/index.html provides us with very useful metrics.One of them is the JVM_Memory Set which gives us the used vs free heap and non heap memories as shown below






When I ran the forceGC.py, in few minutes my used heap memory came down. This is pretty useful in many development environment when your server is performing very slow because of less memory and not yet garbage collected.

Conclusion : Use JVM memory settings according to your application needs. Understanding of the basic jvm memory concepts help you to do better configuration and makes you troubleshoot more meaningfully.

Thursday, February 6, 2014

OSB or BPEL - A practical approach to pick one for your Integration use case

Oracle BPEL and Oracle Service Bus both offer many common features making it difficult to choose one for a particular integration scenario.However both have a different focus at application integration. OSB on routing and BPEL on orchestration. A detailed look at your use case needs from the current and futuristic view should give you a cue on which one to pick.

For example consider the integration scenario illustrated in the figure below.


The integration features mentioned in the above diagram can be achieved by Oracle Service Bus and also Oracle BPEL. So which one to chose depends on multiple factors.

a. Does application B changes its end points frequently?
b. Do you need a extensive transformation capabilities between xml files , binaries and texts or across each of them ?
c. Are you looking for a Asynchronous two way communication between your service and applications.?
d. Are you in need of automatic service load balancing ( note : just not node lode balancing given by cluster)?
e. How is the integration between these systems change in the future? Is the logic going to change too dynamically or is it going to get too detailed ( complex) or does it going to expand by interacting with many more applications.?
f. and Of course the licensing details.

The below table illustrates the features of integration that OSB is better than BPEL. If your integration scenario has priority over the below features then you should prefer OSB.


Oracle Service Bus offers additional ( specific features that BPEL does not) features such as

1. Built in features to generate reports and dashboards.
2. Define SLA's and trigger alerts based on them.
3. Service-artifacts dependancy tracking.
4. Ability to use MFL and Xquery.
5. Developing the orchestration at the run time using console.

Lets now see the features that Oracle BPEL is expert at -



As described above,you should tend to using BPEL when your focus in on orchestration ( ahh this same old thing every blog said but just true !!) and on more back and forth interaction with SCA components and SOAP services.

The following are the features which both Oracle BPEL and OSB provides ( although each of them provides few features in better ways than the other)

Common Features:

1. Support to various transport/message protocols
such as - HTTP, SOAP, REST, JMS, File, FTP, SMTP, IMAP, POP
        Note : OSB has an minor edge in protocol support in two way
a. More protocols are supported.
b. OSB exposes JMS, File, FTP as direct transport versus via adapter which (probably) offers higher               performance as adapters is another level of logic to access the same.

2.  Support to Technology/Application/Packaged adapters.
3. Interaction with Message oriented middleware  ( Queues, Topics etc)
4. Cluster support.
5. Content / Header based routing.
6. Transformation ( XSLT in BPEL , XQUERY/XSLT/MFL in OSB.)
7. Calling Java code. ( Java embedding in BPEL and Java callout in OSB)
8. Dynamic routing based on business logic.
    -via ws addressing changes to partner links in BPEL and dynamic Routing node in OSB
9.Calling external services ( Business services / service callout in OSB , partner links in BPEL)

Conclusion :
                  The features you want to enable in your integration may seem to be achieved by using either of the components -OSB or BPEL. However a thin line can be drawn when you have a detailed look at the additional capabilities that you want to have along with the basic features.Those features may not be a part of current requirements but may be in the future. A true architect should be able to visualize those and make sure that the right component is picked in the first go.

Saturday, August 4, 2012

Connection to SQl Server from JDeveloper to work with DB Adapters in SOA 11g

This post explains 


a) Setup the SqlServer's connection in Jdeveloper 11g.
b) Creating the DB Adapter in Weblogic console to access the SQl Server database.


Steps:

1. Add Oracle’s SQL JDBC driver (Present in Weblogic home/Server/lib) to JDeveloper. Files to copy would be weblogic.jar, wlclient.jar and wlsqlserver.jar. Create a folder called OracleJDBC_MSSQL_Driver under <your path>Oracle/Middleware folder and copy these files in there. Also add these files to the JDeveloper classpath.

2. Create the DB connection with the following :ConnectionType : Generic JDBC.DriverClass : weblogic.jdbc.sqlserver.SQLServerDriver.Library: OracleJDBC_MSSQL_Driver  ( browse the above path in which you have the 3 jars)
3. Jdbc url woud be like : jdbc:weblogic:sqlserver://<hostname>:<portname>;DatabaseName=<yourDBName>Note : its a semi colon after port and not a :

4.Create a new JDBC data source with JNDI value you like  and database type as MS SQL Server. Selected Database driver as Oracle’s MS SQL Server Driver (Type 4) Version 7.0.

5. Make sure you have the DB Adapter's Conection pool properties like below :


a.datasourcename : Your Sql Server datasource name created in above step.
b.platformClassName -  oracle.toplink.platform.database.SQLServerPlatform.
(The default one i.e org.eclipse.persistence.platform.database.Oracle10Platform is for connecting to Oracle Databases.)
c. defaultNchar should be 'false'.
d. sequencePreallocationSize to 50.
e. batchwriting - true.
f. nativesequencing - true.
g. skipLocking - true. 



Tuesday, July 31, 2012

Dealing with Multiple Sources in XSLT in SOA 11g

Quite often we need to derive the values into a variable(target) from more than single source.
SOA 11g Transform activity provides us a way to tag multiple sources in the wizard itself as shown below.


Where source1Var and source2Var are two different sources. If you observe closely in the source code for the same transform activity , the code snapshot pasted below



            <copy>
                <from>ora:doXSLTransformForDoc("xsl/XformSource1Source2ToTarget.xsl", $source1Var, "source2Var", $source2Var)</from>
                <to variable="targetVar"/>
            </copy>

The first source(source1Var) is passed as the normal source to XSL where as the second one is sent as a parameter to the same with the name source2Var and the value of the same is $source2Var.

Also if you open the xsl in source mode you can find that 
....
  <xsl:param name="source2Var"/>
....
So now you can use this second source ( anything other than primary source) as a parameter inside the xslt mapping.

Now lets see how we can work on multiple sources in XSLT. Lets say you have requirement like this.

1. Some of Target variables data elements depend on source1var.
2. Some of them depend on source2Var.
3. Some of them are dependent on source1Var and source2Var in a complex way. ie.,Lets assume a scenario such as -
Loop through the source2 for each record of source1 , then find that record whose "id"(of source2) matches with "id" of source1.Now then multiply   source1Var/x  element with the fetched record of source2Var/y.

1,2 are pretty straightforward with the mapping done directly. 
Coming to scenario 3 we may need to tweak xslt a little bit like below by using some local variables.

         <xsl:for-each select="source1Var/ yourComplexElementForSource1">
             <xsl:variable name="id" select="id"/>
              <xsl:variable name="x" select="x"/>
              <xsl:variable name="y" select="$source2Var/yourComplexElementForSource2[id= $id)]/y"/>
          <targetVarElement>
            <xsl:value-of select="$x * $y"/>
          </targetVarElement>
        </xsl:for-each>

If you observe we are using an inline xpath matching of the value id  of source2(id) with id of source1($id). This acts like another loop(on source2's complex element) for us ( avoiding a real loop to be written).
So thats it ! It works.

A related question is posted on oracle forums recently- https://forums.oracle.com/forums/thread.jspa?threadID=2421631&tstart=0
Please find below is the solution for the same using the above mentioned approach.

A Sample implementation of the concept exaplained above: 

source1.xsd

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://www.example.org"
            targetNamespace="http://www.example.org"
            elementFormDefault="qualified">
  <xsd:element name="docTypeRef_tns_RetrieveGetDataResponse">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="instrumentDatas">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="instrumentData" maxOccurs="unbounded">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="instrument">
                      <xsd:complexType>
                        <xsd:sequence>
                          <xsd:element name="id" type="xsd:string"/>
                          <xsd:element name="yellowkey" type="xsd:string"/>
                        </xsd:sequence>
                      </xsd:complexType>
                    </xsd:element>
                    <xsd:element name="data" maxOccurs="unbounded">
                      <xsd:complexType>
                        <xsd:attribute name="value" type="xsd:string"/>
                      </xsd:complexType>
                    </xsd:element>
                  </xsd:sequence>
                </xsd:complexType>
              </xsd:element>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

source2.xsd

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://www.example.org"
            targetNamespace="http://www.example.org"
            elementFormDefault="qualified">
  <xsd:element name="MyElement">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="TmsBmbrgRateslist" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="curcyPair" type="xsd:string"/>
              <xsd:element name="rate" type="xsd:integer"/>
              <xsd:element name="rDate" type="xsd:integer"/>
              <xsd:element name="attrib1" type="xsd:string"/>
              <xsd:element name="attrib2" type="xsd:string"/>
              <xsd:element name="attrib3" type="xsd:integer"/>
              <xsd:element name="attrib4" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="xsi" type="xsd:string"/>
      <xsd:attribute name="schemaLocation" type="xsd:string"/>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

target.xsd

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://www.example.org"
            targetNamespace="http://www.example.org"
            elementFormDefault="qualified">
  <xsd:element name="F1113Collection">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="F1113" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="c1Rtty" type="xsd:string"/>
              <xsd:element name="c1Crdc" type="xsd:string"/>
              <xsd:element name="c1Crcd" type="xsd:string"/>
              <xsd:element name="c1Crr" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
      <xsd:attribute name="ns2" type="xsd:string"/>
      <xsd:attribute name="xsi" type="xsd:string"/>
      <xsd:attribute name="schemaLocation" type="xsd:string"/>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

Requirement :

Populate "c1Crr" field of target based on below logic.

if(<instrumentData>/<instrument>/<id> = <TmsBmbrgRateslist>/<curcyPair>)
{
c1Crr = <instrumentData>/data[2]/@value * <TmsBmbrgRateslist>/attrib3
}

XSLT Mapping:

<?xml version="1.0" encoding="UTF-8" ?>
<?oracle-xsl-mapper
  <!-- SPECIFICATION OF MAP SOURCES AND TARGETS, DO NOT MODIFY. -->
  <mapSources>
    <source type="XSD">
      <schema location="../xsd/source1.xsd"/>
      <rootElement name="docTypeRef_tns_RetrieveGetDataResponse" namespace="http://www.example.org"/>
    </source>
    <source type="XSD">
      <schema location="../xsd/source2.xsd"/>
      <rootElement name="MyElement" namespace="http://www.example.org"/>
      <param name="source2Var" />
    </source>
  </mapSources>
  <mapTargets>
    <target type="XSD">
      <schema location="../xsd/target.xsd"/>
      <rootElement name="F1113Collection" namespace="http://www.example.org"/>
    </target>
  </mapTargets>
  <!-- GENERATED BY ORACLE XSL MAPPER 11.1.1.5.0(build 110418.1550.0174) AT [WED AUG 01 02:09:19 IST 2012]. -->
?>
<xsl:stylesheet version="1.0"
                xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
                xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
                xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
                xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
                xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:ns0="http://www.example.org"
                xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
                xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:med="http://schemas.oracle.com/mediator/xpath"
                xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
                xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
                xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
                xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:bpmn="http://schemas.oracle.com/bpm/xpath"
                xmlns:ora="http://schemas.oracle.com/xpath/extension"
                xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator"
                xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap"
                exclude-result-prefixes="xsi xsl ns0 xsd bpws xp20 mhdr bpel oraext dvm hwf med ids bpm xdk xref bpmn ora socket ldap">
  <xsl:param name="source2Var"/>
  <xsl:template match="/">
    <ns0:F1113Collection>
      <xsl:for-each select="/ns0:docTypeRef_tns_RetrieveGetDataResponse/ns0:instrumentDatas/ns0:instrumentData">
        <ns0:F1113>
          <ns0:c1Rtty>
            <xsl:value-of select='string("A")'/>
          </ns0:c1Rtty>
          <ns0:c1Crdc>
            <xsl:value-of select="substring(ns0:instrument/ns0:id,4,3)"/>
          </ns0:c1Crdc>
          <ns0:c1Crcd>
            <xsl:value-of select="substring(ns0:instrument/ns0:id,1,3)"/>
          </ns0:c1Crcd>
          <xsl:variable name="id" select="ns0:instrument/ns0:id"/>
          <xsl:variable name="dataValue" select="ns0:data[2]/@value"/>
          <xsl:variable name="attrib3"
                        select="$source2Var/ns0:MyElement/ns0:TmsBmbrgRateslist[(ns0:curcyPair = $id)]/ns0:attrib3"/>
          <ns0:c1Crr>
            <xsl:value-of select="$dataValue * $attrib3"/>
          </ns0:c1Crr>
        </ns0:F1113>
      </xsl:for-each>
    </ns0:F1113Collection>
  </xsl:template>
</xsl:stylesheet>

References:
1. http://blogs.oracle.com/soa_how_to/entry/how_to_implement_multi-source_xslt_mapping_in_11g_bpel
2. http://java.net/downloads/oraclesoasuite11g/Transformations/mapper-105-multiple-sources.zip

Wednesday, June 27, 2012

Element Not Null check in XSLT:

This basically includes two checks :
1. Element not present / existing.
2. Element existing and not empty.

Solution 1:

        <xsl:if test="not(ns1:VisitElement/ns1:visitSequence) or
string-length(ns1:VisitElement/ns1:visitSequence)=0">
            <xsl:value-of select="string('HELLO')"/>
        </xsl:if>

Explanation : In the above example visitSequence is checked for no existence (or) if it exists if its length is zero. In this case we are replacing the value with string called " HELLO"

Another way for doing the same is as below :

Solution 2: 


        <xsl:if test="not(ns1:VisitElement/ns1:visitSequence) or
                                 ns1:VisitElement/ns1:visitSequence[.!='']">
            <xsl:value-of select="string('HELLO')"/>
        </xsl:if>

The expression [.!='']  means that the current node (represented by dot) is not equal(!=) to an empty string('').