출처 : http://blog.naver.com/tyboss/70097410517

Java SE Autodownload Files
http://www.oracle.com/technetwork/java/javase/autodownload-140472.html


Applet 을 만들 때 package를 적용하고 싶으면 java 프로젝트를 별도로 만들어 jar로 배포를 하고 class 파일 단위로 처리할 경우에는 pacakge 없이 컴파일을 해야 한다.

Applet을 refresh 하고 싶다면 새로고침 시 나오는 java 보안 경고 창에서 실행/취소 중 취소를 클릭하고 Applet 표시 부분에 마우스 우클릭 Reload Applet 클릭하면 됨. Java 콘솔도 우클릭 메뉴에 있음.



1. Applet 만들기

package com.maruara.applet;

import java.applet.Applet;
import java.awt.TextField;
import java.util.Date;

import netscape.javascript.JSObject;

public class TestApplet extends Applet implements Runnable {

  /**
  *
  */
 private static final long serialVersionUID = -176201962325630072L;
 
 JSObject window;
 Thread clockThread;
 Date date;
 boolean running = true;
 TextField tf = new TextField(30);

 public void init() {
  window = JSObject.getWindow(this);
  
  clockThread= new Thread(this);
  clockThread.start();
  add(tf);

  /*
  JSObject window = JSObject.getWindow(this);
  JSObject document = (JSObject)window.getMember("document");
  JSObject location = (JSObject)document.getMember("location");
   
  String s = (String)location.getMember("href");
  window.call("doAlert", null);
  */
 }
 
 public void doStart(String msg) {
  System.out.println(msg);
  tf.setText(msg);
  
  running = true;
  clockThread= new Thread(this);
  clockThread.start();
 }
 
 public void doStop(String msg) {
  System.out.println(msg);
  tf.setText(msg);
  
  running = false;
  clockThread = null;
 }
 
 public void run() {
  // loop until told to stop
        while (running) {
            date = new Date();
           
            window.call("view", new Object[] {date});
           
            try {
             // Wait 500milliseconds before continuing
                clockThread.sleep(1000);
            } catch (InterruptedException e) {
             System.out.println(e);
            }
            // he has wait and will now restart his actions.
         }
    }
 
 public void destroy()
    {
         // will cause thread to stop looping
         running = false;
         // destroy it.
         clockThread = null;
    }
 
}


2. Applet Jar로 묶어서 Web 서버에 올리기

jar 묶을 때 src class folder만 체크한 후 export 한다.
이미지처럼 웹에서 접근할 수 있는 경로로 이동한다.


3. HTML 적용

 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

</head>
<body>

<%-- <object id="myApplet" name="myApplet" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" archive="${pageContext.request.contextPath }/myApplet.jar" width="200" height="200" codebase="http://java.sun.com/update/1.7.0/jinstall-7u17-windows-i586.cab"> --%>
<%--  <param name="archive" value="${pageContext.request.contextPath }/myApplet.jar" /> --%>
<!--     <param name="code" value="com.maruara.applet.TestApplet.class" /> -->
<!--     <param name="codebase" value="." /> -->
<!--     <param name="type" value="application/x-java-applet;version=1.6" /> -->
<!--      No JDK 1.3 support for APPLET!! -->
<!-- </object> -->

<!-- <embed id="testapplet" -->
<!--        type="application/x-java-applet;version=1.7" -->
<!--        width="256" height="256"  -->
<%--        archive="${pageContext.request.contextPath }/myApplet.jar" --%>
<!--        code="com.maruara.applet.TestApplet.class" -->
<!--        pluginspage="http://java.com/download/" /> -->


<object id="myApplet" name="myApplet" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" archive="${pageContext.request.contextPath }/myApplet.jar" width="200" height="200" codebase="http://java.sun.com/update/1.7.0/jinstall-7u17-windows-i586.cab">
 <param name="archive" value="${pageContext.request.contextPath }/myApplet.jar" />
    <param name="code" value="com.maruara.applet.TestApplet.class" />
    <param name="codebase" value="." />
    <param name="type" value="application/x-java-applet;version=1.6" />
    <comment>
     <embed id="myApplet"
         type="application/x-java-applet;version=1.7"
         width="256" height="256"
         archive="${pageContext.request.contextPath }/myApplet.jar"
         code="com.maruara.applet.TestApplet.class"
         pluginspage="http://java.com/download/" />
    </comment>
