일반적으로 자바 디컴파일러에 JAD 를 많이 사용하나, JAD 는 1.5 버젼부터는 잘 지원안된다.

그래서 보통 JD 를 많이 사용하는데, JD core 를 이용한 JD-Gui 를 이용하여 주로 사용한다.

허나, 이 또한 일부 디컴파일된 파일이 불안전할 수 가 있는데, 그 대안으로 cfr 을 추천한다.

cfr 또한 불안전한 파일이 나올 수 있으므로 본인은 JD-Gui 로 선행 작업 후, 컴파일 오류가 나는 것들에 대해서 cfr 로 디컴파일한 파일들을 사용한다. 

CFR

cfr 은 java 로 개발된 디컴파일로써, java8 의 람다와 java 7 의 switch 등을 지원한다.

http://www.benf.org/other/cfr/ 에서 최신 버젼을 내려 받은 후 다음과 같이 실행하면 된다. (문서 작성 당시에 cfr 버젼은 0.8.1 이었다.)

> java -jar cfr_0_81.jar <디컴파일할 jar 파일 경로> --outputdir <디컴파일된 소스 파일이 등록될 경로>

다음은 샘플이다.

D:\App\cfr>java -jar cfr_0_81.jar lnk.jar --outputdir d:/app/cfr/result

물론 이렇게 단순한 방법 말고도, 디컴파일시 소스 번호가 나오게 한다던지 등등 다양한 옵션이 존잰한다.

자세한 방법은 --help 를 쳐보면 된다 (웃음)

