ThreadLocal
하나의 쓰레드에서 객체를 전파하는 방법으로 파라미터를 사용하기 않고 코드에서 동일한 객체를 사용할 수 있게 해준다.

활용 예)
- 객체를 쓰레드에 안전하게 해준다.
- 쓰레드 단위로 트랜잭션 컨텍스트를 관리하고자 할때 사용.
(static으로 선언된 ThreadLoacl 변수에 트랜잭션 컨텍스트를 넣어두면 쓰레드에 안전하게 사용가능)
- ThreadLocal을 사용하여 공유 데이터를 사용할 때 현재 실행중인 스레드의 정보를 넘겨줘야 할 필요는 없지만, 이런 방법은 해당 프레임웍에 대한 의존성을 가지고 된다.
- 전역변수처럼 사용되기 때문에 일반적인 전역 변수가 갖는 단점처럼 재사용성을 떨어뜨릴 수 있고, 객체 간에 눈에 보이지 않는 연결 관계를 만들어내기 쉽기 때문에 애플리케이션에 어떤 영향을 미치는지 정확하게 알고 사용해야 한다.

사용 예)

ThreadLocalClass.java
public class ThreadLocalClass {

    public static ThreadLocal<UserInfo> local = new ThreadLocal<UserInfo>();
}

WorkerRunnable.java
- ThreadLocal 변수 사용
- 객체는 할당한 쓰레드에서만 사용할 수 있다.
public class WorkerRunnable implements Runnable {

    private String name;
  
    public WorkerRunnable(String name) {
        this.name = name;      
    }
  
    public void setObject() {
        UserInfo info = new UserInfo();
        info.setName(name);      
        ThreadLocalClass.local.set(info);
    }
  
    @Override
    public void run() {
        setObject();

        while(true) {
            Business business = new Business();
          business.logic_01();
        }
    }
}

Business.java
- 객체 사용
public class Business {

    public void logic_01() {
        UserInfo user = ThreadLocalClass.local.get();
        System.out.println(Thread.currentThread().getName() + ":" + user.getName());
    }
}

UserInfo.java
- 데이터 객체
public class UserInfo {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    } 
}

Launcher.java
- 테스트 클래스
public class Launcher {

    public static void main(String[] args) {      
              
        for(int i = 0;i<10;i++) {
            WorkerRunnable w = new WorkerRunnable("bbaeggar : " + i);
            Thread t = new Thread(w);
            t.start();
        }
    }
}

Posted by 짱가쟁이
웹 서비스 작업을 하면서 아쉽지만 Request를 각 서비스별로 생성하게 되었다. 유연하게 Request 객체를 하나만 생성해서 작업하면 좋것지만, Http binding(GET) 을 지원해야 한다는 제약 사항 때문에 이래저래 귀찮은 일이 좀 생긴듯.

여 기서 하나.. 각 request 별 입력값을 로그로 남겨야 하는데.. 각 value object 에 toString()을 구현하기가 참 귀찮다는 것이다. 그래서 생각한 것이 reflection 을 이용해서 한번에 해결하자 라는 취지로 만들게 되었음.

public class Test {