</object>

<div id="view"></div>
<button type="button" id="btnStart">시작</button>
<button type="button" id="btnStop">정지</button>

<script>
function view(time) {
 $('#view').text(time);
}

$('#btnStart').on('click', function() {
  $('#myApplet').get(0).doStart('stop');
});

$('#btnStop').on('click', function() {
 document.getElementById('myApplet').doStop('stop');
});
</script>

</body>
</html>

 

<script language="Javascript">

  var _app = navigator.appName;

  if (_app == 'Netscape') {
    document.write('<embed code="Applet1.class"',
                   'width="200"',
                   'height="200"',
                   'type="application/x-java-applet;version=1.5.0">');
    }
  else if (_app == 'Microsoft Internet Explorer') {
    document.write('<OBJECT ',
                   'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"',
                   'width="200"',
                   'height="200">',
                   '<PARAM name="code" value="Applet1.class">',
                   '</OBJECT>');
    }
  else {
    document.write('<p>Sorry, unsupported browser.</p>');
    }

</script> 

굴림 9pt(12px)의 글자 크기에 맞춰서 Width로 글자 자르기
굴림체는 맨 아래 byte 글자 자르기로 하면 되고 가변 글자체일 경우에는 해당 width를 수정하여 사용하면 된다.


출처 (PHP) : http://www.xpressengine.com/zb4_tip/854296
출처 첨부파일 :cutstring.php



Java 소스로 변환 (junit test) :TestSubWidth.java

 package test;

import java.text.StringCharacterIterator;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

public class TestSubByte {
 
 private final static String[] strTemp = new String[10];
 private final static int[] strWidth = new int[10];
 private static Map<Integer, Integer> asciiMap = new HashMap<Integer, Integer>();
 
 static {
  strTemp[0] = "@#&*@※☆★○●◎◇◆△▽→←↔〓◁◀▷▶♤♡♧⊙◈▣◐◑▒▤▥▨▧▦▩♨☏☎☜☞↗↙↖↘♭♩♬㉿㈜№㏇™㏂㏘℡";
  strWidth[0] = 12;
  strTemp[1] = "\\mM";
  strWidth[1] = 11;
  strTemp[2] = "%wW□■▲▼♣";
  strWidth[2] = 10;
  strTemp[3] = "~QONGC↑↓♠♥↕®";
  strWidth[3] = 9;
  strTemp[4] = "<>&ZXYRSTUVKHEDBAP♪";
  strWidth[4] = 8;
  strTemp[5] = "zyxusqponhgedcbaLF¶";
  strWidth[5] = 7;
  strTemp[6] = "#$*+-/0123456789=?[]^_{|}vkJ†‡§";
  strWidth[6] = 6;
  strTemp[7] = "()";
  strWidth[7] = 5;
  strTemp[8] = " :;.,!\"'`rª";
  strWidth[8] = 4;
  strTemp[9] = "tljifIº·";
  strWidth[9] = 3;
  
  try {
   StringCharacterIterator sci = null;
   int ascii = 0;
   for(int i=0, s=strTemp.length; i<s; i++) {
    sci = new StringCharacterIterator(strTemp[i]);
    ascii = sci.first();
    while(ascii < 65535) {
     asciiMap.put(ascii, strWidth[i]);
     ascii = sci.next();
    }
   }
  } catch (Exception e) {
  }
 }
 
 private String subWidth(String str, int maxWidth, String tail) throws Exception {
  if (str == null || str.length() < 1) {
   return "";
  }
  if(maxWidth < 1) {
   return "";
  }
  StringCharacterIterator sci = new StringCharacterIterator(str);
  StringBuffer buffer = new StringBuffer();
  int ascii = sci.first();
  Object widthObj = null;
  int width = 0;
  while(ascii < 65535) {
   widthObj = asciiMap.get(ascii);
   if(widthObj != null) {
    width += (Integer)widthObj;
   } else {
    if(ascii > 127) {
     width += 12;
    } else {
     width += 6;
    }
   }
   
   if(width > maxWidth) {
    if(tail != null && tail.length() > 0) {
     buffer.append(tail);
    }
    break;
   } else {
    buffer.append((char)ascii);
   }
   ascii = sci.next();
  }
  return buffer.toString();
 }
 