D:\App\cfr>java -jar cfr_0_81.jar --help
CFR 0_81
   --showops                        (int >= 0)  default: 0
   --decodeenumswitch               (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --sugarenums                     (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --decodestringswitch             (boolean)  default: true if class file from
version 51.0 (Java 7) or greater
   --arrayiter                      (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --collectioniter                 (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --innerclasses                   (boolean)  default: true
   --removeboilerplate              (boolean)  default: true
   --removeinnerclasssynthetics     (boolean)  default: true
   --decodelambdas                  (boolean)  default: true if class file from
version 52.0 (Java 8) or greater
   --hidebridgemethods              (boolean)  default: true
   --liftconstructorinit            (boolean)  default: true
   --removedeadmethods              (boolean)  default: true
   --removebadgenerics              (boolean)  default: true
   --sugarasserts                   (boolean)  default: true
   --sugarboxing                    (boolean)  default: true
   --showversion                    (boolean)  default: true
   --decodefinally                  (boolean)  default: true
   --tidymonitors                   (boolean)  default: true
   --lenient                        (boolean)  default: false
   --dumpclasspath                  (boolean)  default: false
   --comments                       (boolean)  default: true
   --forcetopsort                   (boolean)
   --forceexceptionprune            (boolean)
   --outputdir                      (string)
   --stringbuffer                   (boolean)  default: false if class file from
 version 49.0 (Java 5) or greater
   --stringbuilder                  (boolean)  default: true if class file from
version 49.0 (Java 5) or greater
   --silent                         (boolean)  default: false
   --recover                        (boolean)  default: true
   --eclipse                        (boolean)  default: true
   --override                       (boolean)  default: true if class file from
version 50.0 (Java 6) or greater
   --aexagg                         (boolean)
   --forcecondpropagate             (boolean)
   --hideutf                        (boolean)  default: true
   --hidelongstrings                (boolean)  default: false
   --commentmonitors                (boolean)  default: false
   --allowcorrecting                (boolean)  default: true
   --labelledblocks                 (boolean)  default: true
   --j14classobj                    (boolean)  default: false if class file from
 version 49.0 (Java 5) or greater
   --hidelangimports                (boolean)  default: true
   --recovertypeclash               (boolean)
   --forcereturningifs              (boolean)
   --help                           (string)

  

참조 : 다른 디컴파일러들에 대한 정보는 다음 링크에 잘 나와있다.

https://community.jboss.org/people/ozizka/blog/2014/05/06/java-decompilers-a-sad-situation-of

Java 로 구현하는 JMeter 샘플러 구현방법이다.

우선 다음의 라이브러리를 의존 라이브러리로 추가한다.

pom.xml
<dependency>
    <groupId>org.apache.jmeter</groupId>
    <artifactId>ApacheJMeter_core</artifactId>
    <version>2.8</version>
</dependency>           
 
<dependency>
    <groupId>org.apache.jmeter</groupId>
    <artifactId>ApacheJMeter_java</artifactId>
    <version>2.8</version>
</dependency>

작성할 주요 부분은 다음 4가지 부분이다.

  • AbstractJavaSamplerClient 상속 받기
  • 기본 파라미터 생성 부분
  • 파라미터 가져오는 부분
  • 실행 하는 부분

AbstractJavaSamplerClient 상속받기

Jmeter 테스트 소스로 인식하고 잘 동작하기 위해서 AbstractJavaSamplerClient 를 상속받아 자신의 클래스를 만든다.

 

CreateFileTest.java
public class CreateFileTest extends AbstractJavaSamplerClient implements Serializable {
 
 
}

 

기본 파라미터 생성

기본 파라미터는 JMeter 화면에서 테스트 클래스를 선택했을 때 나타나는 다음과 같은 파라미터 화면이다.



이 기본 값들을 생성해줌으로써 좀 더 테스트가 원할해질 수 있겠다.

CreateFileTest.java
@Override
public Arguments getDefaultParameters() {
    Arguments params = new Arguments();
    params.addArgument("url", "http://localhost:8080/vine-rpc");
    params.addArgument("file", "input file path");
    params.addArgument("limitFileSize", "-1");
    params.addArgument("maxFileSizeForHessian", "-1");
    return params;
}

파라미터 가져오기

파라미터 가져오는 단계는 테스트 소스를 실행할 때, 사용자가 입력한 파마미터를 실행 클래스에 전달해 실행을 준비한다.

말을 어렵게 했지만, 여튼 사용자가 입력한 값을 테스트 클래스에서 가지고 간다는거다.

CreateFileTest.java
private long limitFileSize = -1L;
private long maxFileSizeForHessian = -1L;
private File file;
private EcmClient ecmClient;   
 
@Override
public void setupTest(JavaSamplerContext context) {
    getLogger().debug(whoAmI() + "\tsetupTest()");
    listParameters(context);
    limitFileSize = context.getLongParameter("limitFileSize", limitFileSize);
    maxFileSizeForHessian = context.getLongParameter("maxFileSizeForHessian", maxFileSizeForHessian);
    String url = context.getParameter("url");
    this.file = new File(context.getParameter("file"));
             
    DomainConfig config = new DomainConfig();
    config.setLimitFileSize(limitFileSize);
    config.setMaxFileSizeForHessian(maxFileSizeForHessian);
    config.getUrls().add(new EcmUrl(url));
     
    Configuration configuration = new Configuration(config);
    ecmClient = configuration.makeStub();
     
}

 

실행 부분

이부분은 아주 중요한 부분이다. 

SampleResult 를 생성하고, 던져줘야하며. 실제 시간을 체크하고 싶은 시점에 sampleStart 와 sampleEnd 를 찍어준다.

CreateFileTest.java
public SampleResult runTest(JavaSamplerContext context) {
    SampleResult results = new SampleResult();
    FileInputStream fis = null;
    try {
        // Record sample start time.
        results.sampleStart();
        fis = new FileInputStream(this.file.path);
        ecmClient.createFile(this.file.name, null,null, null, fis);
        results.setSuccessful(true);
    } catch (Exception e) {
        results.setSuccessful(false);
    } finally {
        IOUtils.closeQuietly(fis);
        results.sampleEnd();
    }
    return results;
}


배포하기

만들어진 소스는 jar 파일 형태로 패키징하여 ${JMETER_HOME}/lib/ext 에 넣는다.

그리고 재시작하면 된다. 

이제 다 죽었다..ㅋㅋㅋㅋ

참조 : http://www.javajigi.net/pages/viewpage.action?pageId=184

대부분이 OOME 등이 발생하면 이런 쉬운것(메모리 분석)도 안해보고 왜 그러지, 왜 그러지 하면서 이것저것 손보는데 시간만 보내기십상이다. 

일단 이거 엄청 간단하니깐 일단 이렇게부터 해보구 삽질을 했으면 좋겠다.-_- 여우같은 마눌 보러 가야징


JVM 메모리 분석을 위한 과정은 다음과 같다.

  1. 분석할 프로세스 ID 조회
  2. 메모리 힙덤프 추출
  3. 힙덤프 분석

분석할 프로세스 ID 조회

프로세스 id 조회는 ps - ef | grep 찾을 놈 관련된 텍스트 와 같이 하면 아래와 같이 귀찮게 나올 수 있다. 이건 뭐, 얼마 안된 케이스긴 하지만. 여튼 그렇다.

 

shell.sh
[freshkorea@multi-003 ~]$ ps -ef | grep freshkorea
root     12044  3911  0 15:16 ?        00:00:00 sshd: freshkorea [priv]
1493     12105 26169  0 15:16 ?        00:00:00 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
1493     12205 12044  0 15:17 ?        00:00:00 sshd: freshkorea@pts/2
1493     12655 26169  0 15:17 ?        00:00:00 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
1493     12925 26169  0 15:17 ?        00:00:00 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
1493     13004 26169  0 15:17 ?        00:00:00 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
1493     13005 26169  0 15:17 ?        00:00:00 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
1493     14438 12206  0 15:17 pts/2    00:00:00 grep freshkorea
root     26169     1  0 Jan30 ?        00:05:26 /usr/local/apache2/bin/httpd -k start -f /usr/local/apache2/conf/hosting/freshkorea/httpd.conf
root     27019  3911  0 15:11 ?        00:00:00 sshd: freshkorea [priv]
1493     27051 27019  0 15:11 ?        00:00:00 sshd: freshkorea@notty
1493     29991     1  1 Mar29 ?        00:44:22 /usr/local/jdk/bin/java -Djava.util.logging.config.file=/home/hosting_users/freshkorea/tomcat/conf/logging.properties -XX:MaxPermSize=128m -Xmx128m -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/home/hosting_users/freshkorea/tomcat/endorsed -classpath /home/hosting_users/freshkorea/tomcat/bin/bootstrap.jar -Dcatalina.base=/home/hosting_users/freshkorea/tomcat -Dcatalina.home=/home/hosting_users/freshkorea/tomcat -Djava.io.tmpdir=/home/hosting_users/freshkorea/tomcat/temp org.apache.catalina.startup.Bootstrap start

그럴 땐 JDK/bin 밑에 있는 jps 명령을 이용하자.

jps 는 현재 계정의 java 프로세스만 보여준다.

 

shell.sh
[freshkorea@multi-003 ~]$ jps
29991 Bootstrap
14957 Jps

와우! 바로 딱 나온다. 

tomcat 은 실행시 bootstrap.jar 를 이용하기 때문에 bootstrap 으로 나온다.
이거 가지고 잘 모르겠다면, 'jps -mlv' 이렇게 쳐보라. -_-)b

메모리 힙덤프 추출

보통 힙 덤프 뜰 땐 kill -3 <pid> 를 사용한다. 허나, 그렇게 해도 안찍힐 경우에 jmap 을 이용해 보자.
jmap dump:format=b,file=<output filename> <pid>
메모리 분석을 위해서 fomat=b 을 줌으로써, 바이너리 파일로 생성해야한다.

 

healdump.sh
[freshkorea@multi-003 ~]$ jmap -dump:format=b,file=heap.hprof 29991
Dumping heap to /home/hosting_users/freshkorea/heap.hprof ...
Heap dump file created
[freshkorea@multi-003 ~]$

힙덤프 분석

힙덤프는 분석 툴을 이용해 분석하는게 편하다. eclipse 의 mat 은 공짜이면서 leak 원인까지 찾아주는 기능이 있다.

http://www.eclipse.org/mat/

받아서 설치하자. (그냥 압축 풀면 끝이다.)

설치 후에 Fille -> Open -> Heap dump 를 하면 결과가 다음처럼 대충 나온다. 

 

 

그리고 Details 를 클릭해서 들어가보면 다음과 같이 나온다. 

여기선 hashMap 이 아주 무식하다는게 드러난다. 

 

이제 소스를 보면 왜 이런 참상이 생겼는지 알꺼다.

이렇게 OOME 가 엄청 간단하게 해결되었다.


J2EE5 vs J2EE6

JPA 1.0(in J2EE5) vs JPA 2.0(in J2EE6)

에 관해서 좋은 글들이 있네요.

혹시 링크 바뀔까바, JPA 2.0 에 대한 문서는 별도도 첨부합니다.

jpa-2.0.pdf


얼마전 백기선님의 "스프링 MVC에서 타일즈 2 사용하기" 포스팅을 참조로 스트라이프에서 스프링 MVC + 타일즈로 갈아탔었다. 당시에는 급박해서 그냥 그대로 하긴 했었는데 다음과 같이 페이지마다 definition 을 설정하는 것은 영 성가신게 아니다.

<definition name="cm/meta/meta.create" extends="tiles/cm">

<put-attribute name="title" value="메타 속성 등록" />

<put-attribute name="menu" value="/tiles/menu.cm.jsp" />

<put-attribute name="description" value="메타 속성을 등록합니다." />

<put-attribute name="body" value="/cm/meta/meta.create.spring.jsp" />

</definition>

<definition name="cm/meta/meta.modify" extends="tiles/cm">

<put-attribute name="title" value="메타 속성 수정" />

<put-attribute name="menu" value="/tiles/menu.cm.jsp" />

<put-attribute name="description" value="메타 속성을 수정합니다." />

<put-attribute name="body" value="/cm/meta/meta.modify.spring.jsp" />

</definition>

<definition name="cm/meta/meta.delete" extends="tiles/cm">

<put-attribute name="title" value="메타 속성 삭제" />

<put-attribute name="menu" value="/tiles/menu.cm.jsp" />

<put-attribute name="description" value="메타 속성을 삭제합니다. 이미 컨텐츠 유형이나 분류체계 유형에서 사용하고 있다면 삭제할 수 없습니다. 정말 삭제하시겠습니까?" />

<put-attribute name="body" value="/cm/meta/meta.delete.spring.jsp" />

</definition>


1. 기본 스프링 & 타일즈 설정


그래서 이런 노가다를 없앨 수 있는 방법을 타일즈에서는 여러가지 방법으로 제공하고 있다.

이번에 적용할 방법은 EL 표현식과 와일드카드를 이용하는 방법이다.

이런 방법을 사용하기 위해서는 타일즈 팩토리를 만들어 낼 때, 몇가지 설정이 추가되어야하는데 다행히 스프링에서 엄청 간단한 방법을 제공하고 있다.


<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">

<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"></property>

<property name="order" value="1" />

</bean>

<bean id="viewResolver2" class="org.springframework.web.servlet.view.BeanNameViewResolver" >

<property name="order" value="2"></property>

</bean>

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="prefix" value="/" />

<property name="suffix" value=".spring.jsp" />

<property name="order" value="3" />

</bean>

<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">

<property name="completeAutoload"><value>true</value></property>

<property name="definitions">

<list>

<value>/WEB-INF/tiles2/tiles-*.xml</value>

</list>

</property>

</bean>


위 소스는 뷰리졸버로, 첫번째로 타일즈 뷰 그거없으면 빈네임으로, 그것도 없으면 jsp 렌더링으로 하라는 소스다. 요건 하든지 말든지 알아서 하시고 ㅎㅎ,

여튼, 중요한건 타일즈 속성의 completeAutoload 속성을 true 로 하면 여러가지 표현식을 사용할 수 있게 된다.

물론 이러한 기능을 사용하기 위해서는 tiles-core 가 아닌 tiles-extra 라이브러리가 필요하다.

메이븐 설정에 다음이 들어가 있어야한다.(물론 메이븐을 안 쓰면, 라이브러리만 구해다가 클래스 패스에 등록하면 된다)


<dependency>

<groupId>org.apache.tiles</groupId>

<artifactId>tiles-extras</artifactId>

<version>2.2.2</version>

</dependency>


자, 이제 필요한 설정은 전부 끝났다.

와일드카드와 EL 표현식을 적용한 샘플을 작성해보자.

우선 레이아웃 페이지를 작성한다.


/layout/admin-layout.xml

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %><%@ 

taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ 

taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><%@

taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"

%><!doctype html>

<html lang="ko">

<head>

<meta charset="utf-8">

<meta name="description" content="타일즈 어플리케이션">

<meta name="keywords" content="">

<title><tiles:insertAttribute name="title" /></title>

</head>

<body>

<div id="header">

<h1><tiles:insertAttribute name="title" /></h1>

<nav id="main-menu"><tiles:insertAttribute name="menu" /></nav>

</div>

<div id="page-content">

<tiles:insertAttribute name="body" />

</div>

</body>


주의 깊게 볼 부분은 레이아웃에 넘겨줄 속성 부분이다. 위 샘플은 title, menu, body 를 넣도록 하고 있다.


그다음은 타일즈에서 해당 레이아웃을 사용하고, 각 속성을 넣을 방법을 정의하는 타일즈 deifnition 설정 부분이다.


/WEB-INF/tiles2/tiles-layout.jsp

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

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

<!-- Default Layout -->

<definition name="default-layout" template="/layout/default-layout.jsp">

<put-attribute name="title" value="무제" />

<put-attribute name="menu" value="/layout/empty.jsp" />

<put-attribute name="body" value="/layout/empty.jsp" />

</definition>

<!-- Content -->

<definition name="tiles/admin/index" extends="default-layout">

<put-attribute name="title" value="관리자 페이지" />

<put-attribute name="menu" value="/layout/menu.admin.jsp" />

<put-attribute name="body" value="/admin/index.jsp" />

</definition>

</tiles-definitions>


일단은 definition 에서 수동으로 들어갈 값을 직접 입력해보았다. 이후에 el 표현식과 와일드 카드를 순차적으로 적용하는 것을 보여드릴테니, 조급해하지 마시길:)


그다음은 컨트롤러다.


import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.servlet.ModelAndView;


@Controller

public class AdminController {

@RequestMapping("/admin/index.do")

public ModelAndView adminIndex() {

ModelAndView mav = new ModelAndView("tiles/admin/index");

return mav;

}

}



위와 같이 작성하면 /admin/index.do 로 접근시에 다음과 같이 렌더링된다.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="description" content="타일즈 어플리케이션">
<meta name="keywords" content="">
<title>관리자 페이지</title>
</head>
<body>
<div id="header">
<h1>관리자 페이지</h1>
<nav id="main-menu">
<ul>
<li>전광판 관리</li>
<li>사용자 관리</li>
</ul>
</nav>
</div>
<div id="page-content">
<p>관리자 페이지입니다.</p>
</div>
</body>




자, 이제 노가다를 없애보자.


2. EL 적용


우선 타이틀을 타일즈 설정 파일에서 박는게 아니라 컨트롤러에서 값을 유동적으로 변경 가능하도록 해보자.

컨트롤러를 다음과 같이 title attirbutue 를 추가한다.

@Controller

public class AdminController {

@RequestMapping("/admin/index.do")

public ModelAndView adminIndex() {

ModelAndView mav = new ModelAndView("tiles/admin/index");

mav.addObject("title", "관리자 페이지");

return mav;

}

}


그리고 타일즈 설정파일에 해당 값을 el 표현식으로 바꾼다. value 속성이 아닌 expression 속성을 사용한다는 것을 명심하자.


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

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

<!-- Default Layout -->

<definition name="default-layout" template="/layout/default-layout.jsp">

<put-attribute name="title" value="무제" />

<put-attribute name="menu" value="/layout/empty.jsp" />

<put-attribute name="body" value="/layout/empty.jsp" />

</definition>

<!-- Content -->

<definition name="tiles/admin/index" extends="default-layout">

<put-attribute name="title" expression="${title}" />

<put-attribute name="menu" value="/layout/menu.admin.jsp" />

<put-attribute name="body" value="/admin/index.jsp" />

</definition>


</tiles-definitions>


끝이다. 

만약, template 속성에도 el 을 적용하고 싶을 경우에는 template 속성 대신, templateExpression 속성을 


3. 와일드 카드 적용


이번엔 와일드 카드를 이용해서, body 영역과 메뉴도 동적으로 변경해보자. (이부분도 el 표현식을 이용해도 상관은 없다. 이 글에선 샘플 작성을 위해 일부러 와일드 카드를 이용한다.)


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

<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN" "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">

<tiles-definitions>

<!-- Default Layout -->

<definition name="default-layout" template="/layout/default-layout.jsp" templateExpression="">

<put-attribute name="title" value="무제" />

<put-attribute name="menu" value="/layout/empty.jsp" />

<put-attribute name="body" value="/layout/empty.jsp" />

</definition>

<!-- Content -->

<definition name="WILDCARD:tiles/*/**" extends="default-layout">

<put-attribute name="title" expression="${title}" />

<put-attribute name="menu" value="/layout/menu.{1}.jsp" />

<put-attribute name="body" value="/{1}/{2}.jsp" />

</definition>

</tiles-definitions>


우선 와일드 카드를 사용하는 부분에 대해선 "WIDCARD:" 라고 prefix 코드를 넣어줘야한다. 

그러며 * 패턴에 대해 매칭되는 갑사을 순차적으로 {1}, {2} 등으로 사용할 수 있게 한다.


위 설정대로라면 "/tiles/admin/index" 라는 뷰네임은 다음과 같이 매핑된다.

  • {1} : admin
  • {2} : index
패턴중에 ** 라고 기입을 하면, '이하' 로 풀이한다. (앤트 표현식)
위와 같이 설정한 이유는 다음과 같은 방식에서도 유효하게 하기 위함이다.

예를 들어 "tles/admin/user/manage" 일 경우
  • {1} : admin
  • {2} : user/manage
이렇게 와일드 카드와 el 표현식을 이용해 노가다를 상당히 줄여줄 수 있을 것이다. 다만, 스트라이프처럼 jsp 에 레이아웃으로 값을 넘기는 방법에 대해서는 아직 모르겠다. (타일즈 3.x 에서는 있으려나 모르겠다.)


이 문서는 스프링 3.0.7, tiles 2.2.2 로 작성되었다.


참조링크

  • http://whiteship.me/?p=11657
  • http://tiles.apache.org/2.2/framework/tutorial/advanced/wildcard.html
  • http://tiles.apache.org/2.2/framework/tutorial/advanced/el-support.html
  • http://kaludin.egloos.com/2799009



  1. 죠니 2013.03.13 08:33

    이런글은 추천하라고 배웠습니다.

Stripes 가 워낙 편해서 왠간하면 잘 쓸라했는데, 다른 WAS 는 잘 돌아가는데 꼭 웹로직과는 문제가 생긴다.

지금까지 내가 발견했던 악성 궁합은 이렇다. 대체로 문제가 발생하는 것은 레이아웃 기능을 사용하면 그렇다. 하지만 레이아웃 기능을 뺀 스트라이프트는 스트라이프가 아니지-_-;; (물론 빼도 쓸만하지만, 너무 매력적이지..음)

 

 WAS Stripes 버젼  내용 

 Weblogic 10.0

1.5.3 

레이아웃 고급 기능이 제대로 동작안한다. 1.5.4 에서는 패치되었다. 

- Layout break

- Fixed 1.5.4

 Weblogic 11g(10.3.5)

1.5.4 

화면이 안나온다. 

- No Visible

 Weblogic 12c

1.5.6 

레이아웃이 이상하게 나온다. 1.5.7-SNAPSHOT 에서는 수정되었다.

- Fixed 1.5.7-SNAPSHOT

 Weblogic 12c

1.5.7-SNAPSHOT 

수정된 줄 알았으나, 이슈 트래커에는 수정된 것으로 나온다. 하지만, 일부 페이지에는 화면이 안 나오는 부분이 있다.

* 현재 다른 원인이 있는지 제가 그 원인을 찾고 있는 중입니다.:)

- Fixed 1.5.7-SNAPSHOT???

 Jeus 5.x 1.5.4 

레이아웃 사용시 동적 속성을 String 외에 사용할 수 없다.  

* 이 부분은 제우스가 표준을 안 지킨 것인지, 다른 WAS 가 기능이 더 좋아서 그런것인지는 불분명하다.

- Can't use dynamic attribute for Layout

 Jeus 6.x

1.5.7-SNAPSHOT 

web.xml 에서 welocme page 로 등록된 페이지에 접근시('/' 으로 접근시), Stripes  Filter 를 통과하지 못한다.

- Incorrect Weblcome Page

 Tomcat 6.x

1.5.3 ~ 1.5.7-SNAPSHOT 

Good 
 Jetty

1.5.3 ~ 1.5.7-SNAPSHOT

Good 

 Websphere 8.0

1.5.6  Good 

 

톰캣은 아주 좋다. 개발자가 톰캣만 테스트만 하나보다.

여튼 1.6.0 도 기대해보지만, 과연 나오긴 할 것인지..

Stripes 마지막 릴리즈가 1년전이다. -_-;

 

그래서 직접 Stripes 소스를 분석해 커미터가 되어볼까, 아니면 그냥 다른 사람들 많이 쓰는 Spring Web MVC 조합으로 바꿔버릴까,

 

 

이전에 웹로직에 JDBC 데이터 소스 등록하기 에 대한 페이지를 작성한 적이 있으나, 웹스피어는 또 다른 방식이므로 또 작성해본다. 처음 웹스피어를 써보는 사람은 당황할거 같으니, 이 글이 도움이 되었으면 좋겠다.

* Websphere Application Server 8.0, Oracle 11g Tested.


#

웹스피어에 JDBC 데이터 소스도 웹로직 데이터 소스와 동일하게 클래스패스 구성과 데이터 소스 구성 단계를 거친다.

 

단, 웹로직에서는 클래스 패스 구성을 실행 스크립트에 직접 수정해줘야하지만, 웹스피어에슨 관리 콘솔에서 클래스 패스를 입력해야하는 차이가 있다.

 

1. JDBC 제공자 등록

 

JDBC 드라이버를 위한 클래스 패스를 구성하는 방법이다. 웹 스피어에어스는 JDBC 제공자라는 이름으로 드라이버에 대해 접근하게 한다.

이 방법은 웹로직보다 웹스피어가 나은 방법이다. 실제로 스크립트 손보는 것은 쉽고, 어렵고를 떠나서 귀찮으니 말이다.

  1. '자원/JDBC 제공자' 메뉴를 선택한 후, 범위를 지정하고 '새로 작성' 을 클릭한다.
  2. 데이터베이스 유형을 선택한다.
  3. 클래스 경로를 입력한다. 실제 jdbc.jar 파일을 찾을 수 있는 경로를 파일명까지 입력해야한다. (스크린샷은 환경변수를 등록해야만 가능하다. 귀찮다면, 그냥 풀패스 경로를 입력하는게 편하다.)
  4. '완료' 를 클릭한다.
  5. 마스터 구성에 직접 '저장' 을 클릭한다.
  6. 클래스 패스를 다시 읽어들이도록 서버를 재시작한다. 


2. 데이터 소스 등록하기


  1. '자원/JDBC/데이터 소스' 메뉴로 들어온 후, 범위를 선택하고 '새로 작성' 을 클릭한다.
  2. 데이터 소스 이름과 JNDI 이름을 입력한다. 데이터 소스 이름은 관리를 위한 이름이며, JNDI 이름은 실제로 어플리케이션 JNDI 룩업을 할 때 사용하는 이름이다.
  3. '기존의 JDBC 제공자 선택' 을 체크하고, 이전에 등록한 JDBC 제공자를 선택한다.
  4. 데이터베이스 접속 URL 을 입력한다. 오라클의 경우는 'jdbc:oracle:thin:@[HOST]:[PORT]:[SID]' 이와 같이 하면 되겠다.
  5. 인증 정보를 선택한다. 웹스피어에서는 데이터소스 등록할 때, DB 접속 사용자 id 와 비밀번호를 직접 입력하지 않고, 인증정보를 만든 후에 해당 인증 정보를 이용하도록 한다. 지금은 아직 계정에 대한 정보를 설정하지 않았으므로 그냥 진행한다. 
  6. '완료' 를 클릭한다.
  7. 마스터 구성에 직접 '저장' 을 클릭한다.
  8. 그 후 생성된 데이터 소스를 선택하고, '연결 테스트' 를 클릭해보면 사용자 아이디와 패스워드가 없다로 에러가 뜬다. 당연한 결과다. 생성한 데이터 소스를 선택한다.
  9. 화면 우측에 '관련 항목/JAAS - J2C 인증 데이터' 를 클릭한다.
  10. '새로 작성' 을 클릭한다.
  11. DB 접속 계정을 설정한다.
  12. 마스터 구성에 직접 '저장' 을 클릭한다. 그 후 다시 이전에 생성한 데이터 소스 선택 화면으로 돌아간다. ('데이터 소스 > 데이터 소스 선택')
  13. 그 후 하단에 조금 전에 생성한 인증 데이터를 설정한 후 '확인' 을 클릭한다.
  14. 마스터 구성에 직접 '저장' 을 클릭한 후, 다시 연결 테스트를 시도 한다.
  15. 서버를 재시작 할 필요는 없으며, 해당 데이타 소스를 사용할 어플리케이션을 재시작하면 된다.

 

  1. 장태 2012.06.01 10:12

    고새정리해서 올렸나?ㅋㅋㅋㅋㅋㅋㅋㅋ

웹로직 12c 에 아파치 dbcp 로 데이터 소스를 구성할 경우, 서버 자체가 응답이 없는(무한 대기 상태에 빠지는) 현상이 발생한다. 결국, 자체적인 데이터 소스를 구성하지 않고, 웹로직의 데이터 소스를 구성해 jndi 로 룩업하여 해결하였다. 아파치 dbcp 를 사용하기 위해서 다른 설정을 해야할 것인지, 아니면 그냥 버그인지는 모르겠으나 일단 좀 더 아름다운 구성이 맞을거 같아서 버그 리포팅은 안하기로 했다.


여튼, 이거 하느라고 하루를 날려버린 것도 있고, 웹로직에 오라클이 아닌 타 벤더의 JDBC 데이터 소스를 등록할 경우, 시간을 허비할 지 모르는 개발자들을 위해 블로깅을 해본다.


이 문서에서는 MS 사의 SQL Server 용 JDBC 등록하는 것에 대하여 작성할 것이다. 

본 문서에 사용된 환경 변수에 대한 패스 정보는 다음과 같다.


 변수

설명

예제 경로 
 WL_HOME  웹로직이 설치된 홈 디렉토리  C:\Oracle\Middleware\wlserver_12.1
 WLS_HOME  홈 디렉토리 하위 Server 디렉토리  C:\Oracle\Middleware\wlserver_12.1\serve

작업 절차는 크게 다음과 같다.

  • JDBC 드라이버를 클래스 패스에 등록한다.
  • 관리콘솔에서 데이터 소스를 등록한다.

참조 : http://docs.oracle.com/cd/E24329_01/web.1211/e24367/jdbc_datasources.htm#g1218593


1. JDBC 드라이버 클래스 패스에 등록


오라클에 접속할 경우에는 이미 라이브러리가 클래스 패스에 존재하므로, 이 부분은 지나쳐도 된다.


웹로직에서는 데이터소스를 등록할 경우, 유명한 벤더들의 DBMS 에 대한 설정은 이미 제공되고 있다. 하지만, 오라클 외 타 벤더들에 대한 JDBC 에 대한 설정만 제공하지, 드라이버를 클래스패스에 두고 있지는 않다.


즉, 웹로직 관리콘솔에서 등록한다고 해서 무조건 돌아갈 거 다라는 것은 아니다라는 것이다. 잘 만들어진 GUI 에 현혹 되면 안된다.


그러나, 웹로직에서는 클래스 패스에 해당 드라이버를 넣어주고 있지는 않지만, 참조용으로 제공은 하고 있다. 


해당 드라이버들은 WL_HOME\server\lib 에서 찾을 수 있으며, 파일명은 다음과 같다.

  • For DB2: wldb2.jar
  • For Informix: wlinformix.jar
  • For MS SQL Server: wlsqlserver.jar
  • For Sybase: wlsybase.jar

참조 : http://docs.oracle.com/cd/E24329_01/web.1211/e24376/dd.htm#JDBCP153



해당 파일을 찾았으면, 클래스 패스에 등록을 해야하는데 다음 2가지 위치에서 택일을 한다.


  • 모든 도메인에 해당 드라이버를 적용하고 싶을 경우, WL_HOME/common/bin 하위에 commEnv.cmd/sh 파일을 편집하여 WEBLOGIC_CLASSPATH 환경변수에 jar 파일 위치를 추가한다.
  • 특정한 웹로직 서버 도메인에 해당 드라이버를 적용하고 싶을 경우, 도메인디렉토리/bin 하위에 setDomainEnv.cmd/sh 파일을 편집하여 PRE_CLASSPATH 환경변수에 jar 파일 위치를 추가한다.

다음은 SQL Server 용 jar 를 특정 도메인 환경에 적용한 경우이다.


[setDomainEnv.cmd]

set POST_CLASSPATH=%POST_CLASSPATH%;%WLS_HOME%\lib\wlsqlserver.jar


참조 : http://docs.oracle.com/cd/E24329_01/web.1211/e24487/weblogicserver.htm#i1023430


설정이 모두 되었으면 서버를 재시작한다.

 


2. 관리 콘솔에서 데이터 등록


콘솔에서 등록은 위보다 더 쉽다. 나오는대로 잘 선택하면 해주면 된다.


관리 콘솔에 로그인 한 후 '서비스/데이터소스' 를 선택한 후 '추가' 버튼을 클릭한다.


jndi 에서 조회할 이름과 데이터소스명을 입력하고 데이터베이스 유형을 선택한다.


본 문서에서는 slothinkdb 명으로 MS SQL Server 를 선택했다.




데이터베이스 드라이버는 'Microsoft's MS SQL Server Driver (type4 XA) Versions:2005 and later' 를 선택한다.  




트랜잭션 옵션을 선택한다. MS SQL 은 별다른 트랜잭션 옵션이 없다. '다음' 을 클릭한다.



DB 정보를 입력하고 '다음' 을 클릭한다.



화면 하단 아래에서 '구성 테스트' 를 클릭하여 접속이 옳바르게 되는지 확인 한 후 '다음' 을 클릭한다.



배포할 서버를 선택한 후 '완료' 를 클릭한다.



이제 모든 설정이 완료되었으며, 배포된 서버에 있는 어플리케이션은 JNDI 룩업을 통해 해당 데이터소스를 사용할 수 있다.


* Tested. Oracle Weblogic 12c, MS SQL Server 2008 R2



간만에 글을 쓴다. 굉장히 철지난 글일지만 모르지만, 계속 갈릴레오를 고집하다가 하이버네이트 플러그인이 Helios 를 더 잘 지원해줘서 결국 올렸다.
다른 많은 분들이 꼭 이 플러그인들을 필요로 할지는 모르겠으나, 깔아둬서 언제고 꼭 도움이 되었음 좋겠다.

1.Eclipse 설치

이 문서의 기준은 2011.03.09 현재 Eclipse 3.6 (helios) 를 기준으로 한다.

다음 링크에서 Eclipse IDE for Java EE Developers 버젼을 내려받는다. (물론 원하는 버젼을 내려받아야하지만, 자바 웹개발자라면 해당 버젼이 좋다)

http://eclipse.org/downloads/

 

2.Eclipse 필수 플러그인 설치

다음 플러그인은 JBoss 툴즈를 설치하기 위한 필수 플러그인들이지만, 꼭 JBoss 툴즈가 아니더라도 반드시 설치되어야하는 플러그인들이다.

JBoss Tools 플로그인은 다음의 주소로 업데이트 받는다. 

JBoss Tools 에 유용한 것이 많이 있으므로, 필요한 것만 선택한다. 단, 다음의 것들은 반드시 설치한다.

  • Hibernate Tools
  • JMX Console
  • JBoss GWT Integration
  • FreeMakrder IDE
  • Maven Support 하위 모든 Plugins
  • Web and Java EE Developement 하위 모든 Plugins

JBoss Tools Update URL 에 대한 접속이 원할하지 않을 경우에는 JBoss Tools 페이지(https://www.jboss.org/tools/download/stable.html)에서 JBoss 툴즈 안정버젼을 내려받아서 설치할 수 있다.

현 시점에 JBoss Tool 에 대한 최신 버젼은 3.2.0.GA Stable 이다. 오프라인 설치에 대한 자세한 설명은 https://www.jboss.org/tools/download/installation/update_3_2.html#fromzip 링크를 참조한다.

요약하여, 설명하자면 플러그인 사이트 주소를 추가할 때, 주소 입력이 아닌 Archive 를 눌러서 다운받은 파일을 선택하라는 내용이다.

 

3.설치 Screen Shot

1. 이클립스 실행 후 [Help -> Install New Software] 클릭

eclipse-helios-plugin-01.png

2. [Add] 버튼을 클릭하여 플러그인 저장소를 추가한다.
추가할 저장소들은 위 내용을 참조한다.

eclipse-helios-plugin-02.png

3. 설치할 항목들을 선택한다.

eclipse-helios-plugin-03.png

4. 설치할 항목들이 나타난다. 만일 설치해야할 플러그인이 옳바르지 않거나, 선행으로 설치해야할 플러그인이 존재하지 않거나 할 경우에는 [Back] 을 클릭하여 해당 항목을 제거하고 진행하면 된다.

eclipse-helios-plugin-04.png

5. 라이센스에 동의한다.

eclipse-helios-plugin-05.png

6. 플러그인을 설치하면 이클립스를 재시작한다는 메시지가 나온다. 재시작한 후, 다른 플러그인도 위 1~5단계를 반복하여 설치한다.

eclipse-helios-plugin-06.png

eclipse-helios-plugin-07.png

eclipse-helios-plugin-08.png

eclipse-helios-plugin-09.png

eclipse-helios-plugin-10.png

eclipse-helios-plugin-11.png

eclipse-helios-plugin-12.png

eclipse-helios-plugin-13.png

eclipse-helios-plugin-14.png

eclipse-helios-plugin-15.png

eclipse-helios-plugin-16.png

eclipse-helios-plugin-17(1).png

#URL 로부터 받아지지 않거나, 또는 빠르게 설치하고 싶은 경우에는 위 내용처럼 jboss tool 플러그인 파일을 직접 내려받은 후 [Archive] 를 선택하여 해당 파일을 선택후 설치할 수 있다.

이후 과정은 동일하다.

eclipse-helios-plugin-18(2).png

 eclipse-helios-plugin-19.png

#아래와 같이 나오는 것은, "서명되지 않은 플러그인이라서 위험할 수 있다. 그래도 진행하겠냐?" 라는 내용이다. [OK] 를 클릭하여 진행한다.
eclipse-helios-plugin-20.png


끝이긴 한데, 혹시 이 글을 읽는 분들 중에 "개발자라면 이정도는 가지고 있어야하는거 아니냐? 이 무개념아"라고 말씀해주실분은 플러그인 추천도 부탁드립니다. ^^ 

  1. 지나가는 개발자 2011.04.20 13:52

    정말 좋은 정보 감사합니다!!!

 유지보수 프로젝트에 들어가거나, 기존 업무 환경에서 작업해야할 경우 자신이 사용하고 있는 클래스가 위치한 위치를 찾고 싶은 경우가 있다.

다음과 같은 경우가 필요한 예일 것이다.

  • 실제 파일 위치를 확인 하기 위해서
  • NoSuchMethodError 가 날경우

 1. 실제 파일 위치를 찾기 위한 경우

해당 클래스가 위치한 실제 파일을 찾을 경우는 여러가지가 있다.

공통 jar 를 누군가가 배포해놓았는데, 교체를 해야하는데 어딨는지 도통 모르겠다거나,

그놈의 파일을 얻어다가 디컴파일 하고 싶은 욕구가 생길 경우가 그럴 경우다.

 2. NoSuchMethodError 가 날 경우

이 에러가는 나는 이유는 명백하다. 해당하는 클래스에 호출하는 메소드(메서드명과 인자가 일치하는) 가 없을 경우에 발생한다.

이 에러는 보통 다음과 같은 케이스에 발생하기 쉽다.

  • 런타임 환경에 배포를 안했을 때
  • 클래스 패스가 여러개 있어서, 우선순위가 높은 클래스패스에 이미 해당 클래스가 올려져 있을 때

런타임 환경에 배포를 안 했을 경우에는 참으로 기본적인 것이라 설명하는 것조차 무색하지만

후자의 경우에 많은 개발자들이 당황하기 쉽상이다.

즉, 다른 놈의 jar 안에 동일한명의 클래스가 올려져 있어서 이미 배포가 되어있는데 그것을 모르고 "배포했는데 왜 안되지? 왜 안되지?내렸다 올려도 안되네?"  하는 경우다.

하지만 프로그램은 참으로 정직하다.

대개 많은 개발자들이

내가 운영하고 있는 것도 아니고, 서버 구성도 모르는데 제가 어떻게 압니까?  나 몰라요 몰라

 할지 모르겠으나, 자바가 클래스 로드하는 개념만 분명히 알고 있다면 전혀 두려워 할 필요가 없을 거이다.

 

배포된 파일을 찾고자 할 경우에 해당하는 패키지명과 클래스는 개발자는 분명히 알고 있을것이다.

다음과 같이 작성하여 출력해보면 해당 위치를 찾을 수 있다.

 

java.net.URL r = this.getClass().getClassLoader().getResource("nts/toolkit/EnvelopedMessage.class");
System.out.println(r.toString());

 이 예는 nts.toolkit.EnvelopedMessage.class 가 어딨는지 출력하는 예이다. 이것을 출력하면 다음과 같은 출력을 볼 수 있다.

 

jar:file:/sys0.d/jeusdev2/jeus5/lib/application/NtsApi.jar!/nts/toolkit/EnvelopedMessage.class

 

이 말인 즉슨 jar 파일로 만들어져 있으며 jar 파일은 /sys0.d/jeusdev2/jeus5/lib/application/NtsApi.jar 이고 그 안에 nts.toolkit.EnvelopedMessage.class 가 있다는 뜻이다.

내가 안했다고 두려워하지 말길,,,

이 글은 스프링노트에서 작성되었습니다.

톰캣을 시작했는데, localhost 로는 접속이 되는데 실제 ip 로는 접근이 안되는 경우가 있다.
그럴 때는 conf/server.xml 의 connector 부분에 address="0.0.0.0" 을 추가하면 된다.

<Connector port="8080" maxHttpHeaderSize="8192"
               maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               connectionTimeout="20000" disableUploadTimeout="true" 
               URIEncoding="UTF-8"
               address="0.0.0.0" />
  1. Say_G. 2013.09.12 15:53

    이럴수가... 구글에서 검색해서 어쩌다 들어와보니 이 블로그에 ㅋㅋㅋㅋ
    그런데 해결은 안됐음 (...)

    • BlogIcon slothink 편현장 2013.09.15 03:28 신고

      오오 간만에 댓글이이야 ㅋㅋㅋㅋ
      이걸로 해결안된다니 안타깝소.
      서버 접속이 안되는 경우야 원인이 허다하니깐 ㅋㅋ
      이젠 해결했으라나? ^^;

  2. 2014.11.20 15:45

    비밀댓글입니다

자바에서 사용하는 임시 디렉토리를 가져오는 방법을 설명해보겠습니다. 

사실 쉽기야 엄청 쉬운데 그 속성명을 매번 까먹는단 말이죠-_-;


환경 변수 읽어들이기

시스템에 정의된 설정을 자바에서 읽어들이는 방법입니다. 

이 방법을 통해서 어느 정도 어플리케이션에서 사용할 프로퍼티 양을 좀 줄일 수 있을 겁니다.


Properties properties = System.getProperties();

for(Entry entry : properties.entrySet()) {

System.out.println(entry.getKey()+"="+entry.getValue());

}


다음은 제 PC 에서 조회한 설정 정보입니다.

java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition

sun.boot.library.path=C:\Program Files (x86)\Java\jdk1.5.0_22\jre\bin

java.vm.version=1.5.0_22-b03

java.vm.vendor=Sun Microsystems Inc.

java.vendor.url=http://java.sun.com/

path.separator=;

java.vm.name=Java HotSpot(TM) Client VM

file.encoding.pkg=sun.io

sun.java.launcher=SUN_STANDARD

user.country=KR

sun.os.patch.level=

java.vm.specification.name=Java Virtual Machine Specification

user.dir=D:\workspace\vine\vine\fr

java.runtime.version=1.5.0_22-b03

java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment

java.endorsed.dirs=C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\endorsed

os.arch=x86

java.io.tmpdir=D:\Users\SLOTHI~1.000\AppData\Local\Temp\

line.separator=


java.vm.specification.vendor=Sun Microsystems Inc.

user.variant=

os.name=Windows 7

sun.jnu.encoding=MS949

java.library.path=C:\Program Files (x86)\Java\jdk1.5.0_22\bin;.;C:\Windows\system32;C:\Windows;C:/PROGRA~2/Java/JDK15~1.0_2/bin/../jre/bin/client;C:/PROGRA~2/Java/JDK15~1.0_2/bin/../jre/bin;E:\app\slothink\product\11.2.0\dbhome_1\bin;D:\app\apache-maven-2.2.1\bin;C:\PROGRA~2\Java\JDK15~1.0_2\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Microsoft SQL Server\80\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\90\DTS\Binn\;C:\Program Files (x86)\Microsoft SQL Server\90\Tools\binn\;C:\Program Files (x86)\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies\;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program Files (x86)\SecuwaySSL\bin

java.specification.name=Java Platform API Specification

java.class.version=49.0

sun.management.compiler=HotSpot Client Compiler

os.version=6.1

user.home=D:\Users\slothink.slothink-i7.000

user.timezone=

java.awt.printerjob=sun.awt.windows.WPrinterJob

file.encoding=UTF-8

java.specification.version=1.5

java.class.path=D:\workspace\vine\vine\fr\target\test-classes;D:\workspace\vine\vine\fr\target\classes;D:\workspace\vine\vine\common\target\classes;D:\workspace\vine\vine\springframework\target\classes;D:\Repositories\maven\org\springframework\spring\2.5.6\spring-2.5.6.jar;D:\Repositories\maven\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;D:\Repositories\maven\org\springframework\spring-beans\2.5.6\spring-beans-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-core\2.5.6\spring-core-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-context\2.5.6\spring-context-2.5.6.jar;D:\Repositories\maven\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;D:\Repositories\maven\org\springframework\spring-context-support\2.5.6\spring-context-support-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-aspects\2.5.6\spring-aspects-2.5.6.jar;D:\Repositories\maven\org\aspectj\aspectjrt\1.6.1\aspectjrt-1.6.1.jar;D:\Repositories\maven\org\aspectj\aspectjweaver\1.6.1\aspectjweaver-1.6.1.jar;D:\Repositories\maven\org\springframework\spring-aop\2.5.6\spring-aop-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-orm\2.5.6\spring-orm-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-tx\2.5.6\spring-tx-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-web\2.5.6\spring-web-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-webmvc\2.5.6\spring-webmvc-2.5.6.jar;D:\Repositories\maven\org\springframework\spring-test\2.5.6\spring-test-2.5.6.jar;D:\Repositories\maven\junit\junit\3.8.1\junit-3.8.1.jar;D:\Repositories\maven\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;D:\Repositories\maven\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;D:\Repositories\maven\log4j\log4j\1.2.14\log4j-1.2.14.jar;D:\workspace\vine\vine\hibernate\target\classes;D:\Repositories\maven\org\hibernate\hibernate-core\3.3.2.GA\hibernate-core-3.3.2.GA.jar;D:\Repositories\maven\antlr\antlr\2.7.6\antlr-2.7.6.jar;D:\Repositories\maven\commons-collections\commons-collections\3.1\commons-collections-3.1.jar;D:\Repositories\maven\dom4j\dom4j\1.6.1\dom4j-1.6.1.jar;D:\Repositories\maven\xml-apis\xml-apis\1.0.b2\xml-apis-1.0.b2.jar;D:\Repositories\maven\javax\transaction\jta\1.1\jta-1.1.jar;D:\Repositories\maven\org\hibernate\hibernate-ehcache\3.3.2.GA\hibernate-ehcache-3.3.2.GA.jar;D:\Repositories\maven\net\sf\ehcache\ehcache\1.2.3\ehcache-1.2.3.jar;D:\Repositories\maven\org\hibernate\hibernate-testing\3.3.2.GA\hibernate-testing-3.3.2.GA.jar;D:\Repositories\maven\javassist\javassist\3.9.0.GA\javassist-3.9.0.GA.jar;D:\Repositories\maven\cglib\cglib-nodep\2.2\cglib-nodep-2.2.jar;D:\Repositories\maven\org\slf4j\jcl-over-slf4j\1.6.1\jcl-over-slf4j-1.6.1.jar;D:\Repositories\maven\oro\oro\2.0.8\oro-2.0.8.jar;D:\Repositories\maven\commons-lang\commons-lang\2.4\commons-lang-2.4.jar;D:\Repositories\maven\org\apache\poi\poi\3.5-FINAL\poi-3.5-FINAL.jar;D:\Repositories\maven\org\apache\poi\poi-ooxml\3.5-FINAL\poi-ooxml-3.5-FINAL.jar;D:\Repositories\maven\org\apache\poi\ooxml-schemas\1.0\ooxml-schemas-1.0.jar;D:\Repositories\maven\org\apache\xmlbeans\xmlbeans\2.3.0\xmlbeans-2.3.0.jar;D:\Repositories\maven\stax\stax-api\1.0.1\stax-api-1.0.1.jar;D:\Repositories\maven\commons-fileupload\commons-fileupload\1.2.1\commons-fileupload-1.2.1.jar;D:\Repositories\maven\jazzlib\jazzlib\0.0.7\jazzlib-0.0.7.jar;D:\Repositories\maven\com\vine\ext\commons-mime\1.0\commons-mime-1.0.jar;D:\Repositories\maven\com\vine\ext\ostermillerutils\1.7.0\ostermillerutils-1.7.0.jar;D:\Repositories\maven\com\vine\ext\solme-jsacl\2.0\solme-jsacl-2.0.jar;D:\Repositories\maven\com\vine\ext\solme-api\1.0\solme-api-1.0.jar;D:\Repositories\maven\commons-configuration\commons-configuration\1.6\commons-configuration-1.6.jar;D:\Repositories\maven\commons-digester\commons-digester\1.8\commons-digester-1.8.jar;D:\Repositories\maven\commons-beanutils\commons-beanutils\1.7.0\commons-beanutils-1.7.0.jar;D:\Repositories\maven\commons-beanutils\commons-beanutils-core\1.8.0\commons-beanutils-core-1.8.0.jar;D:\Repositories\maven\commons-io\commons-io\1.4\commons-io-1.4.jar;D:\Repositories\maven\commons-dbcp\commons-dbcp\1.2.2\commons-dbcp-1.2.2.jar;D:\Repositories\maven\commons-pool\commons-pool\1.3\commons-pool-1.3.jar;D:\Repositories\maven\com\vine\ext\mssql\2005\mssql-2005.jar;D:\Repositories\maven\com\oracle\ojdbc14\10.2.0.3.0\ojdbc14-10.2.0.3.0.jar;D:\Repositories\maven\taglibs\standard\1.1.2\standard-1.1.2.jar;D:\Repositories\maven\javax\servlet\jstl\1.1.2\jstl-1.1.2.jar;D:\Repositories\maven\org\apache\geronimo\specs\geronimo-servlet_2.4_spec\1.1\geronimo-servlet_2.4_spec-1.1.jar;D:\Repositories\maven\org\apache\geronimo\specs\geronimo-jsp_2.0_spec\1.1\geronimo-jsp_2.0_spec-1.1.jar;/D:/app/eclipse-jee-galileo-SR2-win32/configuration/org.eclipse.osgi/bundles/309/1/.cp/;/D:/app/eclipse-jee-galileo-SR2-win32/configuration/org.eclipse.osgi/bundles/310/1/.cp/

user.name=slothink

java.vm.specification.version=1.0

java.home=C:\Program Files (x86)\Java\jdk1.5.0_22\jre

sun.arch.data.model=32

user.language=ko

java.specification.vendor=Sun Microsystems Inc.

awt.toolkit=sun.awt.windows.WToolkit

java.vm.info=mixed mode, sharing

java.version=1.5.0_22

java.ext.dirs=C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\ext

sun.boot.class.path=C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\rt.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\i18n.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\sunrsasign.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.5.0_22\jre\classes

java.vendor=Sun Microsystems Inc.

file.separator=\

java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi

sun.io.unicode.encoding=UnicodeLittle

sun.cpu.endian=little

sun.desktop=windows

sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86


임시 디렉토리 가져오기

항상 이 환경변수명을 까먹는데 말이죠. "java.io.tmpdir" 을 속성에서 읽어들이면 됩니다.

이것을 사용하면 시스템 전반에 걸치 임시 디렉토리를 사용할 수 있겟죠?


String dir = System.getProperty("java.io.tmpdir");

System.out.println("Temp Directory="+dir);


Temp Directory=D:\Users\SLOTHI~1.000\AppData\Local\Temp\


이 글은 스프링노트에서 작성되었습니다.

SVN 플러그인 subclipse 설치하기

 

  1. [Help] -> [Install New Software] 클릭
    install-eclipse-galileo-m2eclipse-subclipse-00.png
  2. [Add] 를 클릭한다.
    install-eclipse-galileo-m2eclipse-subclipse-01.png
  3. 추가하는 업데이트 사이트명을 지정하고, 로케이션은 다음과 같이 지정한다.
    Name : subclipse
    Location : http://subclipse.tigris.org/update_1.6.x
    install-eclipse-galileo-m2eclipse-subclipse-02.png
  4. 사이트를 추가하고 나면 해당 업데이트 URL 에 다음과 같은 설치할 수 있는 플로그인 목록이 나타난다. 적절한 항목을 선택한다.
    반드시 설치해야하는 것은 다음과 같다
    Core SVNKit Library, Subclipse
    install-eclipse-galileo-m2eclipse-subclipse-03.png
  5. 선택한 항목에 대한 자세한 정보가 기술된다. 만약 플러그인 의존성에 의해 설치할 수 없다고 나온다면, 이전 항목으로 돌아가 설치할 수 없는 항목을 제거하면 된다.
    install-eclipse-galileo-m2eclipse-subclipse-04.png
  6. 라이센스에 동의한다.

    install-eclipse-galileo-m2eclipse-subclipse-05.png

  7. 업데이트가 진행된다. 잠시 기다리자
    install-eclipse-galileo-m2eclipse-subclipse-06.png
  8. 사인되지 않은 경우, 다음과 같은 경고창이 될 수 있다. 그러나 우리는 믿을 수 있는걸 받고 있다. [OK]를 클릭하여 무시하고 진행한다.

    install-eclipse-galileo-m2eclipse-subclipse-07.png

  9. 플러그인 설치 후 이클립스를 재시작한다고 물어본다. [Yes] 를 클릭하여 재시작한다.

    install-eclipse-galileo-m2eclipse-subclipse-08.png

 

Maven 플러그인 m2eclipse 설치하기

 

m2eclipse 는 maven 이클립스 플러그인으로서 sonatype 에 의해 지원된다.

  1. 이클립스 기동 후 [Help] -> [Install New Software] 클릭한다
  2. [Add] 를 클릭한다.
    install-eclipse-galileo-m2eclipse-subclipse-10.png
  3. 추가할 사이트명과 주소를 지정한다.
    0.98 버젼의 update url 은 "http://m2eclipse.sonatype.org/update" 이었으나(스크린샷), 1.0에선 코어와 엑스트라로 구분되었다.
    현재는 0.98 버젼에 대한 지원이 사라졌다.
    따라서 2번의 추가가 필요한다.

  4. 업데이트 사이트를 추가하면, 다음과 같이 설치할 수 있는 플러그인 항목이 나타난다. 다음의 항목을 체크한다.
    install-eclipse-galileo-m2eclipse-subclipse-12.png
  5.  

    설치할 플러그인에 대한 세부 정보가 나타난다. 플러그인 의존성 실패로 메세지가 나올 경우엔 이전 화면으로 돌아가서 해당 항목을 제거하면 된다.
    install-eclipse-galileo-m2eclipse-subclipse-14.png

  6.  

    라이센스에 동의한다.
    install-eclipse-galileo-m2eclipse-subclipse-15.png

  7. 서명되지 않은 플러그인일 경우에 다음과 같은 경고창이 뜰 수 있다. 믿을만할걸 받고 있다. 무시한다.
    install-eclipse-galileo-m2eclipse-subclipse-16.png
  8. 모든 플러그인 설치 후 이클립스 재시작을 요구한다. [Yes] 클릭

    install-eclipse-galileo-m2eclipse-subclipse-17.png

이 글은 스프링노트에서 작성되었습니다.

작성자. 편현장(slothink)

작성일. 09-01-13

 

이 문서는 동일한 소스를 이용하지만, 환경에 의해 서로 다른 설정을 사용할 경우 profile filter 를 이요한 maven build 방법을 소개하고 있다. 또한 maven 의 실행에 대해서도 간략하게 설명한다.

 

maven의 명령을 실행하는 방법은 2가지가 있다.

 

l  command 창에서 명령어 직접 입력

l  m2clipse maven/build 명령을 이용하여 실행

 

command 창에서의 명령어 입력

command 창에서의 입력은 이전 개발 환경 구축하기 문서에서 적용하였던 패스 설정에 의하여(M2_HOME 또는 MAVEN_HOME 패스 설정) mvn.bat 을 실행하면 된다.

또한 이것을 실행할 경우엔 해당 pom 의 디렉토리로 이동하여 실행하면 된다.


d:\workspace\vines\vine\edms\edms-webapp>mvn package

 

m2clipse 를 이용한 maven 명령어 입력

프로젝트를 선택한 후 마우스 우클릭을 실행하면 run 항목 하위로 build 2가지를 찾을 수 있다. 단축키가 없는 하위 build 를 실행하여 실행할 속성들을 정의할 수 있다. 단축키가 있는 상위 build 항목은 이전에 실행했던 build 명령을 나열해준다. 단축키를 활용하면 매우편하다.


 

작품을 떨궈내려면 package goal 을 실행하면 된다. 실행방법은 위 2가지 중 어느 것을 선택해도 무방하다. m2clipse 의 경우 run as/maven package 가 이미 존재한다.

 

그러나 사이트별로 프로퍼티가 교체된 작품을 떨구기 위해선 package 실행 중에 profile 을 적용하여 실행하여야한다. 콘솔에선 아래와 같이 입력한다.

 

mvn package –P [profile id]

 

캐논용으로 떨구기 위한 예제는 아래와 같다.


mvn package -P canon



m2clipse 를 이용할 경우엔 profile 설정을 적용하기 위해서 Run as/package 가 아니라 Run as/build 항목을 이용하여 별도의 profile 을 기입해야한다.


위와 같이 실행하면 ${base}/target 디렉토리에 결과물(war,jar,pom 등이 생성된다.)

 

profile 이해하기

그러면 위 profile 은 어떤식으로 돌아가게 되는 것일까?

뒤에서부터 쫓아가보도록 하자.

 

goal 실행시 profile 옵션을 주게 되면(ex. mvn package –P slothink) (실행위치의)pom.xml, (실행위치의)profiles.xml, ${user.home}/settings.xml, ${M2_HOME}/conf/settings.xml 순으로 profile 항목을 찾는다. 이와 같이 찾는 도중에 profile id 가 동일한 경우가 나타나면 해당 profile 에서 선언된 내용을 적용한다.

 

다음은 profiles.xml 에 적용된 내용이다.



위에 경우에 profile 마다 별도의 property 를 설정하고 있다. slothink 의 경우 env 라는 프로퍼티의 값으로 slothink 를 할당하고 있다.

 

위와 같이 profile 을 적용하였다면 해당 적용사항은 pom 에서 사용한다. (사용안할 속성은 당연히 적을 필요가 없다).

 

pom.xml 을 살펴보자.


여기서 주의 깊게 볼 부분은 build/filters build/resources 항목이다. 이것이 의미하는 바는 filtering true 가 적용된 resource 안에 filters 에 등록된 값을 치환하라는 의미이다.

resource 항목은 치환대상이 되며 치환할 값은 filter 에 기술되어있다는 뜻이다. 치환된 resource build 시에 사용된다. 그리고 filter 파일을 선택하기 위해 이전 profile 항목에서 기술된 property 속성이 filter 경로에 사용된 것을 볼 수 있다.(i.e. ${env} )

 

실제 샘플을 보자.

src/main/resource/edms.properties (치환 대상 : 리소스)


 

src/main/filters/edms.properties (치환 값 : 필터)



위와 같이 치환 대상(리소스)은 치환할 부분을 ${[속성명]} 과 같이 기술하며 필터 파일에서는 [속성명]=[속성 값] 과 같이 기술한다.

 

이러한 메커니즘을 이용하여, 각 개발자는 자신의 환경에 맞게 profile filter 를 추가하여 사용할 수 있다.

 

그러나 매번 profile 사용하기 위해서 console 상에서 profile 옵션을 주거나 m2clipse build 항목을 이용하는 것은 불편할 것이다. 이것은 ${user.home}/settings.xml 이나 ${M2_HOME}/conf/settings.xml 에서 기본으로 실행할 profile 을 기술하므로 해결할 수 있다.

 

${M2_HOME}/conf/settings.xml


Maven Definitive Guide 는 sonatype 에서 제공한 온라인북인데(출판도 되었다), maven 에 대해 학습하기에 매우 좋다. 그러나 번역본으로 현재 나온 것은 없으나

http://homo-ware.tistory.com/48
에서 7장까지는 구할 수 있다. 7장까지라면 적어도 maven 이 무엇인가에 대해서는 충분히 알게 할 수 있는 분량이다. 번역을 해준 Elvis Lee 에게 감사를 드린다.

(그리고 whiteship 의 블로그도 많은 도움을 준다. http://whiteship.tistory.com/category/Build/Maven?page=2 )

다음의 내용은 위 문서에서 가져왔다.


원본 : http://www.sonatype.com/community/definitive_guide.html

Copyright

서문

1장. 아파치 메이븐 소개

2장. 메이븐 설치와 실행

I부. 메이븐 예제

II부. 메이븐 심화

8장. POM 최적화와 리팩토링

9장. 프로젝트 객체 모델

10장. 빌드 생명주기

11장. 빌드 프로필

12장. Maven 어셈블리

13장. 속성과 리스소 필터링

14장. 메이븐과 이클립스 : m2eclipse

15장. 사이트 생성

16장. 레파지토리 관리

17장. 플러그인 개발

18장. 다른 언어의 플러그인 개발

III부. 부록

부록 A. Settings 세부 내용

부록 B. 명세 대안들

java doc 생성시 일관되지 않은 방법으로 주석을 달아 의미없이 만들어지는 경우가 있다.
간단한 가이드를 작성해보았다.

 Java Doc 작성법


작성자 : 편현장(slothink@gmail.com)

작성일 : 2008.11.25


1.  Method 상단에 /** .. */ 주석을 추가하면, java doc 의 대상이된다.

2.  comment 는 반드시 /** 으로 시작해야한다. /* 은 java doc 의 대상이 아니다.

3.  메서드 설명은 html 형식으로 출력된다. 따라서 한줄 내리기 등은 <br /> 태그를 사용하는 등 html 구조에 맞춰 작성한다

4.  @param, @return, @throws 는 method 에서 필수속성이다(선언시)

기술 방법은 ex) @[type] [name] [description] 이다.
주의. Name 과 description 구분은 사이띄기로 구분한다. 만약, ‘-‘ 등의 값을 추가적으로 사용한다면, java doc 생성시에 - - 이 2개가 출력된다
(java doc 은 기본적으로 name 과 description 사이에 – 를 삽입한다)

5.  @throws 는 사용자가 처리해야할 예외이다. (예외는 에러가 아니다)
따라서 이 예외가 언제 발생하는지에 대해서 반드시 설명이 필요하다.

6.  @return 사용시 리턴 유형에 대해서는 기술할 필요가 없다. 왜냐하면, 이미 메서드 선언에 리턴 유형에 대해서 정의되어있기 때문이다.

@return Article 수정된 게시물 (x)
@return 수정된 게시물 (o)

7.  interface 가 존재한다면, 구현체에서는 주석을 달 필요가 없다.
interface 구현체는 interface 의 기능을 실제로 구현한 것이다.
다시말하자면, interface 에서 정의된 메서드의 의도대로 구현을 한 것이므로, interface 에서의 주석만으로 충분하다. 만약, 다르게 작성해야된다면, 올바르게 구현한것인지 다시 고려해봐야한다.
단, interface 에 정의되어 있지 않은 구현체의 method 는 주석을 필요로 한다.

8.  (non-JavaDoc) 는 eclipse 에서 주석 생성시 eclipse 안에 주석 템플릿이 존재하지 않을 경우에 자동 생성되는 코멘트다. 즉, java doc 생성시에는 의미없는 구문이다. 따라서 의미없는 주석은 삭제한다.

9.  주석 작성시, 다른 클래스를 참조할 경우에는 {@link } 를 사용한다.
이것은 java doc 에서 하이퍼링크를 생성한다. 화면에서는 클래스명만 나타난다.

사용 법 : {@link [class full name]}
ex) {@link com.vine.util.CommonWebFilter}

10.주석 작성시, code 를 기술할 경우엔, <pre> 태그를 사용한다.

<pre>
DetachedCrtieria crit = createCritera();
..
crit.addOrder(Order.asc(“name”));
</pre>

11.class 의 주석은 @author 태그와 설명을 필요로한다

/**
 * 시스템 환경 설정 저장소<br />
 * 시스템의 정의된 설정을 사용할 수 있다.
 * @author 편현장
public class SystemEnvirement {

}

잘못된 사용 예)

/**
 * 게시판을 생성한다.
 * 생성될 게시판코드가 이미 존재할 경우 예외를 발생시킨다.
 * @param code – 게시판 코드
*  @return Board – 생성된 게시판
 * @throws ExistCodeException
 */

/* (non-Javadoc)
 * @see com.comas.proguide.empower.EmpowerMenuService#getMenuAssignInfo()
 */

public Board create(String code) throws ExistCodeException {

교정 후)

/**
 * 게시판을 생성한다..<br />
 * 생성될 게시판 코드가 이미 존재할 경우 예외를 발생시킨다.
 * @param code 게시판 코드 // name 과 description 사이의 ‘-‘ 을 제거
* @return 생성된 게시판 // 반환 유형 기술(여기에선 Board) 삭제
 * @throws ExistCodeException 코드가 이미 존재하는 경우 // 주석 추가
 */
// 의미없는 eclipse 주석을 삭제하였다.(여기에서는 (non-JavaDoc).. )
public Board create(String code) throws ExistCodeException {

올바른 습관을 잘 들이자.

java 1.4 버젼에서 구동시에 발견된 문제다.
http://archive.apache.org/dist/xml/xerces-j/
에서 xerces-j-bin 최신버젼을 다운 받아 배포된 jar 파일을 클래스패스에 등록하면 문제 없이 돌아간다.

org.springframework.beans.factory.BeanDefinitionStoreException: Parser configuration exception parsing XML from class path resource [ehchurch-servlet.xml]; nested exception is javax.xml.parsers.ParserConfigurationException: Unable to validate using XSD: Your JAXP provider [org.apache.crimson.jaxp.DocumentBuilderFactoryImpl@12c7568] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.
 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:398)
 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:328)
 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:296)
 at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143)
 at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178)
 at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149)
 at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:212)
 at org.springframework.test.AbstractSingleSpringContextTests.createApplicationContext(AbstractSingleSpringContextTests.java:242)
 at org.springframework.test.AbstractSingleSpringContextTests.loadContextLocations(AbstractSingleSpringContextTests.java:212)
 at org.springframework.test.AbstractSingleSpringContextTests.loadContext(AbstractSingleSpringContextTests.java:187)
 at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:140)
 at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:100)
 at junit.framework.TestCase.runBare(TestCase.java:125)
 at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:76)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at junit.framework.TestSuite.runTest(TestSuite.java:208)
 at junit.framework.TestSuite.run(TestSuite.java:203)
 at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: javax.xml.parsers.ParserConfigurationException: Unable to validate using XSD: Your JAXP provider [org.apache.crimson.jaxp.DocumentBuilderFactoryImpl@12c7568] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.
 at org.springframework.beans.factory.xml.DefaultDocumentLoader.createDocumentBuilderFactory(DefaultDocumentLoader.java:102)
 at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:70)
 at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:382)
 ... 27 more