    public String getRequestStringMethods(Object obj) {
  
        StringBuffer buffer = new StringBuffer();
      
        try {
            Class dymClass      = obj.getClass();
            Method[] methods = dymClass.getMethods();
          
            buffer.append(dymClass.getSimpleName());
            buffer.append(" : ");
            for(int i = 0;i<methods.length;i++) {
                String methodName = methods[i].getName();
                if("get".equals(methodName.substring(0, 3)) && !"getClass".equals(methodName)) {                
                    String value = (String)methods[i].invoke(obj, null);                  
                    buffer.append("[" + methodName.substring(3, 4).toLowerCase() + methodName.subSequence(4, methodName.length()) + "]");
                    buffer.append(":\"" + value + "\"");
                    buffer.append(" ");
                }
            }
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      
        return buffer.toString();
    }
  
    public String getRequestStringFields(Object obj) {
      
        StringBuffer buffer = new StringBuffer();
      
        try {
            Class dymClass      = obj.getClass();
            Field[] fields      = dymClass.getDeclaredFields();
          
            buffer.append(dymClass.getSimpleName());
            buffer.append(" : ");
            for(int i = 0;i<fields.length;i++) {
                String methodName = "get" + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1, fields[i].getName().length());              
                Method method       = obj.getClass().getMethod(methodName, null);
                String value = (String)method.invoke(obj, null);                  
                buffer.append("[" + methodName.substring(3, 4).toLowerCase() + methodName.subSequence(4, methodName.length()) + "]");
                buffer.append(":\"" + value + "\"");
                buffer.append(" ");
            }
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      
        return buffer.toString();
    }
  
    public static void main(String[] args) {
      
        TestVo vo = new TestVo();
        vo.setAge("33");
        vo.setId("service_01");
        vo.setMsg("message");
        vo.setName("bbaeggar");
        vo.setValue("value");
      
        vo.setValue1("value1");
        vo.setValue2("value2");
        vo.setValue3("value3");
        vo.setValue4("value4");
        vo.setValue5("value5");
        vo.setValue6("value6");
        vo.setValue7("value7");
        vo.setValue8("value8");
        vo.setValue9("value9");
        vo.setValue10("value10");
        System.out.println(new Test().getRequestStringFields(vo));
        System.out.println(new Test().getRequestStringMethods(vo));

    }
}

Result
TestVo : [id]:"service_01" [name]:"bbaeggar" [msg]:"message" [value]:"value" [age]:"33" [value1]:"value1" [value2]:"value2" [value3]:"value3" [value4]:"value4" [value5]:"value5" [value6]:"value6" [value7]:"value7" [value8]:"value8" [value9]:"value9" [value10]:"value10"

TestVo : [name]:"bbaeggar" [value]:"value" [id]:"service_01" [msg]:"message" [age]:"33" [value1]:"value1" [value2]:"value2" [value3]:"value3" [value4]:"value4" [value5]:"value5" [value6]:"value6" [value7]:"value7" [value8]:"value8" [value9]:"value9" [value10]:"value10"

getRequestStringFields() 메소드를 사용하면 필드를 선언한 순서대로 값을 가지고 온다.
getRequestStringMethods() 는 좀 멍청한 넘임.
Posted by 짱가쟁이
2010. 6. 28. 15:30
- http://archive.apache.org/dist/xml/xerces-j/
Xerces-J-bin.1.4.4.zip <- 다운로드

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

public class XMLPrinter {

public String format(String unformattedXml) {
try {
final Document document = parseXmlFile(unformattedXml);

OutputFormat format = new OutputFormat(document);
format.setLineWidth(65);
format.setIndenting(true);
format.setIndent(2);
Writer out = new StringWriter();
XMLSerializer serializer = new XMLSerializer(out, format);
serializer.serialize(document);

return out.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private Document parseXmlFile(String in) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(in));
return db.parse(is);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

- xerces.jar 를 사용하다가 apache cxf 에서 참조하는 lib 랑 충돌이 발생. cast exception 어쩌구가 발생됨.

좀더 simple한 넘으로 찾음
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;



public static String prettyFormat(String input, int indent) {
try {
Source xmlInput = new StreamSource(new StringReader(input));
StringWriter stringWriter = new StringWriter();
StreamResult xmlOutput = new StreamResult(stringWriter);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indent));
transformer.transform(xmlInput, xmlOutput);
return xmlOutput.getWriter().toString();
} catch (Exception e) {
throw new RuntimeException(e); // simple exception handling, please review it
}
}

public static String prettyFormat(String input) {
return prettyFormat(input, 2);
}


Posted by 짱가쟁이
Java5.0 부터 여러가지를 수용하더니 잼난 기능을 하나 추가된듯.

변수를 가변으로 받을 수 있게 됨. 뭐.. 결국 array 로 취급하기는 하지만.. 알아두면 코드 사이즈를 줄이는데 도움이 되지 않을까? 아니면 말구~ 쩌ㅃ

package demo.vat;

/**
 * 자바 가변 인자 테스트
 * jdk 1.5 이상 부터 가능
 *
 * @author bbaeggar
 *
 */
public class VariableArgumentTypeDemo {