 @Test
 public void test1() throws Exception {
  System.out.println( subWidth("대 korea", 100, "..") );
  System.out.println( subWidth("대 korea 한민국1 넘버 입니다", 100, "..") );
  System.out.println( subWidth("abcdEFASDFASDFASDFASDFADSASD", 100, "..") );
 }
 
}




Java 소스로 변환 (TagLibrary) :TagUtility.java

public static String subByte(String str, int len, String encoding) {
  try {
   if (StringUtil.isEmpty(str)) {
    return str;
   }
   byte[] strBytes = str.getBytes(encoding);
   int strLength = strBytes.length;
   int minusByteNum = 0;
   int offset = 0;
   int hangulByteNum = encoding.equals("UTF-8") ? 3 : 2;
   if (strLength > len) {
    minusByteNum = 0;
    offset = len;
    for (int j = 0; j < offset; j++) {
     if (((int) strBytes[j] & 0x80) != 0) {
      minusByteNum++;
     }
    }
    if (minusByteNum % hangulByteNum != 0) {
     offset -= minusByteNum % hangulByteNum;
    }
    return new String(strBytes, 0, offset, encoding);
   } else {
    return str;
   }
  } catch (Exception e) {
   throw new BaseException(e);
  }
 }




Byte(바이트)로 글자 자르기

출처 : http://blog.naver.com/PostView.nhn?blogId=nackhwa7&logNo=140103352320

 public static String parseStringByBytes(String str, int len, String encoding) {
  try {
   if (StringUtil.isEmpty(str)) {
    return str;
   }
   byte[] strBytes = str.getBytes(encoding);
   int strLength = strBytes.length;
   int index = 0;
   int minusByteNum = 0;
   int offset = 0;
   int hangulByteNum = encoding.equals("UTF-8") ? 3 : 2;
   if (strLength > len) {
    minusByteNum = 0;
    offset = len;
    if (index + offset > strLength) {
     offset = strLength - index;
    }
    for (int j = 0; j < offset; j++) {
     if (((int) strBytes[index + j] & 0x80) != 0) {
      minusByteNum++;
     }
    }
    if (minusByteNum % hangulByteNum != 0) {
     offset -= minusByteNum % hangulByteNum;
    }
    return new String(strBytes, index, offset, encoding);
   } else {
    return str;
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 
- 원본 소스

public String[] parseStringByBytes(String raw, int len, String encoding) {
  if (raw == null)
   return null;
  String[] ary = null;
  try {
   // raw 의 byte
   byte[] rawBytes = raw.getBytes(encoding);
   int rawLength = rawBytes.length;

   int index = 0;
   int minus_byte_num = 0;
   int offset = 0;

   int hangul_byte_num = encoding.equals("UTF-8") ? 3 : 2;

   if (rawLength > len) {
    int aryLength = (rawLength / len) + (rawLength % len != 0 ? 1 : 0);
    ary = new String[aryLength];

    for (int i = 0; i < aryLength; i++) {
     minus_byte_num = 0;
     offset = len;
     if (index + offset > rawBytes.length) {
      offset = rawBytes.length - index;
     }
     for (int j = 0; j < offset; j++) {
      if (((int) rawBytes[index + j] & 0x80) != 0) {
       minus_byte_num++;
      }
     }
     if (minus_byte_num % hangul_byte_num != 0) {
      offset -= minus_byte_num % hangul_byte_num;
     }
     ary[i] = new String(rawBytes, index, offset, encoding);
     index += offset;

    }
   } else {
    ary = new String[] { raw };
   }
  } catch (Exception e) {

  }
  return ary;
 } 



 


소스 파일 목록 출력

GenerationFileList.java
 

package com.web.test;

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

public class GenerationFileList {

    private static final String path = "D:/workspaces/eclipse-jee-juno-SR1-win32/ewppis";
    
    private static void searchFile(File file) throws Exception {
        File[] files = file.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                if(dir.toString().endsWith("ewppis\\log")) {
                    return false;
                } else if(dir.toString().endsWith("ewppis\\ref")) {
                    return false;
                } else if(dir.toString().endsWith("ewppis\\source")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\resources\\temp")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\html")) {
                    return false;
                } else if(dir.toString().endsWith("ewppis\\src\\com\\web\\test")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\META-INF")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\test")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\WEB-INF\\classes")) {
                    return false;
                } else if(dir.toString().endsWith("WebContent\\WEB-INF\\upload")) {
                    return false;
                } else if(dir.toString().endsWith(".svn")) {
                    return false;
                }
                
                if (name.startsWith(".")) {
                    return false;
                } else if (name.equals("rebel.xml")) {
                    return false;
                } else if (name.equals("build.xml")) {
                    return false;
                }
                return true;
            }
        });

        for (int i = 0; i < files.length; i++) {
            getFile(files[i]);
        }
    }
    
    private static void getFile(File file) throws Exception {
        if (file.isDirectory()) {
            searchFile(file);
        } else {
            //System.out.println(file.getCanonicalPath());
            String path = file.getCanonicalPath().replaceAll("\\\\", "/");
            path = path.replaceAll("D:/workspaces/eclipse\\-jee\\-juno\\-SR1\\-win32/ewppis/", "");
            int idx = path.lastIndexOf("/");
            System.out.println(path.substring(0, idx) + " : " + path.substring(idx+1));
        }
    }
    
    public static void main(String[] args) throws Exception {
        File file = new File(path);
        if (file.isDirectory()) {
            searchFile(file);
        }
    }
    
}


