Wednesday, June 23, 2010

Cache - Least Recently Used Algorithm

LRU algorithm is heavily used in most of the cache implementation. In general, most of the time we depend on heavy weighted caching implementation and end up paying huge for that softwares.

java.util.LinkedHashMap provides simplest way to do this by overriding a method removeEldestEntry().

Here, I would like to present as an utilit class which will be reused our needs. New class LRUHashMap created from LinkedHashMap and cacheSize limit has to be passed as argument.

LRUHashMap Implementation

LRUHashMap.java 
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * LRUHashMap implements Least Recently Used algorithm to store and retrive the
 * values from {Map}.
 */

public class LRUHashMap<K, V> extends LinkedHashMap<K, V> {

 private static final long serialVersionUID = -6805360112277349979L;
 private final static int DEFAULT_INITIALCAPACITY = 10;
 private final static float LOADFACTOR = 0.75f;

 /**
  * Number of entries possible to keep maximum in given time in this {Map}
  */
 private final int cacheSize;

 public LRUHashMap() {
  super(DEFAULT_INITIALCAPACITY, LOADFACTOR, true);
  cacheSize = -1;
 }

 public LRUHashMap(int cacheSize) {
  super(DEFAULT_INITIALCAPACITY, LOADFACTOR, true);
  this.cacheSize = cacheSize;
 }
 
 /**
  * @param initialCapacity
  */
 public LRUHashMap(int initialCapacity, int cacheSize) {
  super(initialCapacity, LOADFACTOR, true);
  this.cacheSize = cacheSize;
 }

 /**
  * @param m
  */
 public LRUHashMap(Map<K, V> m, int cacheSize) {
  super(DEFAULT_INITIALCAPACITY, LOADFACTOR, true);
  putAll(m);
  this.cacheSize = cacheSize;
 }

 /**
  * @param initialCapacity
  * @param loadFactor
  */
 public LRUHashMap(int initialCapacity, float loadFactor, int cacheSize) {
  super(initialCapacity, loadFactor, true);
  this.cacheSize = cacheSize;
 }



 
 /** To achieve Thread Safe
 * @return
 */
 public Map<K, V> getsynchronizedMap()
 {
  return Collections.synchronizedMap(this);
 }

 @Override
 protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
  return size() > cacheSize;
 }
}

Test

LRUHashMapTest.java

public class LRUHashMapTest {

 public static void main(String[] args) {
  Map<Integer, String> map = new LRUHashMap<Integer, String>(10);
  
  //Enables Thread Safe
  //map = ((LRUHashMap<Integer, String>)map).getsynchronizedMap();
  
  for (int i = 0; i < 100; i++) {
   map.put(i, "valueof :" + i);

   for (int j = i - 5; j >= 0; j--)
    map.get(j);
  }

  System.out.println(map);
 }
}

Here, Cache Size set to 10, hence at any given time only 10 entries will be stored in Map. Additionally, whenever read access happens that object will be removed from actual location and added to rear of Map.

Output:

{95=valueof :95, 96=valueof :96, 97=valueof :97, 98=valueof :98, 99=valueof :99,
 4=valueof :4, 3=valueof :3, 2=valueof :2, 1=valueof :1, 0=valueof :0}

Thread Safe

The above mentioned implementation alone will not achieve thread safe. If our application is multi-threaded then we may need to fall-back to Collections.SynchronizedMap. We can achieve this by calling getsynchronizedMap(); in LRUHashMap.
Map<Integer, String> map = ((LRUHashMap<Integer, String>)map).getsynchronizedMap();

Monday, June 7, 2010

PropertyIgnoreCase

java.util.Properties helps to store and retrieve the key-value pair, where non-null values in key and value. This implementation made on top of java.util.HashTable. We do get all the features and APIs of HashTable additionally, getProperty(...), load() APIs.

In getProperty method, key has to be passed as argument to retrive the value. We can even specify the default value also in it, if no key found in list.