    public void test(int type, String... list) {
   
        System.out.println("type : " + type);
       
        for(int i = 0;i<list.length;i++) {
            System.out.println("list[" + i + "] : " + list[i]);
        }
    }
   
    public static void main(String[] args) {
        new VariableArgumentTypeDemo().test(0, "a", "b", "c");
    }
}

- 코드를 자세히 보면 결국 array 로 취급하기 때문에 argument 는 같은 타입이고, 마지막에 선언해야 한다는 제약이 있는듯.

Posted by 짱가쟁이
InputStream 을 문자열로 반환하는 넘.
public static String readStringFromStream(InputStream in) throws IOException {   
        StringBuilder sb = new StringBuilder(1024);
   
        for (int i = in.read(); i != -1; i = in.read()) {
            sb.append((char) i);
        }   
        in.close();   
        return sb.toString();
}

InputStream 을 byte array로 반환하는 넘
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

public static byte[] readBytesFromStream(InputStream in) throws IOException {
        int i = in.available();
        if (i < DEFAULT_BUFFER_SIZE) {
            i = DEFAULT_BUFFER_SIZE;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream(i);
        copy(in, bos);
        in.close();
        return bos.toByteArray();
}

public static int copy(final InputStream input, final OutputStream output) throws IOException {
         return copy(input, output, DEFAULT_BUFFER_SIZE);
}
     
public static int copy(final InputStream input, final OutputStream output, int bufferSize) throws IOException {
        int avail = input.available();
        if (avail > 262144) {
            avail = 262144;
        }
        if (avail > bufferSize) {
            bufferSize = avail;
        }
        final byte[] buffer = new byte[bufferSize];
        int n = 0;
        n = input.read(buffer);
        int total = 0;
        while (-1 != n) {
            output.write(buffer, 0, n);
            total += n;
            n = input.read(buffer);
        }
        return total;
}

Posted by 짱가쟁이
매번 까먹고 다시 만들고.. 머릿속의 지우개는 어떻게 하지 못하는 건지.... 쩌ㅃ~

 /**
     *
     * @param format
     *             ex> format : yyyyMMddHHmmssSSS
     * @return
     */
    public static String getCurrentTime_0(String format) {
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);

        return dateFormat.format(calendar.getTime());
    }

    public static String getCurrentTime_1(String format) {
        DateFormat df = new SimpleDateFormat(format); // HH=24h, hh=12h
         return df.format(System.currentTimeMillis());
    }

- format 을 맞춰주면 오늘 날짜/시간을 가져온다. 밀리세컨드 까징..
- 뭐 나오세컨드 까지 나온듯 싶지만.. 고넘은 벌써 까먹음.. 다음에 기회가 생기면 그때.. 쩌ㅃ~
Posted by 짱가쟁이
String 클래스에 repalceAll() 요넘.. '$' 특수문자 변환에 걸려서리.. 사용하기 존내 짜증남.. 예전에 어떻게 처리 한거 같기도 한데.. 마찮가지로 머릿속의 지우개가 문제인듯.

public static String replaceAll(String buffer, String src, String dst)
{
    if (buffer == null)
        return null;
    if (src == null || buffer.indexOf(src) < 0)
        return buffer;

    int bufLen = buffer.length();
    int srcLen = src.length();
    StringBuffer result = new StringBuffer();

    int i = 0;
    int j = 0;
    for (; i < bufLen;)
    {
        j = buffer.indexOf(src, j);
        if (j >= 0)
        {
            result.append(buffer.substring(i, j));
            result.append(dst);

            j += srcLen;
            i = j;
        }
        else
            break;
    }
    result.append(buffer.substring(i));
    return result.toString();
}

Posted by 짱가쟁이
quartz를 사용하고 멀티쓰레드로 작업을 병렬로 처리하던중.. 작업지연으로 인해서 이전 작업이 끝나기도 전에 다음 작업이 시작된다. 뭐.. 가장 좋은 방법은 단순하게 쿼즈가 실행하는 쓰레드 하나만 사용하면 좋것지만.. DB 성능 문제로 인해서 꼭 병렬처리를 수행해야 한다면.. ?? 이때.. Callable 인터페이스를 사용하여 쓰레드의 결과값을 받을 수 있다.

Launcher.java
private final ExecutorService executor  = Executors.newFixedThreadPool(THEAD_SIZE);

public void excute() {
    Future[] future = new Future[THEAD_SIZE];
    for(int i = 0;i<THEAD_SIZE;i++) {
        future[i] = executor.submit(new WokerThread(synchData, 1, totalCount, reqVo));                       
    }
    for(int i = 0;i<THEAD_SIZE;i++) {
        info.info("[" + future[i].get() + "] 종료" );   
    }
}

Callable을 구현한 넘
import java.util.concurrent.Callable;

public class WokerThread implements Callable<String> {
  