-----------------------------------------------------------------------------------------------------------------------


패키지 클래스 / 메소드 출력

 import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import org.junit.Test;

public class MethodPrintTest {

 @Test
 public void test1() throws Exception {
  Class[] classes = getClasses("패키지경로");
  for(int i=0; i<classes.length; i++) {
   Class clazz = classes[i];
   
   Method[] methods = clazz.getDeclaredMethods();
   for(int j=0; j<methods.length; j++) {
    Method method = methods[j];
    System.out.println(method.toString());
   }
  }
 }
 
 
 private static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException {
     ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
     assert classLoader != null;
     String path = packageName.replace('.', '/');
     Enumeration<URL> resources = classLoader.getResources(path);
     List<File> dirs = new ArrayList<File>();
     while (resources.hasMoreElements()) {
         URL resource = resources.nextElement();
         dirs.add(new File(resource.getFile()));
     }
     ArrayList<Class> classes = new ArrayList<Class>();
     for (File directory : dirs) {
         classes.addAll(findClasses(directory, packageName));
     }
     return classes.toArray(new Class[classes.size()]);
 }

 private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {
     List<Class> classes = new ArrayList<Class>();
     if (!directory.exists()) {
         return classes;
     }
     File[] files = directory.listFiles();
     for (File file : files) {
         if (file.isDirectory()) {
             assert !file.getName().contains(".");
             classes.addAll(findClasses(file, packageName + "." + file.getName()));
         } else if (file.getName().endsWith(".class")) {
             classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));
         }
     }
     return classes;
 }
 
}



출처 : http://howtodoinjava.com/2012/10/22/singleton-design-pattern-in-java/

Singleton pattern is a design solution where an application wants to have one and only one instance of any class, in all possible scenarios without any exceptional condition. It has been debated long enough in java community regarding possible approaches to make any class singleton. Still, you will find people not satisfied with any solution you give. They can not be overruled either. In this post, we will discuss some good approaches and will work towards our best possible effort.

Sections in this post:

  • Eager initialization
  • Lazy initialization
  • Static block initialization
  • Bill pugh solution
  • Using Enum
  • Adding readResolve()
  • Adding serial version id
  • Conclusion

Singleton term is derived from its mathematical counterpart. It wants us, as said above, to have only one instance. Lets see the possible solutions:

Eager initialization

This is a design pattern where an instance of a class is created much before it is actually required. Mostly it is done on system start up. In singleton pattern, it refers to create the singleton instance irrespective of whether any other class actually asked for its instance or not. 