Caused by: java.lang.IllegalArgumentException: No attributes are implemented
 at org.apache.crimson.jaxp.DocumentBuilderFactoryImpl.setAttribute(DocumentBuilderFactoryImpl.java:93)
 at org.springframework.beans.factory.xml.DefaultDocumentLoader.createDocumentBuilderFactory(DefaultDocumentLoader.java:99)
 ... 29 more
일반적으로 자바 실행시 사용되는 변수명으로 JAVA_OPTS 를 사용한다.
따라서 윈도우의 환경변수나, 리눅스의 프로필 파일에 JAVA_OPTS 를 등록하면 자바 실행시에 옵션을 지정할 수 있다.

대표적으로 사용되는 옵션을 정리해보았다.
-XX:PermSize=4m -XX:MaxPermSize=32m -Xms64m -Xmx128m -XX:+PrintGCDetails

-XX:+PrintGCDetails 는 GC 로그를 출력하는 옵션이다. GC LOG는 기본적으로 stdout 으로 출력되기 때문에 파이프라인 등을 통하여 파일로 기록하는편이 분석하기에 좋을것이다. 윈도우용은 어찌해야할지 모르겠다. 아는 사람은 코멘트를 달아주시길 바랍니다 (_  _)
  1. slothink 2009.08.17 18:14

    -XX:PermSize=32m -XX:MaxPermSize=128m -Xms128m -Xmx512m