Then, What makes different in this blog posting ?. Here, the key is case-sensitive one. We have to send exact word to get the value. Most of the time, we may need to retrieve value for case-insensitive key. This is where, why don't we extend the functionality to give support to retrieve value with case-insensitive key.

Here, Properties extended to create PropertyIgnoreCase class, and added two APIs - getPropertyIgnoreCase(String key), getPropertyIgnoreCase(String key, String defaultV)


import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;

public class PropertyIgnoreCase extends Properties {

 private static final long serialVersionUID = 7511088737858527084L;

 /**
  * get value from {Properties}
  * 
  * @param props
  * @param key
  * @return
  */
 public String getPropertyIgnoreCase(String key) {
  return getPropertyIgnoreCase(key, null);
 }

 /**
  * get value from {Properties}, if no key exist then return default value.
  * 
  * @param props
  * @param key
  * @param defaultV
  * @return
  */
 public String getPropertyIgnoreCase(String key, String defaultV) {
  String value = getProperty(key);
  if (null != value)
   return value;

  // Not matching with the actual key then
  Set<Entry<Object, Object>> s = entrySet();
  Iterator<Entry<Object, Object>> it = s.iterator();
  while (it.hasNext()) {
   Entry<Object, Object> entry = it.next();
   if (key.equalsIgnoreCase((String) entry.getKey())) {
    return (String) entry.getValue();
   }
  }
  return defaultV;
 }

 public static void main(String[] args) {
  PropertyIgnoreCase props = new PropertyIgnoreCase();
  props.put("Abc", "Value of Abc");
  props.put("xYZ", "Value of xYZ");

  System.out.println("get Key 'XYZ' using API from Properties = "
    + props.getProperty("XYZ"));
  System.out.println("get Key 'XYZ' using new API  = "
    + props.getPropertyIgnoreCase("XYZ"));
 }

}
Output:
get Key 'XYZ' using API from Properties = null
get Key 'XYZ' using new API  = Value of xYZ

Thursday, March 11, 2010

Sample XSLT Processor

Extensible Style Language Transformation (XSLT) helps to convert an XML from one form to another. Resulting format could be anything, it could be XML, HTML, XFDF, and etc.,.

XSLT Mapper file

Most of the IDE provides XSLT auto mapping facility to convert/map from one XSD format to another XSD format. XPATH, XQuery, and XSLT functions helps to locate and manipulate the source XML file and result the format in target.

XSLT Processor

XSLT processing capability/library comes with most of the popular languages.


import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;

import oracle.xml.parser.v2.DOMParser;
import oracle.xml.parser.v2.XMLDocument;
import oracle.xml.parser.v2.XMLParseException;
import oracle.xml.parser.v2.XSLException;
import oracle.xml.parser.v2.XSLProcessor;
import oracle.xml.parser.v2.XSLStylesheet;

import org.xml.sax.SAXException;

public class XSLTTransformation {
public static void main(String[] args) throws MalformedURLException,
XSLException, XMLParseException, SAXException, IOException {

URL xslURL = new URL("file:///tmp/shiporder.xsl");

URL xmlURL = new URL("file:///tmp/shiporder.xml");

XSLProcessor processor = new XSLProcessor();
XSLStylesheet xsl = processor.newXSLStylesheet(xslURL);

// parser input XML content
DOMParser parser = new DOMParser();
parser.setPreserveWhitespace(true);
parser.parse(xmlURL);

XMLDocument xml = parser.getDocument();
processor.showWarnings(true);
processor.setErrorStream(System.err);

// Transform the document
StringWriter strWriter = new StringWriter();
processor.processXSL(xsl, xml, new PrintWriter(strWriter));

System.out.println("Transformed XML file: "
 + strWriter.getBuffer().toString());
strWriter.close();
}
}
javas -cp xmlparserv2.jar XSLTTransformation.java