public class EagerSingleton {
 private static volatile EagerSingleton instance = new EagerSingleton();

 // private constructor
 private EagerSingleton() {
 }

 public synchronized static EagerSingleton getInstance() {
  if (instance == null) {
   instance = new EagerSingleton();
  }
  return instance;
 }
}
 

Above method works fine, but has one performance drawback. The getInstance() method is synchronized and each call will require extra locking/unlocking steps which are necessary only for first time, and never there after.

Lets solve above problem in next method.

Lazy initialization

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. In singleton pattern, it restricts the creation of instance until requested first time. Lets see in code: 

public final class LazySingleton {
 private static volatile LazySingleton instance = null;

 // private constructor
 private LazySingleton() {
 }

 public static LazySingleton getInstance() {
  if (instance == null) {
   synchronized (LazySingleton.class) {
    instance = new LazySingleton();
   }
  }
  return instance;
 }
}
 

On first invocation, above method will check if instance is already created using instance variable. If there is no instance i.e. instance is null, it will create an instance and will return its reference. If instance is already created, it will simply return the reference of instance.

But, this method also has its own drawbacks. Lets see how. Suppose there are two threads T1 and T2. Both comes to create instance and execute “instance==null”, now both threads have identified instance variable to null thus assume they must create an instance. They sequentially goes to synchronized block and create the instances. At the end, we have two instances in our application.

This error can be solved using double-checked locking. This principle tells us to recheck the instance variable again in synchronized block in given below way:

public class EagerSingleton {
 private static volatile EagerSingleton instance = null;

 // private constructor
 private EagerSingleton() {
 }

 public static EagerSingleton getInstance() {
  if (instance == null) {
   synchronized (EagerSingleton.class) {
    // Double check
    if (instance == null) {
     instance = new EagerSingleton();
    }
   }
  }
  return instance;
 }

 Above code is the correct implementation of singleton pattern.

Please ensure to use “volatile” keyword with instance variable otherwise you can run into out of order write error scenario, where reference of instance is returned before actually the object is constructed i.e. JVM has only allocated the memory and constructor code is still not executed. In this case, your other thread, which refer to uninitialized object may throw null pointer exception and can even crash the whole application.

Static block initialization

If you have little idea about class loading sequence, you can connect to the fact that static blocks are executed during the loading of class and even before the constructor is called. We can use this feature in our singleton pattern also like this:

public class StaticBlockSingleton {
 private static final StaticBlockSingleton INSTANCE;

 static {
  try {
   INSTANCE = new StaticBlockSingleton();
  } catch (Exception e) {
   throw new RuntimeException("Uffff, i was not expecting this!", e);
  }
 }

 public static StaticBlockSingleton getInstance() {
  return INSTANCE;
 }

 private StaticBlockSingleton() {
  // ...
 }

Above code has one drawback. Suppose there are 5 static fields in class and application code needs to access only 2 or 3, for which instance creation is not required at all. So, if we use this static initialization. we will have one instance created though we require it or not.

Next section will overcome this problem.

Bill pugh solution

Bill pugh was main force behind java memory model changes. His principle “Initialization-on-demand holder idiom” also uses static block but in different way. It suggest to use static inner class.

public class BillPughSingleton {
 private BillPughSingleton() {
 }

 private static class LazyHolder {
  private static final BillPughSingleton INSTANCE = new BillPughSingleton();
 }

 public static BillPughSingletongetInstance() {
  return LazyHolder.INSTANCE;
 }

 As you can see, until we need an instance, the LazyHolder class will not be initialized until required and you can still use other static members of BillPughSingleton class. This is the solution, i will recommend to use. I also use it in my all projects.

Using Enum

This type of implementation recommend the use of enum. Enum, as written in java docs, provide implicit support for thread safety and only one instance is guaranteed. This is also a good way to have singleton with minimum effort.

public enum EnumSingleton {
 INSTANCE;
 public void someMethod(String param) {
  // some class member
 }
}

 

Adding readResolve()

So, till now you must have taken your decision that how you would like to implement your singleton. Now lets see other problems that may arise even in interviews also.
Lets say your application is distributed and it frequently serialize the objects in file system, only to read them later when required. Please note that, de-serialization always creates a new instance. Lets understand using an example:

Our singleton class is: 

public class DemoSingleton implements Serializable {
 private volatile static DemoSingleton instance = null;