원문 번역중입니다.
원문 : http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html


Iterating over a collection is uglier than it needs to be. Consider the following method, which takes a collection of timer tasks and cancels them:
void cancelAll(Collection<TimerTask> c) {
for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); )
i.next().cancel();
}

The iterator is just clutter. Furthermore, it is an opportunity for error. The iterator variable occurs three times in each loop: that is two chances to get it wrong. The for-each construct gets rid of the clutter and the opportunity for error. Here is how the example looks with the for-each construct:

void cancelAll(Collection<TimerTask> c) {
for (TimerTask t : c)
t.cancel();
}

When you see the colon (:) read it as “in.” The loop above reads as “for each TimerTask t in c.” As you can see, the for-each construct combines beautifully with generics. It preserves all of the type safety, while removing the remaining clutter. Because you don't have to declare the iterator, you don't have to provide a generic declaration for it. (The compiler does this for you behind your back, but you need not concern yourself with it.)

Here is a common mistake people make when they are trying to do nested iteration over two collections:

List suits = ...;
List ranks = ...;
List sortedDeck = new ArrayList();

// BROKEN - throws NoSuchElementException!
for (Iterator i = suits.iterator(); i.hasNext(); )
for (Iterator j = ranks.iterator(); j.hasNext(); )
sortedDeck.add(new Card(i.next(), j.next()));

