Friday, March 11, 2016

Getting JDK information in Gradle to add tools.jar as dependency

Many times we would have the necessity of tools.jar into our class path at runtime. Mostly when you do something with compile or javadoc.
The best way which I found to do this is ask the Gradle itself to give JVM information and get tools.jar or rt.jar (runtime jar) from it.

Gradle have a singleton Class org.gradle.internal.jvm.Jvm which give the information about the JVM. The JAVA_HOME or java.home directory, runtime jar, tools jar, calling any other executable from the jdk, etc.

dependencies {
   runtime files(org.gradle.internal.jvm.Jvm.current().toolsJar)
}
Works well for Gradle project in eclipse or when running in a build street. Note that when you need tools.jar in eclipse. the Gradle work environment must be set to use JDK instead of JRE. This can be done in eclipse preferences of Gradle.
import org.gradle.internal.jvm.Jvm
println Jvm.current().javaHome
println Jvm.current().javacExecutable
println Jvm.current().javadocExecutable

You can also get other information from Jvm class. It implements interface org.gradle.internal.jvm.JavaInfo which has following outline.

Wednesday, December 30, 2015

Applying grouping on a Collection

Best practice to convert List to a Map. In other words how to apply grouping on a List or Collection without writing separate methods for each.

I recently came across a case where grouping was done at many places on different grouping criteria. Every thing in that is same except of the grouping criteria.
For example; If I have a collection of Persons and I want to group them by Salary. Then it becomes a Map with String as key and List of persons as the value
// Original list
List<Person>
// Expected group
Map<String, List<Person>>
    private static Map<String, List<Person>> groupBySalary(List<Person> persons) {
        Map<String, List<Person>> groupedMap = new HashMap<String, List<Person>>();
        for (Person p : persons) {
            // Grouping criteria
            String role = p.getRole();
            List<Person> list = groupedMap.get(role);
            if (list == null) {
                // not exist in group. create and add for first time.
                list = new ArrayList<Person>();
                groupedMap.put(role, list);
            }
            list.add(p);
        }
        return groupedMap;
    }

Later if we want to group it by Role or First name or maybe some thing different; then the Declaration remains the same but we need to write different methods. This is not a nice practice to duplicate the code. See the class ListToMapHelper which demonstrate how a list can be grouped easily to Map by providing the grouping criteria on the fly. Something like you provide the Sorting criteria for Collections class. In same way you provide the Grouping criteria to this Helper static method. With lambda expressions in Java 8 this is again must simpler with just one line code. See main method for usage.

package in.mbm.playground;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;


/**
 * 
 * @author Mohammed Bin Mahmood
 *
 */
public class ListToMapHelper {

    public interface IGroupingCriteria<G, T> {
        /**
         * Takes a Type T from which Grouping has to be done. check main method for the usage.
         * 
         * @param type T
         * @return Object of type G which is the grouping criteria.
         */
        public G group(T type);
    };

    /**
     * Takes an Iterable and Grouping criteria implementation and returns a Map grouped by the
     * criteria.
     * 
     * @param iteratableCollection
     * @param groupBy
     * @return
     */
    public static <G, T> Map<G, List<T>> groupBy(Iterable<T> iteratableCollection, IGroupingCriteria<G, T> groupBy) {
        Map<G, List<T>> map = new HashMap<G, List<T>>();
        for (T type : iteratableCollection) {
            // grouping criteria
            G group = groupBy.group(type);

            List<T> list = map.get(group);
            if (list == null) {
                // not exist in group. create and add for first time.
                list = new ArrayList<T>();
                map.put(group, list);
            }
            list.add(type);
        }
        return map;
    }

    public static void main(String[] args) {
        // assume list of persons is populated
        List<Person> persons = fillSomePersons();

        // group persons by Role.
        // provide the implementation of IGroupingCriteria with String as Key and Person as the Type
        // itself

        Map<String, List<Person>> map = groupBy(persons, new IGroupingCriteria<String, Person>() {

            @Override
            public String group(Person p) {
                // group by role.
                return p.getRole();
            }
        });

        // by Java 8
        map = groupBy(persons, p -> p.getRole());

        // print and see the results.
        for (Entry<String, List<Person>> entry : map.entrySet()) {
            System.out.println(entry.getKey() + "\t" + entry.getValue());
        }
    }

