참조


Excel file을 다루는 Java APIs 를 소개한다. 위 참조를 보면 자세한 설명이 있음. 간략하게 소개하면..
1. Andy Khan's Java Excel API
2. The xlSQL Excel JDBC Driver
3. OpenXLS
4. Apache POI



Posted by 짱가쟁이
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 짱가쟁이
apache cxf 는 기본적으로 thread safety를 지원 하지 않는다고 한다. 뭐 그래서 어쩌구 저쩌구 하지만... 다른 방법으로 할수 있다고는 한다.

cxf.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xsi:schemaLocation="
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <httpj:engine-factory bus="cxf">
        <httpj:engine port="9000">
            <httpj:sessionSupport>true</httpj:sessionSupport>
        </httpj:engine>
    </httpj:engine-factory>
  
    <cxf:bus>
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>
</beans>

Server Side - service class
package bbaeggar.jaxws.simple.server.service;

import javax.annotation.Resource;
import javax.jws.WebService;
import javax.servlet.http.HttpSession;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

@WebService(endpointInterface = "bbaeggar.jaxws.simple.server.service.Login",
        serviceName = "Login")
public class LoginImpl implements Login {

    //webServiceContext is injected by the JAXWS API
    @Resource private WebServiceContext wsContext;
  
    SessionVo sessionVo;
  
    @Override
    public boolean login(String id, String pw) {
        // TODO Auto-generated method stub

        MessageContext mc = wsContext.getMessageContext();
        HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession(true);
        // Get a session property "counter" from context
        if (session == null)
            System.out.println("session is null");
              
        sessionVo = new SessionVo();
      
        sessionVo.setId(id);
        sessionVo.setPw(pw);

        session.setAttribute("session", sessionVo);
              
        return true;

    }

    @Override
    public String getId() {
        // TODO Auto-generated method stub      
        MessageContext mc = wsContext.getMessageContext();      
        HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();      
        SessionVo vo = (SessionVo)session.getAttribute("session");

        return vo.getId();      
    }
}

Client side class
package bbaeggar.jaxws.simple.client;

import java.util.Map;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

import bbaeggar.jaxws.simple.server.service.HelloWorld;
import bbaeggar.jaxws.simple.server.service.Login;

public class TestRunnable implements Runnable {
  
    @Override
    public void run() {
        login();      
    }
  
    public void login() {
                  
        Service service = Service.create(Client.SERVICE_LOGIN);
        String endpointAddress = "http://localhost:9000/Login";
        service.addPort(Client.PORT_LOGIN, SOAPBinding.SOAP11HTTP_BINDING, endpointAddress);
      
        Login login = service.getPort(Login.class);
      
        Map requestContext = ((BindingProvider)login).getRequestContext();
        requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
      
        String id = "bbaeggar" + Thread.currentThread().getId();
      
        boolean isLogin = login.login(id, "aaaa");
      
        System.out.println("client : " + login.getId());
      
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
      
        if(id.equals(login.getId())) {
            System.out.println("같은 세션임");
        } else {
            System.out.println("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
        }
    }
}


위 코드는 미친척하고 테스트용으로 만든거임.. 테스트용으로만 사용하삼.  쩌ㅃ~
Posted by 짱가쟁이
KTF Khub 작업을 하던중... jdk 1.6 버전에서 khub 테스트 코드가 동작을 안하더라.. 이유를 찾아보니.. jaxb 버전 문제로 클라이언트 코드가 동작은 안함. 뭐. jdk 버전을 낮춰서 작업하면 되것지만.. cxf를 공부하고 있는 도중이였기에 cxf에서 제공하는 "wsdl2java" 툴을 사용하게 되었음.

우선 콘솔창에서 작업해도 무난히 동작하지만.. 이클립스를 사용하기 때문에 편하게 ant로 작업했음.(이클립스 너무 편한듯.. 쩌ㅃ~)

khub_wsdl2java.xml
<?xml version="1.0"?>
<project name="cxf khub_wsdl2java" basedir="."> 
   <property name="cxf.home" location ="C:\Develop\02. Documents\01. Apache cxf\apache-cxf-2.2.7\apache-cxf-2.2.7"/>

   <path id="cxf.classpath">
      <fileset dir="${cxf.home}/lib">
         <include name="*.jar"/>
      </fileset>
   </path>
    