Can you spot the bug? Don't feel bad if you can't. Many expert programmers have made this mistake at one time or another. The problem is that the next method is being called too many times on the “outer” collection (suits). It is being called in the inner loop for both the outer and inner collections, which is wrong. In order to fix it, you have to add a variable in the scope of the outer loop to hold the suit:

// Fixed, though a bit ugly
for (Iterator i = suits.iterator(); i.hasNext(); ) {
Suit suit = (Suit) i.next();
for (Iterator j = ranks.iterator(); j.hasNext(); )
sortedDeck.add(new Card(suit, j.next()));
}

So what does all this have to do with the for-each construct? It is tailor-made for nested iteration! Feast your eyes:

for (Suit suit : suits)
for (Rank rank : ranks)
sortedDeck.add(new Card(suit, rank));

The for-each construct is also applicable to arrays, where it hides the index variable rather than the iterator. The following method returns the sum of the values in an int array:

// Returns the sum of the elements of a
int sum(int[] a) {
int result = 0;
for (int i : a)
result += i;
return result;
}
So when should you use the for-each loop? Any time you can. It really beautifies your code. Unfortunately, you cannot use it everywhere. Consider, for example, the expurgate method. The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it. Finally, it is not usable for loops that must iterate over multiple collections in parallel. These shortcomings were known by the designers, who made a conscious decision to go with a clean, simple construct that would cover the great majority of cases.