javas -cp xmlparserv2.jar XSLTTransformation

In the following xml file, If we apply below given XSLT then city and note element are get removed.

shiporder.xml

<?xml version="1.0" encoding="UTF-8" ?>
<shiporder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.example.org a.xsd" 
orderid="1" ns0="ns02" xsi="xsi3" xmlns="http://www.example.org">
   <orderperson>orderperson4</orderperson>
   <shipto>
      <name>name5</name>
      <address>address6</address>
      <city>city7</city>
      <country>country8</country>
   </shipto>
   <item>
      <title>title9</title>
      <note>note10</note>
      <quantity>11</quantity>
      <price>120.72</price>
   </item>
   <item>
      <title>title13</title>
      <note>note14</note>
      <quantity>15</quantity>
      <price>160.73</price>
   </item>
   <item>
      <title>title17</title>
      <note>note18</note>
      <quantity>19</quantity>
      <price>200.73</price>
   </item>
</shiporder>

shiporder.xsl

<?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="../a.xsd"/>
      <rootElement name="shiporder" namespace="http://www.example.org"/>
    </source>
  </mapSources>
  <mapTargets>
    <target type="XSD">
      <schema location="../b.xsd"/>
      <rootElement name="shiporder" namespace="http://www.example.org"/>
    </target>
  </mapTargets>
  <!-- GENERATED BY ORACLE XSL MAPPER 11.1.1.2.0(build 091116.1400.3492) AT [THU MAR 11 12:51:59 IST 2010]. -->
?>
<xsl:stylesheet version="1.0"
                xmlns:xpath20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
                xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
                xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
                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: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 xpath20 bpws mhdr oraext dvm hwf med ids bpm xdk xref ora socket ldap">
  <xsl:template match="/">
    <ns0:shiporder>
      <xsl:attribute name="orderid">
        <xsl:value-of select="/ns0:shiporder/@orderid"/>
      </xsl:attribute>
      <xsl:attribute name="ns0">
        <xsl:value-of select="/ns0:shiporder/@ns0"/>
      </xsl:attribute>
      <xsl:attribute name="xsi">
        <xsl:value-of select="/ns0:shiporder/@xsi"/>
      </xsl:attribute>
      <xsl:attribute name="schemaLocation">
        <xsl:value-of select="/ns0:shiporder/@schemaLocation"/>
      </xsl:attribute>
      <ns0:orderperson>
        <xsl:value-of select="/ns0:shiporder/ns0:orderperson"/>
      </ns0:orderperson>
      <ns0:shipto>
        <ns0:name>
          <xsl:value-of select="/ns0:shiporder/ns0:shipto/ns0:name"/>
        </ns0:name>
        <ns0:address>
          <xsl:value-of select="/ns0:shiporder/ns0:shipto/ns0:address"/>
        </ns0:address>
        <ns0:country>
          <xsl:value-of select="/ns0:shiporder/ns0:shipto/ns0:country"/>
        </ns0:country>
      </ns0:shipto>
      <xsl:for-each select="/ns0:shiporder/ns0:item">
        <ns0:item>
          <ns0:title>
            <xsl:value-of select="ns0:title"/>
          </ns0:title>
          <ns0:quantity>
            <xsl:value-of select="ns0:quantity"/>
          </ns0:quantity>
          <ns0:price>
            <xsl:value-of select="ns0:price"/>
          </ns0:price>
        </ns0:item>
      </xsl:for-each>
    </ns0:shiporder>
  </xsl:template>
</xsl:stylesheet>
Refer Convert XMLElement/XMLDocument to String

Recent Posts

Unix Commands | List all My Posts

Texts

This blog intended to share the knowledge and contribute to JAVA Community such a way that by providing samples and pointing right documents/webpages. We try to give our knowledege level best and no guarantee can be claimed on truth. Copyright and Terms of Policy refer blogspot.com