Tuesday 27 July 2010

The Terrible Dangers of Autoboxing (Part 2)

Solution to part 1:
j is equal to m
j is equal to K
K is equal to m

The result of one of the Object being null, will of course cause a NullPointerException.

Part 2:

class Autoboxing


    public static void main(String[] args)
    {
        Integer a = 10;
        Integer b = 10;
        Integer c = 1000;
        Integer d = 1000;
        System.out.println(a == b); //true
        System.out.println(c == d); //false
    }

};

Please explain.

(Found it in my Linkedin groups "Sun Certified Java Programmer" here)


References

Most common gotchas in Java
http://vanillajava.blogspot.nl/2014/02/most-common-gotchas-in-java.html

Monday 26 July 2010

The Cycle

Somewhere during the lifetime of a software development project, especially when concerning frameworks, the following things happen:

  1. a software project is started
  2. people notice that it is convenient and easy to use
  3. people demand new changes, and additional functionality
  4. the small software project starts to grow into the form of a framework
  5. the small software project becomes big, unruly, difficult to use, slow, hard to maintain, has all sorts of functionality that most people do not need.
  6. some people grow tired/irritated at the state of things
  7. some people have the great idea to make something better...

Somewhere,... a software project is started.

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: <Object.value>, no session or session was closed

ERROR [STDERR] Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: <Object.value>, no session or session was closed

Sooner or later, anyone using Hibernate, is running into this problem.

Check out http://community.jboss.org/wiki/OpenSessioninView

Sunday 25 July 2010

REST Webservice URI setup

Thank heavens I found the blog topic http://marxsoftware.blogspot.com/2010/02/jax-rs-with-jersey-introduction.html.

So, here's the setup.

http://hostname/<context root of web application>/<url pattern of the servlet mapping>/<path defined in java class>

http://
hypertext transfer protocol
hostname
the hostname where the web server is lurking
context root of web application
the context root is defined by the proprietary xml file sun-web.xml
url pattern of the servlet mapping
the url pattern defined in the web.xml for a particular servlet, to indicate for which urls the servlet needs to be called
path defined in java class
the path is defined in the java class that is going to function as the REST webservice. It's defined by means of the @Path annotation on the Class itself.

Wednesday 14 July 2010

Scaling large amounts of images in a directory structure

The following links helped me a lot!
import java.util.*;
import java.io.*;

import java.awt.image.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.io.FilenameFilter;

public class Autoboxing
{
    public static String DESTINATION_PATH = "C:\\destination";

    public static String SOURCE_PATH = "C:\\source";

    public static boolean verbose = false;

    public static int MAX_RETRIES = 20;
   
    /**
     * Saves a BufferedImage to the given file, pathname must not have any
     * periods "." in it except for the one before the format, i.e. C:/images/fooimage.png
     * @param img
     * @param ref a pathname
     */