    private static class Person {
        private final int id;
        private String name, role;

        Person(int id) {
            this.id = id;
        }

        Person setName(String name) {
            this.name = name;
            return this;
        }

        String getRole() {
            return role;
        }

        Person setRole(String role) {
            this.role = role;
            return this;
        }

        @Override
        public String toString() {
            return id + " " + name + " " + role;
        }
    }

    private static List<Person> fillSomePersons() {
        List<Person> persons = new ArrayList<ListToMapHelper.Person>(5);
        persons.add(new Person(1).setName("Person A").setRole("Role A"));
        persons.add(new Person(2).setName("Person B").setRole("Role A"));
        persons.add(new Person(3).setName("Person C").setRole("Role B"));
        persons.add(new Person(4).setName("Person D").setRole("Role B"));
        persons.add(new Person(5).setName("Person E").setRole("Role A"));
        persons.add(new Person(6).setName("Person F").setRole("Role A"));
        persons.add(new Person(7).setName("Person G").setRole("Role B"));
        persons.add(new Person(8).setName("Person H").setRole("Role C"));
        persons.add(new Person(9).setName("Person I").setRole("Role A"));
        return persons;
    }

    private static Map<String, List<Person>> groupByRole(List<Person> persons) {
        Map<String, List<Person>> groupedMap = new HashMap<String, List<Person>>();
        for (Person p : persons) {
            // Grouping criteria
            String role = p.getRole();
            List<Person> list = groupedMap.get(role);
            if (list == null) {
                // not exist in group. create and add for first time.
                list = new ArrayList<Person>();
                groupedMap.put(role, list);
            }
            list.add(p);
        }
        return groupedMap;
    }
}


Hope this example helps. Do share your feedback and pass it on.

Thursday, October 4, 2012

How to display Window in the center of the screen

In Java, many of the swings applications by default opens the window at the top left corner of the screen. In addition to setting the size and making it visible, we also need to set the coordinates where the new window has to be displayed. To show the window in the center of the given screen/monitor, I have written an example explained below.

This example automatically takes the current screen resolution and depending on the size (of the window) provided, it adjusts the start point of the screen.

Friday, June 24, 2011

Parsing Multiple XML Tags

How to parse XML with different multiple tags? For instance, I have a root tag element and few child tags with same name. For below is the snippet for the XML I will be providing parsers for
Multiple XML Tags
multiple-tags.xml
<?xml version="1.0" encoding="UTF-8"?>
<rootTag Name="Root">
 <ChildOne activityType="Task">
  <Name>P1</Name>
  <Incoming>0</Incoming>
  <Outgoing>P1P2</Outgoing>
 </ChildOne>
 <ChildOne activityType="Task">
  <Name>P2</Name>
  <Incoming>P1P2</Incoming>
  <Outgoing>P2G1</Outgoing>
 </ChildOne>
 <ChildOne activityType="GatewayParallel">
  <Name>G1</Name>
  <Incoming>P2G1</Incoming>
  <Outgoing>G1P3 G1P4</Outgoing>
 </ChildOne>
 <ChildTwo type="bpmn:SequenceEdge">
  <Name>P1P2</Name>
  <Source>P1</Source>
  <Destination>P2</Destination>
  <Path>P1P2</Path>
 </ChildTwo>
 <ChildTwo type="bpmn:SequenceEdge">
  <Name>P2G1</Name>
  <Source>P2</Source>
  <Destination>G1</Destination>
  <Path></Path>
 </ChildTwo>
 <ChildTwo type="bpmn:SequenceEdge">
  <Name>G1P3</Name>
  <Source>G1</Source>
  <Destination>P3</Destination>
  <Path>P2P3</Path>
 </ChildTwo>
</rootTag>

Monday, March 7, 2011

Difference in two Calendar Dates