원문 번역중입니다.

원문 : http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html


당신이 Cellction 에서 element를 취할 때, 당신은 Collection 안에 저장되어있는 element로 타입을 캐스팅해야만 한다. 게다가 더 불편한것은, 이것은 위험하다는 것이다. 컴파일러는 당신이 Collection 타입을 동일하게 캐스팅했는데 체크하지 않으며, 따라서 런타임시에 캐스팅은 실패할 수 있다.

Generics 은 당신이 컴파일러에게 Collection의 타입에 대해 전할 수 있는 방법을 제공한다. 따라서 이것은 컴파일러에 의해 체크될 것이다. 한번에 컴파일러는 Collection의 타입을 알며, 당신이 Collection에 저장하거나 취할 때 올바른 캐스팅을 하고 있는지 체크할 수 있다.


여기에 Collection 튜토리얼로부터 얻은 간단한 예제가 있다.

// Removes 4-letter words from c. Elements must be strings
static void expurgate(Collection c) {
for (Iterator i = c.iterator(); i.hasNext(); )
if (((String) i.next()).length() == 4)
i.remove();
}


여기에 generic을 사용한 수정된 예제가 있다.

// Removes the 4-letter words from c
static void expurgate(Collection<String> c) {
for (Iterator<String> i = c.iterator(); i.hasNext(); )
if (i.next().length() == 4)
i.remove();
}