    public static void saveImage(BufferedImage img, String ref)
    {
        try {
            String format = (ref.endsWith(".png")) ? "png" : "jpg";
            ImageIO.write(img, format, new File(ref));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static BufferedImage loadImage(File ref)
    {
        BufferedImage bimg = null;
        try {

            bimg = ImageIO.read(ref);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bimg;
    }

    /**
     * Convenience method that returns a scaled instance of the
     * provided {@code BufferedImage}.
     *
     * @param img the original image to be scaled
     * @param targetWidth the desired width of the scaled instance,
     *    in pixels
     * @param targetHeight the desired height of the scaled instance,
     *    in pixels
     * @param hint one of the rendering hints that corresponds to
     *    {@code RenderingHints.KEY_INTERPOLATION} (e.g.
     *    {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
     *    {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
     * @param higherQuality if true, this method will use a multi-step
     *    scaling technique that provides higher quality than the usual
     *    one-step technique (only useful in downscaling cases, where
     *    {@code targetWidth} or {@code targetHeight} is
     *    smaller than the original dimensions, and generally only when
     *    the {@code BILINEAR} hint is specified)
     * @return a scaled version of the original {@code BufferedImage}
     */

    public static BufferedImage getScaledInstance(BufferedImage img,
                                           int targetWidth,
                                           int targetHeight,
                                           Object hint,
                                           boolean higherQuality)
    {
        int type = (img.getTransparency() == Transparency.OPAQUE) ?
            BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage ret = (BufferedImage)img;
        int w, h;
        if (higherQuality) {
            // Use multi-step technique: start with original size, then
            // scale down in multiple passes with drawImage()
            // until the target size is reached
            w = img.getWidth();
            h = img.getHeight();
        } else {
            // Use one-step technique: scale directly from original
            // size to target size with a single drawImage() call
            w = targetWidth;
            h = targetHeight;
        }
    int count = 0;
        do {
        count ++;
            if (count > MAX_RETRIES)
            {
                throw new RuntimeException("Max retries reached.");
            }
            if (higherQuality && w > targetWidth) {
                w /= 2;
                if (w < targetWidth) {
                    w = targetWidth;
                }
            }

            if (higherQuality && h > targetHeight) {
                h /= 2;
                if (h < targetHeight) {
                    h = targetHeight;
                }
            }

            BufferedImage tmp = new BufferedImage(w, h, type);
            Graphics2D g2 = tmp.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
            g2.drawImage(ret, 0, 0, w, h, null);
            g2.dispose();

            ret = tmp;
        } while (w != targetWidth || h != targetHeight);

        return ret;
    }

    /**
     * Recursively resizes images.
     * @param directory the source directory containing .jpg files
     * @param destination the destination directory where the resized .jpg files are to be put
     * @param filter the filter to use, for example *.jpg
     * @param recurse wether or not to traverse the directory tree
     * @param recreate wether or not to recreate the entire directory tree
     * in the destination or simply dump .jpg files.
     * @param overwrite true, it overwrites existing files, false, if destination file already exists, skips it.
     */

    public static void changeFiles(
            File directory,
            File destination,
            FilenameFilter filter,
            boolean recurse,
            boolean recreate,
            boolean overwrite)
    throws IOException
    {
        if (verbose) System.out.println("Checking directory : " + directory.getCanonicalPath() + " with " + destination.getCanonicalPath() );
        // List of files / directories
        Vector<File> files = new Vector<File>();
       
        // Get files / directories in the directory
        File[] entries = directory.listFiles();
       
        // Go over entries
        for (File entry : entries)
        {
            if (verbose) System.out.println(" File: " + entry.getName());
            // If there is no filter or the filter accepts the 
            // file / directory, resize the image found
            if (filter == null || filter.accept(directory, entry.getName()))
            {
                File newFile = new File(destination.getCanonicalPath() + File.separator + entry.getName());
                if (newFile.exists() && !overwrite)
                {
                    // skipping this one, already done apparently.
                    if (verbose) System.out.println(" File " + newFile .getCanonicalPath() + " exists, skipped.");
                    continue;
                }

                try
                {
                    BufferedImage theImage = loadImage(entry);
                    theImage = getScaledInstance(theImage, 50, 50,  RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
                    if (!recreate)
                    {
                        saveImage(theImage, destination.getCanonicalPath() + "\\" + entry.getName());
                    }
                    else
                    {
                        if (!newFile.exists())
                        {
                            // create the equivalent
                            newFile.createNewFile();
                        }
                        saveImage(theImage, newFile.getCanonicalPath());
                    }
                }
                catch (Exception e)
                {
                    System.out.println("Error resizing image " + entry.getCanonicalPath());
                    e.printStackTrace();
                }
            }
           
            // If the file is a directory and the recurse flag
            // is set, recurse into the directory
            if (recurse && entry.isDirectory())
            {
                if (recreate)
                {
                    File newFile = new File(destination.getCanonicalPath() + File.separator + entry.getName());
                    if (!newFile.exists())
                    {
                        // create the equivalent
                        newFile.mkdir();
                    }
                    changeFiles(entry, new File(destination.getCanonicalPath() + File.separator + entry.getName()), filter, recurse, recreate, overwrite);
                }
                else
                {
                    changeFiles(entry, new File(destination.getCanonicalPath()), filter, recurse, recreate, overwrite);
                }
            }
        }

    }

    public static class MyFilenameFilter implements FilenameFilter
    {
        public boolean accept(File dir,
                        String name)
        {
            return name.endsWith(".jpg");
        }
    }
   
   
    public static void main(String args[])
    throws IOException
    {
        boolean overwrite = false;
        boolean recursive = false;
        boolean recreate = false;
        boolean nextIsDestination = false;
        boolean nextIsSource = false;
        String destination = DESTINATION_PATH;
        String source = SOURCE_PATH;
        for (String argument : args)
        {
            if (nextIsDestination)
            {
                destination = argument;
                nextIsDestination = false;
            }
            if (nextIsSource)
            {
                source = argument;
                nextIsSource = false;
            }
            if ("-r".equals(argument))
            {
                recursive = true;
            }
            if ("-tree".equals(argument))
            {
                recreate = true;
            }
            if ("-s".equals(argument))
            {
                nextIsSource = true;
            }
            if ("-d".equals(argument))
            {
                nextIsDestination = true;
            }
            if ("-o".equals(argument))
            {
                overwrite = true;
            }
            if ("-v".equals(argument))
            {
                verbose = true;
            }
        }
       
        File src_file = new File(source);
        File dest_file = new File(destination);
        System.out.println("absolute path: " +  src_file.getAbsolutePath());
        System.out.println("canonical path: " +  src_file.getCanonicalPath());
        System.out.println("path: " +  src_file.getPath());
        System.out.println("name: " +  src_file.getName());
        changeFiles(src_file, dest_file, new MyFilenameFilter(), recursive, recreate, overwrite);
    }
}

Friday 9 July 2010

Concurrency problems in jsp Pages

I'm so ashamed that I didn't notice this problem sooner, but apparently servlets (and, therefore, jsp pages too) are instanced and put into a pool for multithreaded use.

This has the very bad effect of messing with your class variables.

So, do NOT do the following:

<%!
// authentication && authorization

/* name of the current user logged in */
private String itsPlayerName;

private Logger itsLog = Logger.getLogger("mmud");
 
/* password of the current user logged in, unsure if used */
private String itsPlayerPassword = "";
 
/* sessionid/cookiepassword of current user */
private String itsPlayerSessionId;

private StringBuffer contents = new StringBuffer("");
%>

A JSP page is by default thread unsafe. This means that multiple requests, started in multiple threads for a specific JSP access the same Instance.

Do not make your JSP page threadSafe="true". It will become a performance nightmare.

If you are interested, the following is put in the javadoc of the javax.servlet.Servlet interface service method:

Servlets typically run inside multithreaded servlet containers that can handle multiple requests concurrently. Developers must be aware to synchronize access to any shared resources such as files, network connections, and as well as the servlet's class and instance variables.

How to Transmit New Objects To REST Service

One of the reasons for adding this, is because there was a huge lack of POST/PUT/DELETE/HEAD examples out there, and I thought I should do my part. Although the principles are the same as with GET.

I've been at it for some time now, and for some reason there always seem to be one or two things that go wrong when creating a new REST Service, even though I've created a working REST Service not two days ago. That in itself is kind of frustrating.

Check out Japod's Blog for starters. In order to use more complicated Data Structures in REST, these need to be defined in a derivative of the JAXBContext class.

Personally, I really don't understand why that same cannot be done using simple Annotations, but that's just me.

Then there's the security issue. How to see who the person is that is accessing the webservice. Luckily, I found me some help here.

There seems to be some confusion regarding the mapping of the HTTP calls3, which I've tried to put in the picture above.

Updated 14/09/2014.

References

[1] Why PUT and DELETE?
http://www.artima.com/lejava/articles/why_put_and_delete.html
[2] rfc2616
http://www.ietf.org/rfc/rfc2616.txt
[3] Wikipedia - Representational state transfer
http://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_constraints