There are many ways to calculate the difference between two Calendar dates in Year, Months, weeks or days by simply dividing them with a fixed constant. DateUtil.java below has a method for getting the difference in Days. this method can similarly be modified to get in Weeks, Months or Years.

But some times the challenge is to display the difference in two java.util.Calendar  or java.util.Date in more user friendly manner. Like in format X Years, X months, X weeks, X days. Where X is positive number greater than zero.

Example: If the number of Full Years < 1, the format should be X months, X weeks, X days. If the number of Full Years >= 1 but the number of Full Months < 1, the format should be X Years, X weeks, X days and so on. Values of 0 is not written. Like "2 months, 2 days" rather than "2 months, 0 weeks, 2 days"

Thursday, February 3, 2011

How to read file without locking in Java

In java, we can read or write to a file without acquiring locks to it. These are mostly used for log files. Recently I was tying to mimic the tail command (of Linux) in java and wrote a simple program below.

Using java.io.RandomAccesFile we can read/write to a file without obtaining locks. Let me demonstrate with example step by step how it works.

RandomAccessFile accessFile = new RandomAccessFile(file, "r");

Create an instance of the RandomAccessFile by either passing java.io.File or a path of a file. The second constructor argument is the type of access needed. In this case it is read only "r". If you want to make it read/write pass "rw". Like Buffers of java.nio package, this class also works with the pointers. it reads the bytes and move the pointer as it progresses. The current pointer gives the information about how much of the file have bean read or has to be read.

public void print(OutputStream stream) throws IOException {
    long length = accessFile.length();
    while (accessFile.getFilePointer() < length) {
        stream.write(accessFile.read());
    }
    stream.flush();
}

Tuesday, January 18, 2011

Where to use MAP and where not

Map is a collection object which contains a key - value pair. Key is unique for identification and Value is the actual object itself. For example to store employees backed with their IDs.
  • 001 - Employee One
  • 002 - Employee Two
  • 003 - Employee Three
Point I will be stressing is the uniqueness of the Key in a Map. Keys inside a java.util.Map  will be stored as a java.util.Set no matter what implementation it is. Either java.util.HashMap or java.util.LinkedHashMap (where sequence or retrieval is retained). If we are adding objects to a Map using map.put(key,value) and retrieving using key by map.get(key), then yes we are using the Map.

Let me justify it futher. When using map.put(), map will check if there is any java.util.HashMap.Entry with the key passed. If so then it will replace the value with a new one and returns the previous Value. But the process of checking of unique key is complex. it involves method like key.equals() and key.hashcode(). Imagine if we have 100 objects to be added to a map, this comparison is done that many times irrespective if there is already an entry or not.
So, when we really think that we need to get benefited by the java.util.Set (inside the Map) then yes, usage of Map is encouraged. Many times, we do not want the feature of unique keys, we know that the Map will be populated with unique data but I want to retrieve objects by their keys, for example get Employee object with the help of an employee ID or java.util.Properties would be the best example for retrieval by keys. Here we use map.get() extensively. In this scenario there is no option but to going for Map unless you have written your own framework to retreive objects by key without using a Map.
If we have a scenario where we just use flat iteration over a map where we populate map by unique data or we don't consider uniqueness and we do not use map.get() even. We just iterate over all entries and use the data from both key and value to do some kind of processing then I would not prefer java.util.Map. Yes, there is an alternate which follows.
I would use any simple Collection object like java.util.List of type like EntryData and iterate over it.
            List<EntryData> data = new ArrayList<EntryData>(1);
            data.add(new EntryData("Some key", "Some vallue"));
            for(EntryData entry: data){
                processKey(entry.key);
                processValue(entry.value);
            }

in this way, I am preparing data which has a pair of key and value. But without using a features of map.get(key) method or I would say any feature of java.util.Map. I do not have a best example right now to describe where this could actually be used in real time. But believe me we do need this. I needed this kind of approach recently and figured out that usage of java.util.Map is not always a best practice in terms of performance.

EntryData.java
    private static class EntryData {
        final Object key,value;

        public EntryData(Object key, Object value) {
            this.key= key;
            this.value= value;
        }
    }