   <target name="cxfWSDLToJava">
      <java classname="org.apache.cxf.tools.wsdlto.WSDLToJava" fork="true">
         <arg value="-client"/>
         <arg value="-d"/>
         <arg value="D:\wsdl2java\khub_client"/>
         <arg value="http://125.131.85.42/khub/WebService?wsdl"/>
         <classpath>
            <path refid="cxf.classpath"/>
         </classpath>
      </java>
   </target>
</project>

cxf 홈 디렉트리, java code 생성 경로, wsdl 경로만 변경하면.. 무난히 동작함.
Ant로 빌드하면 코드가 생성되는데.. 패키지 구조가 좀 지져분한게 생성됨.. 뭐 따로 설정하면 되것지만.. 이거는 수작업을 함.
생성된 빌드를 보면 "IWebService_IWebServicePort_Client" 라는 넘이 있는데.. 이놈이 실제로 Entry point 가 된다.
jdk1.6 으로 작업하고 싶다면.. Apache CXF를 사용하는 것도 무난할듯..

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 짱가쟁이
우선은 JAX-WS 에서 soap 과 http binding 의 endpoint sample을 올린다. http binding은 RS 가 좀더 낳다는 의견이 많지만, soap과 같이 서비스하며, 코드를 재사용할 수 있다는 장점 때문에 WS를 사용하게 됨.

sample
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://cxf.apache.org/jaxws
    http://cxf.apache.org/schemas/jaxws.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-http-binding.xml" />

<!-- The service bean -->
   <bean id="demoServiceImpl" class="cxf.demo.service.DemoServiceImpl" />

   <jaxws:endpoint id="getServiceHttp"
      implementor="#demoServiceImpl"
      implementorClass="cxf.demo.service.DemoService"
      address="/DemoService"
      bindingUri="http://apache.org/cxf/binding/http">
      <jaxws:serviceFactory>
         <ref bean="jaxWsServiceFactoryBean"/>
      </jaxws:serviceFactory>
   </jaxws:endpoint>
  
   <jaxws:endpoint
      id="getServiceSoap"
      implementor="#demoServiceImpl"
      implementorClass="cxf.demo.service.DemoService"
      address="/DemoService/soap" />
           
   <bean id="jaxWsServiceFactoryBean"
    class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean" scope="prototype">
      <property name="wrapped" value="false" />
   </bean>    
</beans>
<!-- END SNIPPET: beans -->


'framework > apache cxf' 카테고리의 다른 글

[Apache cxf] - session support  (0) 2010.06.28
[Apache cxf] - WSDL to Java  (0) 2010.06.28
[Apache cxf] cxf, axis2, metro 성능 비교  (0) 2010.06.28
[Apache cxf] - client remote ip 가져오자  (1) 2010.06.28
[CXF] - cxf 소개  (0) 2010.06.28
Posted by 짱가쟁이
졸라 할게 많아서 짜증이 나기는 하지만.. 하나하나 찾는 재미는 쏠쏠한듯..

밑에 코드는 웹 서비스에 Request를 보내는 넘의 IP를 가져오는 코드임

@Resource
private WebServiceContext context;
  
/**
* Clinet IP 를 가져온다.
* @return
*     remote ip
*/
private String getRemoteAddr() {
   MessageContext msgCtxt = context.getMessageContext();
   HttpServletRequest req = (HttpServletRequest)msgCtxt.get(MessageContext.SERVLET_REQUEST);
   String clientIP = req.getRemoteAddr();

   return clientIP;
}

'framework > apache cxf' 카테고리의 다른 글

[Apache cxf] - session support  (0) 2010.06.28
[Apache cxf] - WSDL to Java  (0) 2010.06.28
[Apache cxf] cxf, axis2, metro 성능 비교  (0) 2010.06.28
[Apache cxf] - Spring 에서 endpoint 설정하자  (0) 2010.06.28
[CXF] - cxf 소개  (0) 2010.06.28
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 짱가쟁이
출처
 - http://www.ibm.com/developerworks/kr/library/j-jws12.html (Java 웹 서비스 : CXF 소개)
 - http://www.ibm.com/developerworks/kr/library/ws-pojo-springcxf/(CXF 와 스프링을 사용하는 웹 서비스 만들기 소개)

IBM developerworks 에 소개된 기사들임.

최근에 한글로 번역된듯해서 올린다.
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 짱가쟁이