당신이 <Type> 코드를 보게 될 때, 이것은 "of Type"으로 읽는다. 위에 정의는 "Collection of String c"로 읽는다. generics를 사용한 코드는 더 깨끗하며 더 안전한다. We have eliminated an unsafe cast and a number of extra parentheses. More importantly, we have moved part of the specification of the method from a comment to its signature, so the compiler can verify at compile time that the type constraints are not violated at run time. Because the program compiles without warnings, we can state with certainty that it will not throw a ClassCastException at run time. The net effect of using generics, especially in large programs, is improved readability and robustness.

To paraphrase Generics Specification Lead Gilad Bracha, when we declare c to be of type Collection<String>, this tells us something about the variable c that holds true wherever and whenever it is used, and the compiler guarantees it (assuming the program compiles without warnings). A cast, on the other hand, tells us something the programmer thinks is true at a single point in the code, and the VM checks whether the programmer is right only at run time.

generics의 주된 사용은 Collection 이지만, 여기에는 다른 많은 사용법이 있다. “Holder classes,” such as WeakReference and ThreadLocal, have all been generified, that is, they have been retrofitted to make use of generics. More surprisingly, class Class has been generified. Class literals now function as type tokens, providing both run-time and compile-time type information. This enables a style of static factories exemplified by the getAnnotation method in the new AnnotatedElement interface:

    <T extends Annotation> T getAnnotation(Class<T> annotationType); 