    public String call() {       
        while(true) {           
            return (String)Thread.currentThread().getName();
        }
    }
}

위에 샘플은 단순한 사용방법을 구현했지만.. 다양한 방법으로 유용하게 사용할 수 있을듯.


Posted by 짱가쟁이

- Sample
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumFractionDigits(9);
nf.setGroupingUsed(false);

nf.format((double)228588.0/(double)1000000000.0);

- Result
0.000228588

'java > util' 카테고리의 다른 글

Calendar, SimpleDateFormat 사용하자  (0) 2010.06.28
[replaceAll] - 문자열 치환  (0) 2010.06.28
[정규식] - Pattern 을 사용한 Validate  (0) 2010.06.25
[정규식] - 한글 검사  (0) 2010.06.25
[정규식] - 초성 검사  (0) 2010.06.25
Posted by 짱가쟁이

package com.util;

import java.util.regex.Pattern;

/**
 * 정규식을 이용한 값 체크
 *
 * @author bbaeggar
 *
 */
public class ValidationUtil {

    /**
     * 일반 전화번호 검증
     *
     * @param phoneNum
     * @return
     */
    public static boolean isNomalPhoneNumber(String phoneNum, String separate) {
        String regEx = "^\\d{2,3}"+separate+"\\d{3,4}"+separate+"\\d{4}$";      
        return Pattern.matches(regEx, phoneNum);
    }
  
    /**
     * 모바일 전화번호 검증
     *
     * @param phoneNum
     * @return
     */
    public static boolean isMobilePhoneNumber(String phoneNum, String separate) {
        String regEx = "^01(?:[0-9])"+separate+"(?:\\d{3}|\\d{4})"+separate+"\\d{4}$";      
        return Pattern.matches(regEx, phoneNum);
    }

    /**
     * V4 Ip Address 검증
     *
     * @param ipAddress
     * @return
     */
    public static boolean isIpAdressVersion4(String ipAddress) {
        String regEx = "([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})\\.([0-9]{1,3})";      
        return Pattern.matches(regEx, ipAddress);
    }
  
    /**
     * 주민번호 검증
     *
     * @param ipAddress
     * @return
     */
    public static boolean isJuminNumber(String number) {
        String regEx = "\\d{6}\\-[1-4]\\d{6}";      
        return Pattern.matches(regEx, number);
    }

    /**
     * 이메일 검증
     *
     * @param email
     * @return
     */
    public static boolean isEmail(String email) {
        String regEx = "^([0-9a-zA-Z_-]+)@([0-9a-zA-Z_-]+)(\\.[0-9a-zA-Z_-]+){1,2}$";      
        return Pattern.matches(regEx, email);
    }
  
    public static void main(String[] args) {      
        System.out.println(ValidationUtil.isNomalPhoneNumber("02-123-4516", "-"));
        System.out.println(ValidationUtil.isMobilePhoneNumber("016-0014-1234", "-"));
        System.out.println(ValidationUtil.isIpAdressVersion4("1.1.1.1"));
        System.out.println(ValidationUtil.isJuminNumber("123456-1634316"));
        System.out.println(ValidationUtil.isEmail("bbaeggar@gmail.com"));
    }
}

Posted by 짱가쟁이