 public static DemoSingleton getInstance() {
  if (instance == null) {
   instance = new DemoSingleton();
  }
  return instance;
 }

 private int i = 10;

 public int getI() {
  return i;
 }

 public void setI(int i) {
  this.i = i;
 }
}
 

Lets serialize this class and de-serialize it after making some changes:

public class SerializationTest {
 static DemoSingleton instanceOne = DemoSingleton.getInstance();

 public static void main(String[] args) {
  try {
   // Serialize to a file
   ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
     "filename.ser"));
   out.writeObject(instanceOne);
   out.close();

   instanceOne.setI(20);

   // Serialize to a file
   ObjectInput in = new ObjectInputStream(new FileInputStream(
     "filename.ser"));
   DemoSingleton instanceTwo = (DemoSingleton) in.readObject();
   in.close();

   System.out.println(instanceOne.getI());
   System.out.println(instanceTwo.getI());

  } catch (IOException e) {
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

Output:
20
10
 

 Unfortunately, both variables have different value of variable “i”. Clearly, there are two instances of our class. So, again we are in same problem of multiple instances in application.
To solve this issue, we need to include readResolve() method in our DemoSingleton class. This method will be invoked when you will de-serialize the object. Inside this method, you must return the existing instance to ensure single instance application wide. 

public class DemoSingleton implements Serializable {
 private volatile static DemoSingleton instance = null;

 public static DemoSingleton getInstance() {
  if (instance == null) {
   instance = new DemoSingleton();
  }
  return instance;
 }

 protected Object readResolve() {
  return instance;
 }

 private int i = 10;

 public int getI() {
  return i;
 }

 public void setI(int i) {
  this.i = i;
 }
}
 

Now when you execute the class SerializationTest, it will give you correct output. 

20
20 

 

Adding serial version id

So far so good. Till now, we have solved the problem of synchronization and serialization both. Now, we are just one step behind our correct and complete implementation. And missing part is serial version id.

This is required in condition when you class structure can change in between you serialize the instance and go again to de-serialize it. Changed structure of class will cause JVM to give exception while de-serializing process.

java.io.InvalidClassException: singleton.DemoSingleton; local class incompatible: stream classdesc serialVersionUID = 5026910492258526905, local class serialVersionUID = 3597984220566440782
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at singleton.SerializationTest.main(SerializationTest.java:24) 

 This problem can be solved only by adding a unique serial version id to class. It will prevent the compiler to throw the exception by telling that both classes are same, and will load the available instance variables only.

Conclusion

After having discussed so many possible approaches and other possible error cases, i will recommend you below code template to design your singleton class which shall ensure only one instance of class in whole application in all above discussed scenarios.

public class DemoSingleton implements Serializable {
 private static final long serialVersionUID = 1L;

 private DemoSingleton() {
  // private constructor
 }

 private static class DemoSingletonHolder {
  public static final DemoSingleton INSTANCE = new DemoSingleton();
 }

 public static DemoSingleton getInstance() {
  return DemoSingletonHolder.INSTANCE;
 }

 protected Object readResolve() {
  return getInstance();
 }

I hope, this post has enough information to make you understand the most common approaches for singleton pattern. Let me know of you thoughts please.

Happy Learning !!

Update: I just thought to add some examples which can be referred for further study and mention in interviews:

========================================================================================================
========================================================================================================

Singleton Serializable

출처 : http://atin.tistory.com/355

자바 개발을 하면서 제일 많이 쓰는 패턴 중 하나가 싱글톤 패턴이다.
그리고 싱글톤 소스 또한 다양하게 작성한다.
Source2와 같은 경우는 다중 쓰레드 상에서 위험하다. Source3과 같은 경우는 안전하긴 하지만 성능상 Source1이 제일 좋다.

Source4와 같은 경우는 싱글톤에서 직렬화 처리를 해주기 위한 방법이다. Serializable 을 구현해주고 readResolve메소드를 구현하고 모든 인스턴스 필드를 transient 로 선언해준다.

Source5와 같은 경우는 enum을 통한 구현 방법이다. 직렬화가 자동으로 지원되고 인스턴스가 여러개 생기지 않도록 지원해준다.


public class Singleton {

private static final Singleton instance = new Singleton();

private Singleton(){}

public static final Singleton getInstance(){
return instance;
}
}

[Source. 1] 
 

class Singleton2 {
private static Singleton2 instance = null;

private Singleton2(){}

public static final Singleton2 getInstance(){
if(instance == null) instance = new Singleton2();
return instance;
}
}

[Source. 2] 


class Singleton3 {
private static Singleton3 instance = null;

private Singleton3(){}

public static final Singleton3 getInstance(){
if(instance == null) {
synchronized(Singleton3.class){
instance = new Singleton3();
}
}
return instance;
}
}

[Source. 3] 
 

class Singleton4 implements Serializable {
/**
*/
private static final long serialVersionUID = 6209266452691660409L;
private static final transient Singleton4 instance = new Singleton4();

private Singleton4(){}

public static final Singleton4 getInstance(){
return instance;
}
private Object readResolve(){
return instance;
}
}

[Source. 4] 
 

enum Singleton5{
instance;
public void method(){}
}

[Source. 5] 

출처 : http://stackoverflow.com/questions/12540088/java-singleton-pattern-for-mysql-connection-pool-too-many-connections


import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

class DBConnectionPool {

    private DataSource ds = null;

    private DBConnectionPool() {
        try {
            Context context = new InitialContext();
            Context envctx = (Context) context.lookup("java:comp/env");
            ds = (DataSource) envctx.lookup("jdbc/TestDB");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static enum PoolSingleton {
        POOL_INSTANCE;

        private static final DBConnectionPool singleton = new DBConnectionPool();

        private DBConnectionPool getSingleton() {
            return singleton;
        }
    }

    private static DBConnectionPool getDBConnectionPoolInstance() {
        return PoolSingleton.POOL_INSTANCE.getSingleton();
    }

    static Connection getConnection() {
        try {
            return getDBConnectionPoolInstance().ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }
} 


DB Resource 정의 (mysql)

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/myapp">
    <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000" username="root"
        password="root" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb"
        removeAbandoned="true" removeAbandonedTimeout="60" />
</Context>
 


public User findByUsername(String username) throws DBExFailure {
        Connection conn = DBConnectionPool.getConnection();
        PreparedStatement statement = null;
        ResultSet set = null;
        final String query = "SELECT * FROM users WHERE username=?";
        if (conn != null) {
            try {
                statement = conn.prepareStatement(query);
                statement.setString(1, username);
                set = statement.executeQuery();
                while (set.next()) {
                    User user = new User();
                    // user.setId(set.getInt("ID"));
                    user.setUsername(set.getString("username"));
                    user.setName(set.getString("name"));
                    user.setSurname(set.getString("surname"));
                    user.setPassword(set.getString("password"));
                    user.setEmail(set.getString("email"));
                    user.setRole(RolesENUM.values()[set.getInt("role")]);
                    return user;
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
                throw new DBExFailure();
            } finally {
                DBConnectionPool.closeResources(set, statement, conn);
            }
        }
        return null;
    }
 


static void closeResources(ResultSet set, Statement statement,
        Connection conn) {
    if (set != null) {
        try {
            set.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    if (statement != null) {
        try {
            statement.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
}
 



출처 : http://blog.naver.com/nillwow/7631084


JSP 에러 페이지를 만드는 세가지 방법

JSP에서 에러페이지를 보여주는 방식은 크게 세가지로 나눌수 있습니다.

1. 첫째는 옛날 방식으로 JSP페이지에 직접 에러페이지를 표시해주는 방식입니다.
<%@ page errorPage="error.jsp" %>
이때 error.jsp에 <%@ page isErrorPage="true" %>라고 선언해야합니다.
JSP페이지에 에러가 발생하면 error.jsp로 제어가 넘어가고 error.jsp에서는
"exception"이라는 implicit 객체를 사용하여 에러메시지를 보여줄 수 있습니다.
에러를 우아하게 처리하기 위해서는 JSP페이지마다 errorPage속성을 지정해야하는
불편이 있었던 방식입니다.



2. 둘째는 서블릿2.3에서 추가된 것으로, web.xml에 에러유형별로 에러페이지를
지정해 주는 좀더 진화된 방식입니다.(첨부파일 참조)
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>

이제 JSP에서 예외가 발생하면 해당 JSP페이지에 errorPage속성을 선언 안해도
error.jsp가 자동으로 에러를 처리합니다. 그리고 error-page에서 지정해준 error.jsp에는
<%@ page isErrorPage="true" %> 등의 선언이 불필요합니다. 그러나 이전 방식과는 다르게
예외객체인 "exception"을 직접 접근하진 못합니다.
대신 새로이 추가된 속성값으로 예외객체를 불러올 수 있습니다.
Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
에러 관련하여 request 스코프에 저장된 속성의 목록입니다.

(http://network.hanbitbook.co.kr/view_news.htm?serial=78)
javax.servlet.error.status_code: 에러 상태 코드를 말해 주는 정수이다.
javax.servlet.error.exception_type: 에러가 생기게 된 예외 형을 지적해 주는 클래스 인스턴스이다.
javax.servlet.error.message: 예외 메시지를 말해주는 스트링이며, 예외 컨스트럭터로 보내어 진다.
javax.servlet.error.exception: 실제 예외가 없어지면 버릴 수 있는 객체이다.
javax.servlet.error.request_uri: 문제를 일으킨 리소스의 URI를 말해주는 스트링이다.

에러페이지를 JSTL로 작성한다면 위의 속성들은 이렇게 접근할 수 있습니다.
(가르쳐주신 ares님께 감사드립니다)
<c:out value="${requestScope['javax.servlet.error.message']}"/>
저처럼 <c:out value="${javax.servlet.error.message}"/> 로 하지 마시길...



3. 추가로 스트러츠 고유의 에러 처리법도 있습니다.
struts-config.xml에서 Exception의 타입에 따라 에러 페이지를 매핑합니다.
(ExceptionHandler를 새로 구현하셔도 됩니다)
<global-exceptions>
<exception key="error.general"
type="java.lang.Exception"
handler="org.apache.struts.action.ExceptionHandler"
path="/error.jsp"
scope="request"/>
</global-exceptions>

스트러츠를 사용하는 어플리케이션에서 Exception이 발생하면 Exception 객체는
request에 org.apache.struts.Globals.EXCEPTION_KEY 키로 저장되고 제어권은
error.jsp로 넘어갑니다. 스트러츠용 error.jsp의 예입니다.

<% Exception ex = (Exception)request.getAttribute(org.apache.struts.Globals.EXCEPTION_KEY); %>
<% if (ex != null) { %>
<table width=100% border=1 cellpadding=6 cellspacing=0>
<tr align="center" bgcolor="#FFCC66"><td>에러 메시지</td></tr>
<tr align="center"><td><b><%= ex %></b></td></tr>
</table>
<p>
<table width=100% border=1 cellpadding=6 cellspacing=0>
<tr align="center" bgcolor="lightgrey"><td>에러 스택 추적 정보
</td></tr>
<tr align="left"><td>
<pre><% ex.printStackTrace(new java.io.PrintWriter(out)); %></pre>
</td></tr>
</table>
<p>
<% } %>

※ 내용에 오류가 있으면 지적해 주시기 바랍니다.
ares
세번째 파트에 첨가를 하자면
struts 커스텀 태그 중에
<html:errors /> 태그 단 한줄을
이용해도 쉽게 에러메세지를 표현할수 있습니다.
하지만 html:errors 태그로 stack의 정보를 아는 방법은
없는것 같습니다.
2003-01-31 12:00:26.0
박종진
부연하자면 <html:errors/> 태그를 사용하실때는
(1) 에러메시지를 담고있는 메시지 리소스 파일(ex: ApplicationResources.properties)을 작성하셔야하고,
(2) Form 또는 Action에서 에러 발생시에 적절한 ActionError를 만들어주는 작업이 필요합니다.
(3) struts-config.xml의 action요소에서 input 파라미터
세팅하는 것도 빼먹어선 안되겠죠.

+ Recent posts