This is a generic method. It infers the value of its type parameter T from its argument, and returns an appropriate instance of T, as illustrated by the following snippet:
    Author a = Othello.class.getAnnotation(Author.class);
Prior to generics, you would have had to cast the result to Author. Also you would have had no way to make the compiler check that the actual parameter represented a subclass of Annotation.

Generics are implemented by type erasure: generic type information is present only at compile time, after which it is erased by the compiler. The main advantage of this approach is that it provides total interoperability between generic code and legacy code that uses non-parameterized types (which are technically known as raw types). The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code. There is, however, a way to achieve guaranteed run-time type safety for generic collections even when interoperating with ill-behaved legacy code.

The java.util.Collections class has been outfitted with wrapper classes that provide guaranteed run-time type safety. They are similar in structure to the synchronized and unmodifiable wrappers. These “checked collection wrappers” are very useful for debugging. Suppose you have a set of strings, s, into which some legacy code is mysteriously inserting an integer. Without the wrapper, you will not find out about the problem until you read the problem element from the set, and an automatically generated cast to String fails. At this point, it is too late to determine the source of the problem. If, however, you replace the declaration:

    Set<String> s = new HashSet<String>();
with this declaration:
    Set<String> s = Collections.checkedSet(new HashSet<String>(), String.class);
the collection will throw a ClassCastException at the point where the legacy code attempts to insert the integer. The resulting stack trace will allow you to diagnose and repair the problem.

당신이 할 수 있는 모든 곳에서 generics를 사용할 수 있다. The extra effort in generifying code is well worth the gains in clarity and type safety. It is straightforward to use a generic library, but it requires some expertise to write a generic library, or to generify an existing library. There is one caveat: You may not use generics (or any other Tiger features) if you intend to deploy the compiled code on a pre-5.0 virtual machine.

If you are familiar with C++'s template mechanism, you might think that generics are similar, but the similarity is superficial. Generics do not generate a new class for each specialization, nor do they permit “template metaprogramming.”

generics 에 대해 좀 더 많은걸 배우고 싶다면  Generics Tutorial 여기를 보라.

1. 자바 SDK 를 다운받아 설치한다.(SDK : Standard Developer Kit, JDK: Java Developer Kit)
http://java.sun.com
J2EE는 엔터프라이즈용이다. EJB 등 J2EE 서버 개발 계획이 없다면, sdk로 설치한다.
설치경로는 임의대로 하되 디폴트 설치처럼 자바 버젼이 디렉토리명안에 들어가게 설치되는것을 권장한다.
ex) c:\j2sdk_1.4.12

2. 환경 변수를 설정한다.
예전 windwo 98이나, me 예선 command 창에서 set 명령어로 환경변수를 설정하는데, 윈도우 2000이나 xp 이상에선 시스템 화면에서 환경변수 창이 존재한다.
- 제어판 -> 시스템 -> 고급 -> 환경 변수로 이동한다.
- 환경변수에 아래 항목을 추가한다.
JAVA_HOME        C:\Program Files\J2SDK_1.5.11   (자바 SDK가 설치된 경로를 지정한다)
CLASS_PATH        .;%JAVA_HOME%\lib;               (현재 디렉토리와 자바의 기본라이브러리)
PATH                  %JAVA_HOME%\bin;                  (자바 실행 파일)

3. 제대로 되었는지 확인을 한다.
명령프롬프트(command.com or cmd.exe) 를 실행 시킨 후 프롬프트에

java -version

명령을 입력한다. 설치한 자바버젼이 올바르게 나온다면 정상적인 것이다.

- 알수 없는 명령이라고 나오면 path 변수에 자바설치경로\bin 디렉토리가 정확하게 설정되지 않은것이다.
- 설치한 버젼과 다른 버젼이 나온다면, 기존에 설치되어있던 자바 실행 경로가 우선순위가 높은 것이다. path에 등록된 항목을 살펴서, 앞쪽에 현재 설치한 sdk\bin 경로를 위치한다.

Seq Name Seq Name
\b backspace \f formfeed
\t horizontal tab \" double quote
\n newline \' single quote
\r carriage return \\ backslash
\### Latin encoded character \uHHHH Unicode encoded character
Calendar cal = Calendar.getInstance();
System.out.println("now:"+cal.getTime());
 
// Set date : 월은 0부터 시작된다
cal.set(year, month-1, day, hour, min, sec);

// Prev a year
cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) -1);
System.out.println("prev a year:"+cal.getTime());
 
 
// Prev a month
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) -1);
System.out.println("prev a month:"+cal.getTime());
 
// Prev a week
cal.set(Calendar.HOUR, -1 * 24 * 7);
System.out.println("prev a week:"+cal.getTime());
 
// Prev a day
cal.set(Calendar.HOUR, -24);
System.out.println("prev a day:"+cal.getTime());

+ Recent posts