Wednesday, September 21, 2011

Ranges and Sequences in Java Interface

Friends,

We often come across requirements where we have to create interfaces to define contiguous constants or a sequence of constants in an interface may be because they represent array indexes.
But such a code becomes hurdle when we need to add one or more constants in-between the existing list of contiguous constants.

e.g. in the following code snippet:


public interface XYZConstants
{
      public static final int A1 = 0;
      public static final int A2 = 1;
      public static final int A3 = 2;
      public static final int A4 = 3;
      public static final int A5 = 4;
      public static final int A6 = 5;
      public static final int A7 = 6;
}

If you want to add say A31, A32 and A33 between A3 and A4, you will need to modify the values of all the constants after A3 as shown below:



public interface XYZConstants
{
      public static final int A1 = 0;
      public static final int A2 = 1;
      public static final int A3 = 2;
      public static final int A31 = 3;
      public static final int A32 = 4;

      public static final int A33 = 5;
      public static final int A4 = 6;
      public static final int A5 = 7;
      public static final int A6 = 8;
      public static final int A7 = 9;
}

This is fine if the list is small but what if the list has 5000 constants and you want to add after 1500 and you can't just append at the last because the code will become haphazard ?

How nice it would be if we can just increment some integer counter or sequence but the problem is that interfaces do not allow arithmetic operations in the assignment and only allow fields to be public static and final.

Following is one possible solution:

package test;

/**
 * @author ujariya
 *
 */
public interface InterfaceCounter
{
      public static final int A1 = Counter.nextVal(0,10);
      public static final int A2 = Counter.nextVal();
      public static final int A3 = Counter.nextVal();
      public static final int A4 = Counter.nextVal();
      public static final int A5 = Counter.nextVal();
      public static final int A6 = Counter.nextVal();
      public static final int A7 = Counter.nextVal();
     
      public static final int A8 = Counter.nextVal(200, 300);
      public static final int A9 = Counter.nextVal();
      public static final int A10 = Counter.nextVal();
      public static final int A11 = Counter.nextVal();
      public static final int A12 = Counter.nextVal();
      public static final int A13 = Counter.nextVal();
      public static final int A14 = Counter.nextVal();
      public static final int A15 = Counter.nextVal();
     
      class Counter
      {
            private static int count_ = 0;
            private static int max_ = Integer.MAX_VALUE;
           
            public static int nextVal()
            {
                  int ret = count_++;
                 
                  // The biggest flaw in this approach is, if the range exceeds,
                  // it will only be known at execution time when this class
                  // gets loaded in the JVM
                  // There is no Compile Time Catch :-)
                  if(ret > max_)
                        throw new RuntimeException(
                                    "Counter exceeded out of range: "+ret);
                 
                  return ret;
            }
           
            public static int nextVal(int seed, int max)
            {
                  count_ = seed;
                  max_ = max;
                  return count_++;
            }
      }
}

Here, we have a inner class Counter which statically keeps counting the next value and we get the contiguous range of constants in every case.

In the aforementioned example, you will just need to add the following lines wherever you like to add:

      public static final int A31 = Counter.nextVal();
      public static final int A32 = Counter.nextVal();

      public static final int A33 = Counter.nextVal();

This logic will guaranty that you always get a sequence no matter where you have added the new lines of code.

You can also maintain the ranges if you want but if your range gets exceeded, it can be identified at run-time only because the values will get calculated while loading the class in the JVM.


Regards,
~Upendra.


P.S.

If you wanna test the above logic, following is the testing code and test results:

public class InterfaceCounterTest
{
      public static void main(String[] args)
      {
            System.out.println(InterfaceCounter.A1);
            System.out.println(InterfaceCounter.A2);
            System.out.println(InterfaceCounter.A3);
            System.out.println(InterfaceCounter.A4);
            System.out.println(InterfaceCounter.A5);
            System.out.println(InterfaceCounter.A6);
            System.out.println(InterfaceCounter.A7);
            System.out.println(InterfaceCounter.A8);
            System.out.println(InterfaceCounter.A9);
            System.out.println(InterfaceCounter.A10);
            System.out.println(InterfaceCounter.A11);
            System.out.println(InterfaceCounter.A12);
            System.out.println(InterfaceCounter.A13);
            System.out.println(InterfaceCounter.A14);
            System.out.println(InterfaceCounter.A15);
      }
}

And the test results are:

0
1
2
3
4
5
6
200
201
202
203
204
205
206
207
 

Wednesday, December 15, 2010

The great book on Core Java...

Finally, I came to know that the Thread.stop() methods generates the ThreadDeath object and how to use the interrupted flag...

The great! great! book on Core Java:

Core Java - Volume 1 - Fundamentals
  by: Cay S. Horstmann & Gary Cornell
  PEARSON Education, Sun Microsystems

Saturday, May 30, 2009

Remove gphone.exe virus by Java Program

import java.io.File;
import java.io.FilenameFilter;

/**
* This programs removes files created by the gphone.exe virus
*
* This virus creates duplicate copies of itself (gphone.exe) into every folder
* of your system with the name that folder.
* The common behavior is that all virus files share the same size
* and the same lastModified date.
*
* Notes:
* + You may have to change the virusFileSize and lastModified variables below.
* + un-comment the "files[i].delete()" below to enable the deletion.
* + on a unix machine, following command is also useful
* + find . -name "*.exe" -printf "%s\t\t%f\n"
*
* @author ujariya
* @version 1.0 (30th May 2009)
*/

public class VirusExeDelete
{
static int virusCounter = 0;
// 1232372178000 => Mon Jan 19 19:06:18 IST 2009
// This time is in milliseconds
static long lastModified = new Long("1232372178000").longValue();
static int virusFileSize = 349184;

public static void main(String[] args)
{
System.out.println("Searching and Removing");
//File root = new File("/mnt/S_VIDEO");

// Run the search into every partition / PEN drives
findAndDeleteVirusFiles(new File("/mnt/S_DATA"));
findAndDeleteVirusFiles(new File("/mnt/S_MISC"));
findAndDeleteVirusFiles(new File("/mnt/S_MOVIES"));
findAndDeleteVirusFiles(new File("/mnt/S_OPSYS"));
findAndDeleteVirusFiles(new File("/mnt/S_SANGEET"));
findAndDeleteVirusFiles(new File("/mnt/S_TEMP"));
findAndDeleteVirusFiles(new File("/mnt/S_VIDEO"));

System.out.println("virusCounter: "+ virusCounter);
}

static void findAndDeleteVirusFiles(File dir)
{
File[] files = dir.listFiles();
for(int i=0; i
{
// Iterate recursively
if(files[i].isDirectory())
{
findAndDeleteVirusFiles(files[i]);
}

// Search / Destroy the virus
else if(files[i].getName().toLowerCase().endsWith(".exe")
&& files[i].length() == virusFileSize)
{
System.out.println(files[i].length()+ " "+ files[i].lastModified()+" " +files[i].getPath());
// delete viruses
// files[i].delete();
virusCounter++;
}

// Searching other files having same last modified date (within one minute) / file size
/* else if(Math.abs(files[i].lastModified() - lastModified) <>
{
System.out.println(files[i].length()+ " "+ files[i].lastModified()+" " +files[i].getPath());
virusCounter++;
}
*/
}
}
}