티스토리 툴바


Closing a statement you left open, please do your own housekeeping

2011/01/26 20:55 | Posted by 포데브(엄지사랑) 엄지사랑
환경: JDK1.6.0_21 + JBoss EAP 4.3.2 + Spring 2.5.6 + iBATIS 2.3.4

19:50:53,405 WARN  [WrappedConnection] Closing a statement you left open, please do your own housekeeping
java.lang.Throwable: STACKTRACE
at org.jboss.resource.adapter.jdbc.WrappedConnection.registerStatement(WrappedConnection.java:872)
at org.jboss.resource.adapter.jdbc.WrappedStatement.<init>(WrappedStatement.java:62)
at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.<init>(WrappedPreparedStatement.java:56)
at org.jboss.resource.adapter.jdbc.WrappedConnection.prepareStatement(WrappedConnection.java:241)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:225)


Closing statements and ResultSets is important if you want to use prepared statement caching and/or don't won't to leak cursors in your database.


만약 prepared statement 캐슁을 사용하길 원하면서 데이터베이스의 커서가 누출(leak) 되지 않게 하려면 statements 와 ResultSets 을 닫아주는 것은 중요하다.


위의 링크를 참고해 보면 Connection leak 등을 추적하기 위한 용도로 사용하는 건데 사실 실제 소스코드를 보면 connection을 닫으려고 시도하고 있다. 만약 
Exception trying to close statement:
와 같은 경고를 만났다면 Connection leak이 발생할 수는 있다. 그러나 

Closing a statement you left open, please do your own housekeeping

와 같은 경고는 Connection을 생성한 곳에서 닫아야 한다는 원칙을 개발자에게 상기시켜주면서 해당 컨넥션을 닫아 주려고 시도한다.

결론은 트랜잭션이 제대로 설정되어 있지 않아서 Statement에 대해서 commit 이나 rollback이 발생하지 않았으므로 확인하라는 내용이다.

역시 경고는 무시하면 안된다. 

저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

No JTA TransactionManager found at fallback JNDI location

2010/12/31 19:47 | Posted by 포데브(엄지사랑) 엄지사랑
Jetty 6.1.11 + Spring 2.5.6에서 트랜잭션관리자를 <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" /> 와 같이 선언하고 로그레벨을 DEBUG 모드로 실행하면 다음과 같은 에러들을 볼 수 있다.

[DEBUG] (JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:comp/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'TransactionManager'

...

[DEBUG] (JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:appserver/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'appserver/TransactionManager'

...

(JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:pm/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'pm/TransactionManager'

...

(JtaTransactionManager.java:717) - No JTA TransactionManager found at fallback JNDI location [java:/TransactionManager]
javax.naming.NameNotFoundException; remaining name 'TransactionManager'

그러나 위의 예외메시지는 무시해도 될 것 같다. 
만약 JBoss에서 실행하면 java:/TransactionManager 은 설정되는 것을 확인했다. 

[DEBUG] (JtaTransactionManager.java:676) - JTA UserTransaction found at default JNDI location [java:comp/UserTransaction]

Jetty에서는 [java:comp/UserTransaction]만 설정하는 것같다.

JtaTransactionManager.java 파일의 내용을 보면 아래와 같은데 그냥 정보성으로 출력만 한다.
/**
* Fallback JNDI locations for the JTA TransactionManager. Applied if
* the JTA UserTransaction does not implement the JTA TransactionManager
* interface, provided that the "autodetectTransactionManager" flag is "true".
* @see #setTransactionManagerName
* @see #setAutodetectTransactionManager
*/
public static final String[] FALLBACK_TRANSACTION_MANAGER_NAMES =
new String[] {"java:comp/TransactionManager", "java:appserver/TransactionManager",
"java:pm/TransactionManager", "java:/TransactionManager"};

...

// Check fallback JNDI locations.
for (int i = 0; i < FALLBACK_TRANSACTION_MANAGER_NAMES.length; i++) {
String jndiName = FALLBACK_TRANSACTION_MANAGER_NAMES[i];
try {
TransactionManager tm = (TransactionManager) getJndiTemplate().lookup(jndiName, TransactionManager.class);
if (logger.isDebugEnabled()) {
logger.debug("JTA TransactionManager found at fallback JNDI location [" + jndiName + "]");
}
return tm;
}
catch (NamingException ex) {
if (logger.isDebugEnabled()) {
logger.debug("No JTA TransactionManager found at fallback JNDI location [" + jndiName + "]", ex);
}
}
}

위의 소스코드를 추적해보면 알겠지만 결국 최종 목적은 UserTransaction을 생성하는 것에 있다. 그리고 TransactionManager는 UserTransaction을 생성하기 위해 필요한 것이다.
       /**
* Initialize the UserTransaction as well as the TransactionManager handle.
* @throws TransactionSystemException if initialization failed
*/
protected void initUserTransactionAndTransactionManager() throws TransactionSystemException {
// Fetch JTA UserTransaction from JNDI, if necessary.
if (this.userTransaction == null) {
if (StringUtils.hasLength(this.userTransactionName)) {
this.userTransaction = lookupUserTransaction(this.userTransactionName);
this.userTransactionObtainedFromJndi = true;
}
else {
this.userTransaction = retrieveUserTransaction();
}
}

// Fetch JTA TransactionManager from JNDI, if necessary.
if (this.transactionManager == null) {
if (StringUtils.hasLength(this.transactionManagerName)) {
this.transactionManager = lookupTransactionManager(this.transactionManagerName);
}
else {
this.transactionManager = retrieveTransactionManager();
}
}

// Autodetect UserTransaction at its default JNDI location.
if (this.userTransaction == null && this.autodetectUserTransaction) {
this.userTransaction = findUserTransaction();
}

// Autodetect UserTransaction object that implements TransactionManager,
// and check fallback JNDI locations else.
if (this.transactionManager == null && this.autodetectTransactionManager) {
this.transactionManager = findTransactionManager(this.userTransaction);
}

// If only JTA TransactionManager specified, create UserTransaction handle for it.
if (this.userTransaction == null && this.transactionManager != null) {
this.userTransaction = buildUserTransaction(this.transactionManager);
}
}

이소스코드로 부터 예외를 내지 않게 하는 방법을 찾았는데 다음과 같이 WAS가 제공하는 것을 설정해주면 정상동작했다. 그러나 굳이 DEBUG 모드에서 스프링을 실행하지 않을 것이고 로드할 당시에만 발생하므로 무시해도 될것 같다.

  JBoss에서 예외로그 없이 동작하는 JtaTransactionManager 설정.
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" >
    <property name="autodetectTransactionManager" value="false"/>
    <property name="transactionManagerName" value="java:/TransactionManager"/>
  </bean>

결론은 내가 너무 예민한 것같다. ^^;
저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

JZ0SB: 매개변수 인덱스가 범위를 벗어났습니다. 1.

2010/12/31 13:10 | Posted by 포데브(엄지사랑) 엄지사랑
iBatis + Sybase ASE 15.5 (ISO1) + JavaSE 6(JDK1.6.0_21) 환경에서...

제목과 같은 예외가 발생했다. 실행한 SQL은 다음과 같다.
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="CM_CommonCode">

<!-- TODO 테스트를 위한 공통코드 업데이트 -->
<update id="updateCommonCode" parameterClass="CommonCode">
update
  IDCM..TC_CMN_CODE
set
  code_wrth_abrv_name = '테스트'
where code_id = #codeId#
  and code_wrth = #codeWrth#
</update>

</sqlMap>

그냥 지극히 평범한 SQL인데 왜 에러를 내는 것일까? 
문제의 원인은 Encode(Charset)에 있었다. 즉, 매핑 XML이 <?xml version="1.0" encoding="UTF-8"?>와 같이 UTF-8으로 선언되어 있고 DB는 ISO1로 선언되어 있어서 코드를 변환했을 때 에러가 나는 것이었다. 만약 한글을 직접넣고 싶다면 UTF-8을 EUC-KR로 변경하면 정상처리된다.


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

iBatis + Sysbase ASE 15.5 Unicode Column CRU 검증결과 및 적용방안

2010/12/16 11:09 | Posted by 포데브(엄지사랑) 엄지사랑

1. 검증결과: JBoss WAS 에서 JDBC를 연결할 때 다음과 같이 DataSource를 생성한다. 이 내용은 JBoss에 배포할 서버의 deploy/sybase-ds.xml 의 내용중 일부이다.

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

<datasources>

  <local-tx-datasource>

    <jndi-name>jdbc/KFlowDS</jndi-name>

    <connection-url>jdbc:sybase:Tds:localhost:3000</connection-url>

    <driver-class>com.sybase.jdbc3.jdbc.SybDriver</driver-class>

    <connection-property name="CHARSET">eucksc</connection-property>

    …

    <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.SybaseExceptionSorter</exception-sorter-class-name>

    <track-statements>true</track-statements>

    <metadata>

      <type-mapping>Sybase</type-mapping>

    </metadata>

  </local-tx-datasource>

</datasources>

여기서 핵심 내용은 JDBC의 속성중의 하나인 “CHARSET”“eucksc”로 설정함으로써 DB에서 읽거나 쓸 때 [iso1 : ISO-8859-1] – [eucksc: EUC-KR | KSC5601] 간 변환을 자동으로 처리해 준다. 문제는 DB 컬럼이 하나의 Charset이 아닌 경우 즉, Unicode 컬럼이 있는 경우에 대해서 검증이 필요했다.

첫 번째 조회의 경우, Java는 이미 Unicode(엄밀히 말하면 J2SE 5, 6Unicode 4.0을 사용함)를 사용하기 때문에 아무런 처리를 해주지않고 JDBC 설정만으로 해결이 가능하다.

참고: http://ko.wikipedia.org/wiki/유니코드

     [PDF] UnicodeData Types in Sybase® Adaptive Server® Enterprise 12.5

(http://www.sybase.com/content/1013476/4073UNI-chorwpaperv3.pdf)

두 번째 생성 및 변경의 경우, Sybase 아키텍처에는 문제가 없다고설명이 되어 있다. , 하나의 Charset이라면 위의 JDBC 설정만으로 간단하게 해결이 된다. 그런데 DB CharsetISO1 로 되어 있고 특정 컬럼만 Unicode로 되어있다면 Sybase JDBC 드라이버는 문자열을 Unicode-> ISO1로 변환을 하며 Unicode 컬럼에 맞지 않는 Charset이므로 깨져서 들어가게 된다. 문제는 이렇게 깨진 글자를읽어 들일 때 다시 eucksc로 변환을 한다는 것이다.

좀 복잡하게 설명을 했으나 어쨌든 기본적인 방법으론 이를 해결할 수 없다는 결론을 내렸다. 물론 JDBC Charset을지정하지 않고 순수하게 변환된 값을 넣어 줄 수도 있으나 개발자들이 처리해 줘야 할 것이 많아지고 유지보수 시점에도 어렵게 될 것이다.


해결방안:

이 문제를 해결하기 위해서는 iBatis 프레임워크가 Java Type, Jdbc type, Sql Type을 어떻게 처리하는지 이해해야만 한다. iBatis TypeHandler 라른 것을 이용하여 이 문제를해결하고 있다. 그런데 특정 DBMS의 경우 JDBC 표준을 따르지 않아서 프레임워크에서 처리하기 어려운 데이터 타입들이 존재한다. 예를 들면 Oracle LONG이나 CLOB, BLOB등은 표준을 따르지 않기로 유명하고 이를 처리하기 위한 다양한 방법이고안되었다. 현재 이 부분이 해결되었는지는 모를 일이다.

Sybase의 경우 UNICHAR,UNIVARCHAR, UNITEXT 등은 SQL type에서 조차 보이지 않는 듯 하다. 그러므로 JDBC 차원에서 해결하기 어렵다고 본다. 그래서 위의 Type TypeHandler를 확장한 CustomTypeHandler를 이용하게 되었고CustomTypeHandler에서 호출하는 TypeHandlerCallback 인터페이스를구현하게 되었다. 아래는 현재 구현된 모델을 보여준다.


위의 핸들러들을 이용하는 방법은 다음과 같으며 RI(ReferenceImplement: 참조구현)에서 소스코드를 확인 할 수 있다.

RiCommonEntity컴포넌트에서 /RiCommonEntity/src/main/resources/com/kyobobook/kflow/common/logic/dao/unicode-data-sqlmap-config.xml파일내용을 보면 다음과 같다.

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

<!DOCTYPE sqlMapConfig PUBLIC"-//ibatis.apache.org//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <settings cacheModelsEnabled="true"enhancementEnabled="true" lazyLoadingEnabled="true"useStatementNamespaces="true"/>

  <typeHandler javaType="java.lang.String"jdbcType="UNICHAR" callback="com.kyobobook.kflow.bizcommon.utility.dao.UnicharTypeHandlerCallback"/>

  <typeHandler javaType="java.lang.String" jdbcType="UNIVARCHAR" callback="com.kyobobook.kflow.bizcommon.utility.dao.UnivarcharTypeHandlerCallback"/>

  <typeHandler javaType="java.lang.String" jdbcType="UNITEXT" callback="com.kyobobook.kflow.bizcommon.utility.dao.UnitextTypeHandlerCallback"/>

  <sqlMap resource="com/kyobobook/kflow/common/logic/dao/sqlmap/RI_UnicodeData.xml"/>

</sqlMapConfig>

이제 UNICHAR, UNIVARCHAR, UNITEXT 타입을 처리할수 있는 준비가 되었으며 실제 SqlMap은다음과 같다.

...

<parameterMap id="insert-UnicodeData-param"class="UnicodeData">

  <parameter property="authorCode" jdbcType="CHAR" />

  <parameter property="authorName" jdbcType="VARCHAR" />

  <parameter property="authorNameUni" jdbcType="UNIVARCHAR" />

  <parameter property="authorEnglishName" jdbcType="VARCHAR" nullValue="NO_ENTRY"/>

  <parameter property="authorAnotherName" jdbcType="VARCHAR" nullValue="NO_ENTRY"/>

  <parameter property="authorAnotherNameUni" jdbcType="UNIVARCHAR"nullValue="NO_ENTRY" />

</parameterMap>

<insert id="registerUnicodeData"parameterMap="insert-UnicodeData-param">

insert intoIDPL..TM_STC_AUTR_UNI_TEST (

  autr_code

 ,autr_name

 ,autr_name_uni

 ,autr_ensn_name

 ,autr_atnm_name

 ,autr_atnm_name_uni

 

 ,autr_dvcd

 ,phtg_ysno

 

 ,use_ysno

 ,rgst_dttm

 ,rgsr_emnm

 ,amnd_dttm

 ,amnr_emnm

)

values (

  ?,?,?

 ,?,?,?

 ,'1'

 ,'Y'

 ,'Y'

 ,getDate()

 ,'1'

 ,getDate()

 ,'1'

)

</insert>

위와 같이 단지 parameterMap을 선언하고 jdbcType을 선언하는 것으로 Unicode가 처리된다. 여기서 주의할 내용은 nullValue="NO_ENTRY" 속성에 대한 이해인데 Nullable 한 컬럼에 대해서 실제 값이 Null인 경우 널을 허용하겠다는 표시를 해야 하며 “NO_ENTRY”가그런 의미로 사용된다.

이상으로 애플리케이션에서 Sybase Unicode Column 검증및 적용방안에 대한 설명을 마친다.

참고: http://imhotk.tistory.com/m/801<- Java에서 문자열과 Charset을 어떻게 다루는지 핵심사항을 쉽게 설명하고있다.

첨부:


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License
Spring 2.5.6 + 2.3.4.726 + Sybase ASE 15.5  환경에서 아래와 같은 에러가 발생했다면 데이터에 null이 들어있고 해당 값에 대한 적절한 JDBC Type을 찾지 못해서 발생하는 예외이다.

Caused by: com.sybase.jdbc3.jdbc.SybSQLException: A wrong datastream has been sent to the server. The server was expecting token 32 but got the token 33. This is an internal error.

at com.sybase.jdbc3.tds.Tds.a(Unknown Source)
at com.sybase.jdbc3.tds.Tds.nextResult(Unknown Source)
at com.sybase.jdbc3.jdbc.ResultGetter.nextResult(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.nextResult(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.nextResult(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.queryLoop(Unknown Source)
at com.sybase.jdbc3.jdbc.SybStatement.executeQuery(Unknown Source)
at com.sybase.jdbc3.jdbc.SybPreparedStatement.executeQuery(Unknown Source)
at com.sybase.jdbc3.jdbc.SybDatabaseMetaData.a(Unknown Source)
at com.sybase.jdbc3.jdbc.SybDatabaseMetaData.getDatabaseProductName(Unknown Source)
at org.apache.commons.dbcp.DelegatingDatabaseMetaData.getDatabaseProductName(DelegatingDatabaseMetaData.java:259)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.jdbc.support.JdbcUtils$1.processMetaData(JdbcUtils.java:325)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:290)
... 34 more

이 문제를 해결하기 위해서는 다음과 같이 해당 타입에 대한 jdbcType 과 nullValue="NO_ENTRY"와 같이 NULL을 허용하겠다는 것을 명시해야만 한다.

<parameterMap id="UnicodeData-param" class="UnicodeData">
  <parameter property="authorCode" jdbcType="CHAR" />
  <parameter property="authorName" jdbcType="VARCHAR" />
  <parameter property="authorNameUni" jdbcType="UNIVARCHAR" />
  <parameter property="authorEnglishName" jdbcType="VARCHAR" nullValue="NO_ENTRY" />
  <parameter property="authorAnotherName" jdbcType="VARCHAR" nullValue="NO_ENTRY" />
  <parameter property="authorAnotherNameUni" jdbcType="UNIVARCHAR" nullValue="NO_ENTRY" />
</parameterMap>


저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

스프링에서 Multi DataSource 사용

2010/12/14 14:31 | Posted by 포데브(엄지사랑) 엄지사랑
Spring-2.5.6 에서 여러개의 DataSource를 사용하는 방법을 소개한다.

다음과 같이 두개의 데이터 소스가 선언되어 있을 때 자동 주입(Inject)하고자 한다면 
<context:component-scan base-package="com.kyobobook.kflow" />

  <!-- ===================================================================== -->
  <!-- Transaction Configuration                                             -->
  <!-- ===================================================================== -->
  <aop:config proxy-target-class="true" />

  <bean id="riUniTestDataSource"  class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <qualifier value="riUniTestDataSource" />
    <property name="driverClassName" value="com.sybase.jdbc3.jdbc.SybDriver" />
    <property name="url" value="jdbc:sybase:Tds:192.168.0.15:3000" />
    <property name="connectionProperties" value="charset=eucksc;" />
    <property name="username" value="dev_kf" />
    <property name="password" value="dev_kf" />
  </bean>

  <bean id="riDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <qualifier value="riDataSource" />
    <property name="driverClassName" value="com.sybase.jdbc3.jdbc.SybDriver" />
    <property name="url" value="jdbc:sybase:Tds:192.168.0.6:3000/biltis" />
    <property name="connectionProperties" value="charset=eucksc;" />
    <property name="username" value="dev_kb" />
    <property name="password" value="dev_kb" />
  </bean>

첫번째 @Resource annotation을 사용할 수 있다.
    @Resource(name = "riDataSource")
    public void setDataSource(DataSource dataSource) {
        super.buildSqlMapClient(dataSource);
    }

두번째 방법은 @Autowired와 @Qualifier 를 사용하는 방법이다.
    @Autowired
    public void setDataSource(@Qualifier("riDataSource") DataSource dataSource) {
        super.buildSqlMapClient(dataSource);
    }

위 두가지 방법의 차이점은 DI(Dependency Injection)를 어떻게 할 것인가이다. 다음은 Anyframe에서 설명하는 Dependency Injection 에 대한 내용이다.(설명이 잘되어 있어서 퍼왔으나 라이센스가 문제가 된다면 링크로 변경할 것입니다.)

특정 Bean의 기능 수행을 위해 다른 Bean을 참조해야 하는 경우 사용하는 Annotation으로는 @Autowired 또는 @Resource가 있다.
  • @Autowired

  • Spring Framework에서 지원하는 Dependency 정의 용도의 Annotation으로, Spring Framework에 종속적이긴 하지만 정밀한 Dependency Injection이 필요한 경우에 유용하다.

  • @Resource

  • JSR-250 표준 Annotation으로 Spring Framework 2.5.* 부터 지원 가능한 Annotation이다. Annotation 사용으로 인해 특정 Framework에 종속적인 어플리케이션을 구성하지 않기 위해서는 @Resource를 사용할 것을 권장한다. @Resource를 사용하기 위해서는 클래스패스 내에 jsr250-api.jar 파일이 추가되어야 함에 유의해야 한다.
다음은 @Resource를 사용한 예이다.
@Service
public UserServiceImpl implements UserService {
    @Resource
    private UserDAO userDAO;
}

@Autowired와 @Resource를 사용할 수 있는 위치는 다음과 같이 약간의 차이가 있으므로 필요에 따라 적절히 사용하면 된다.
  • @Autowired : 필드, 생성자, 입력파라미터가 여러개인 메소드(@Qualifier는 메소드의 파라미터)에 적용 가능
  • @Resource : 필드, 입력 파라미터가 한 개인 빈 프로퍼티 setter 메소드에 적용가능
@Autowired나 @Resource를 필드에 직접 정의하는 경우 별도 setter 메소드는 정의하지 않아도 된다.


Type-driven Injection

@Autowired는 기본적으로 type-driven injection 이다. 타입으로 참조할 빈을 찾았을 때 같은 타입의 빈이 여러 개 검색되었을 경우, @Qualifier annotation을 사용하여 구분할 수 있도록 해준다. 

다음은 @Qualifier를 사용한 예이다.
@Service
public ProductService {
    @Autowired
    @Qualifier("electronics")
    private ProductCategory productCategory;
}
Qualifier를 정의하는 방법에는 다음과 같이 두가지가 있다.
  • XML을 사용한 정의
  • <bean class="anyframe.sample.springmvc.annotation.web.
    SimpleProductCategory">
        <qualifier value="electronics"/>
        <!-- inject any dependencies required by this bean -->
    </bean>
    
    <bean class="anyframe.sample.springmvc.annotation.web.
    SimpleProductCategory">
        <qualifier value="cosmetics"/>
        <!-- inject any dependencies required by this bean -->
    </bean>
    		
  • Annotation을 사용한 정의
  • @Component
    @Qualifier("electronics")
    public class ElectronicsProductCategory implements ProductCategory {
    	//...
    }

기본적으로 @Autowired가 적용된 프로퍼티는 필수이기 때문에 반드시 해당 빈이 존재해야 하지만, required 속성을 false로 설정하는 경우에는 해당되는 Bean을 찾지 못하더라도 에러가 발생하지 않는다.
@Service
public UserService implements UserService {
    @Autowired(required=false)
    private UserDAO userDAO;
}

Naming Auto Wired Dependencies

@Resource annotation은 다음과 같은 경우에 사용한다.
  • Bean name으로 Dependency Injection을 하고자 하는 경우
  • Type-driven injection을 할 수 없는 Collection이나 Map 타입의 빈
@Resource를 사용하는 경우 참조되는 Bean은 변수명을 Bean Name으로 하여 Spring 컨테이너에 의해 자동으로 인지되는데, 변수명을 이용하여 참조 관계에 놓인 Bean을 찾았는데 해당 Bean이 없는 경우에는 클래스 타입을 이용하게 된다. 참조 관계에 놓인 Bean의 Name을 직접 명시하고자 하는 경우에는 다음과 같이 'name' 속성을 부여할 수 있다.
@Service
public UserServiceImpl implements UserService {
    @Resource (name="uDAO")
    private UserDAO userDAO;
}






저작자 표시
크리에이티브 커먼즈 라이선스
Creative Commons License

[Castor] null값을 갖는 객체의 속성을 XML로 변환하기(Marshaling)

2009/05/26 13:43 | Posted by 포데브(엄지사랑) 엄지사랑

"옳바른 성장과 따뜻한 나눔"

Castor에서 null값을 갖는 속성은 무시된다. 즉, XML로 변환되지 않는다.
그런데 가끔 우리는 해당 엘리먼트가 반드시 존재해야 할 때가 있다.
즉, 값이 존재하지 않는 빈 태그가 필요한 경우 어떻게 할 것인가?

Castor 1.3(castor-xml-1.3, castor-core-1.3) 사용

Castor 0.9.6 에서부터 지원하기 시작한 nillable을 이용하거나 핸들러를 만들 수 있다.
그러나 핸들러를 별도로 만들경우 모든 경우에 대한 핸들러를 만들어 줘야만 하기 때문에 현실적으로 어렵다. 그러므로 여기에서는 nillable을 이용한 방법을 알아본다.

아래와 같은 객체와 Castor맵핑파일이 있을 때

/**
 * 간단한 개인정보
 */
public class Person implements java.io.Serializable {
    /** UID */
    private static final long serialVersionUID = -1318223135327041667L;

    /** 이름 */
    private String name;
    /** 나이 */
    private int age;
    /** 주소 */
    private String address;

    /**
     * 기본생성자
     */
    public Person() {
        //
    }

    /**
     * 생성자
     * @param name 이름
     * @param age 나이
     * @param address 주소
     */
    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    // Getters and Setters

}


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.exolab.org/mapping.dtd">
<mapping>
  <class name="mypackage.Person">
    <map-to xml="Person" />
    <field name="name" type="java.lang.String" nillable="true" required="true">
      <bind-xml name="Name" node="element" />
    </field>
    <field name="age" type="int">
      <bind-xml name="Age" node="element" />
    </field>
    <field name="address" type="java.lang.String">
      <bind-xml name="Address" node="element" />
    </field>
  </class>
</mapping>


만약 Person persion = new Person(null, 0 , null); 와 같은 인스턴스를 XML로
변환하면 아래와 같다.

<?xml version="1.0" encoding="UTF-8"?>
<Person>
  <Name xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />
  <Age>0</Age>
</Person>

즉, name은 필수 요소이면서 널을 허용하므로 엘리먼트를 만들고 address는 널이므로 엘리먼트를 생성하지 않는다.

여기에서 주의할 것은 nillable 하나만 사용할 경우 required의 기본값이 false이므로 위와 같이 생성되지 않는다는 것이다. 그러므로 빈태그를 생성하기 위해서는 반드시 nillable과 required를 같이 적용해야만 한다.


 

크리에이티브 커먼즈 라이선스
Creative Commons License

윈도우 XP, Vista, Linux(Ubuntu) 에서 테스트 단계를 4단계나 거치면서 안정적이라고 생각했었다. 그러나 실제 운영 서버는  IBM 머신에 AIX / IBM JDK 1.6이었으며 이러한 테스트 환경을 초기에 구축하기어려웠다. 어느정도 문제가 있을 거란 예상은 했으나 이정도로 나를 힘들게 할줄은 몰랐다. 각종 검색사이트에서 검색을 해봐도 비슷하지만 내가 원하는 원인 분석이나 해결방법을 찾지를 못했다. 또하나 에러의 원인이 최하단의 내용을 보기보단 최상단 에러인 스트럿츠에 초점을 맞춰 해결방법을 찾으려고 했기때문에 더욱 힘들었던것 같다. 어쨌든 원인을 알았고 임시적인 해결방법을 찾았으니 나와 같은 경우를 만날 개발자를 위하여 정보를 남긴다.

-----------
실행환경
$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build pap3260sr1-20080416_01(SR1))
IBM J9 VM (build 2.4, J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20080415_18762 (JIT enabled, AOT enabled)
J9VM - 20080415_018762_bHdSMr
JIT  - r9_20080415_1520
GC   - 20080415_AA)
JCL  - 20080412_01

원인 : IBM JDK 버전과 Spring버전간 호환이 안되는 문제

spring2.5 && ibm jdk5 또는  spring2.0.8 && ibm jdk6 ==> 정상
spring2.5 && ibm jdk6  ==> NullPointerException이 발생

해결안 : 위에 언급된 정상케이스에 맞게 버전을 맞추거나 아래 Spring 2.5.5 SNAPSHOT 버전을 사용한다.

참고 : http://jira.springframework.org/browse/SPR-4788
Spring 2.5.5 snapshot 버전 :
 http://static.springframework.org/downloads/nightly/snapshot-download.php?project=SPR

증상 :

00:55:40,176 INFO  [STDOUT] [ WARN] 12:55 40 (InterceptorBuilder.java:60) InterceptorBuilder.constructInterceptorReference :
Unable to load config class com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor at interceptor -
jar:file:/usr/jboss-eap-4.3/jboss-as/server/uresortweb/deploy/UResortFoWEB.war/WEB-INF/lib/struts2-core-2.0.11.1.jar!/struts-default.xml:101:116
probably due to a missing jar, which might be fine if you never plan to use the exception interceptor

00:55:40,187 INFO  [STDOUT] [ERROR] 12:55 40 (InterceptorBuilder.java:63) InterceptorBuilder.constructInterceptorReference :
Actual exception
     Caught Exception while registering Interceptor class com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor - interceptor -
     jar:file:/usr/jboss-eap-4.3/jboss-as/server/uresortweb/deploy/UResortFoWEB.war/WEB-INF/lib/struts2-core-2.0.11.1.jar!/struts-default.xml:101:116
        at com.opensymphony.xwork2.ObjectFactory.buildInterceptor(ObjectFactory.java:206)
        at com.opensymphony.xwork2.config.providers.InterceptorBuilder.constructInterceptorReference(InterceptorBuilder.java:57)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.lookupInterceptorReference(XmlConfigurationProvider.java:905)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStack(XmlConfigurationProvider.java:743)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStacks(XmlConfigurationProvider.java:756)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptors(XmlConfigurationProvider.java:777)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:410)
        at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:239)
        at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:111)
        at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reload(DefaultConfiguration.java:152)
        at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:52)
        at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:395)
        at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:452)
        at org.apache.struts2.dispatcher.FilterDispatcher.init(FilterDispatcher.java:201)
        at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
        at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
        at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108)
        at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3720)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4358)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:732)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:553)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:59)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:297)
        at org.jboss.mx.server.RawDynamicInvoker.invoke(RawDynamicInvoker.java:164)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.apache.catalina.core.StandardContext.init(StandardContext.java:5300)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:59)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:297)
        at org.jboss.mx.server.RawDynamicInvoker.invoke(RawDynamicInvoker.java:164)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.web.tomcat.service.TomcatDeployer.performDeployInternal(TomcatDeployer.java:301)
        at org.jboss.web.tomcat.service.TomcatDeployer.performDeploy(TomcatDeployer.java:104)
        at org.jboss.web.AbstractWebDeployer.start(AbstractWebDeployer.java:375)
        at org.jboss.web.WebModule.startModule(WebModule.java:83)
        at org.jboss.web.WebModule.startService(WebModule.java:61)
        at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
        at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
        at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
        at $Proxy0.start(Unknown Source)
        at org.jboss.system.ServiceController.start(ServiceController.java:417)
        at sun.reflect.GeneratedMethodAccessor8.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
        at $Proxy41.start(Unknown Source)
        at org.jboss.web.AbstractWebContainer.start(AbstractWebContainer.java:466)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:59)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
        at org.jboss.mx.interceptor.DynamicInterceptor.invoke(DynamicInterceptor.java:97)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
        at $Proxy42.start(Unknown Source)
        at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
        at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
        at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
        at sun.reflect.GeneratedMethodAccessor46.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
        at $Proxy10.deploy(Unknown Source)
        at org.jboss.deployment.scanner.URLDeploymentScanner.deploy(URLDeploymentScanner.java:421)
        at org.jboss.deployment.scanner.URLDeploymentScanner.scan(URLDeployme
00:55:40,190 INFO  [STDOUT] ntScanner.java:634)
        at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.doScan(AbstractDeploymentScanner.java:263)
        at org.jboss.deployment.scanner.AbstractDeploymentScanner.startService(AbstractDeploymentScanner.java:336)
        at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
        at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:59)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
        at $Proxy0.start(Unknown Source)
        at org.jboss.system.ServiceController.start(ServiceController.java:417)
        at sun.reflect.GeneratedMethodAccessor8.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
        at $Proxy4.start(Unknown Source)
        at org.jboss.deployment.SARDeployer.start(SARDeployer.java:302)
        at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
        at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
        at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
        at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:766)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:59)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:39)
        at java.lang.reflect.Method.invoke(Method.java:612)
        at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
        at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
        at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
        at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
        at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
        at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
        at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
        at $Proxy5.deploy(Unknown Source)
        at org.jboss.system.server.ServerImpl.doStart(ServerImpl.java:482)
        at org.jboss.system.server.ServerImpl.start(ServerImpl.java:362)
        at org.jboss.Main.boot(Main.java:200)
        at org.jboss.Main$1.run(Main.java:508)
        at java.lang.Thread.run(Thread.java:735)

Caused by: java.lang.NullPointerException
        at org.springframework.core.GenericTypeResolver.getTypeVariableMap(GenericTypeResolver.java:144)
        at org.springframework.core.GenericTypeResolver.resolveReturnType(GenericTypeResolver.java:93)
        at org.springframework.beans.GenericTypeAwarePropertyDescriptor.getPropertyType(GenericTypeAwarePropertyDescriptor.java:57)
        at java.beans.PropertyDescriptor.setWriteMethod(Unknown Source)
        at java.beans.PropertyDescriptor.<init>(Unknown Source)
        at org.springframework.beans.GenericTypeAwarePropertyDescriptor.<init>(GenericTypeAwarePropertyDescriptor.java:47)
        at org.springframework.beans.CachedIntrospectionResults.<init>(CachedIntrospectionResults.java:274)
        at org.springframework.beans.CachedIntrospectionResults.forClass(CachedIntrospectionResults.java:143)
        at org.springframework.beans.BeanWrapperImpl.getCachedIntrospectionResults(BeanWrapperImpl.java:252)
        at org.springframework.beans.BeanWrapperImpl.getPropertyDescriptors(BeanWrapperImpl.java:259)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.unsatisfiedNonSimpleProperties(AbstractAutowireCapableBeanFactory.java:1074)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByName(AbstractAutowireCapableBeanFactory.java:993)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:945)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:325)
        at com.opensymphony.xwork2.spring.SpringObjectFactory.autoWireBean(SpringObjectFactory.java:167)
        at com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:154)
        at com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:128)
        at com.opensymphony.xwork2.ObjectFactory.buildBean(ObjectFactory.java:143)
        at com.opensymphony.xwork2.ObjectFactory.buildInterceptor(ObjectFactory.java:184)
        ... 148 more
크리에이티브 커먼즈 라이선스
Creative Commons License

mvn deploy:deploy-file에서 Return Code 401 이 발생했을 때 원인과 처리방법

2008/06/03 19:43 | Posted by 포데브(엄지사랑) 엄지사랑

아래와 같이 메이븐을 실행하고 난후 "Return Code 401"과 같은 에러가 발생했다.
에러를 처리하기위해 여러 구글링을 했지만 역시 특별한 해결책은 없어 보였다.
대부분 settings.xml에서

<servers>
  <server>
   <id>nextech-rep</id>
   <username>dev</username>
   <password>dev</password>
  </server>
 </servers>

와 같이 설정했는데 이 사용자의 권한이 없는 것이란다. 흠. 그래서 권한이 있는 유저로 바꿔도 같은 에러만 반복되었다.

아뿔싸. -DrepositoryId=centeral 와 같이 나는 repositoryId를 repositories/repository 의 id로 착각하여 centeral과 같이 준것이다.

http://www.jfrog.org/sites/artifactory/1.2/import.html
에 다음과 같은 글이 나를 구원해 줬다.

NOTE: the repositoryId my-artifactory should be a server id declared in maven settings.xml. You will get a 401 error if there is no valid username/password provided for deploying to Artifactory.

정말 이 한줄때문에 ~~~
결국 해결책은 -DrepositoryId=nextech-rep 와 같이 해주는 것이다. 물론 권한이 있는 유저이어야만 한다.

D:\uResort\workspace2\UResortFoWEB>mvn deploy:deploy-file -DgroupId=kr.seohak.uresort.WebLib -DartifactId=xFormsXmlSaxLib -Dversion=1.0 -Dpackaging=jar -Dfile=D:\uResort\workspace2\UResortFoWEB\WebContent\WEB-INF\lib\xFormsXmlSaxLib.jar -Durl=http://192.168.10.200:8081/artifactory/libs-releases -DrepositoryId=centeral -e

+ Error stacktraces are turned on.
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'deploy'.
WAGON_VERSION: 1.0-beta-2
[INFO] ----------------------------------------------------------------------------
[INFO] Building UResort FO Web
[INFO]    task-segment: [deploy:deploy-file] (aggregator-style)
[INFO] ----------------------------------------------------------------------------
[INFO] [deploy:deploy-file]
Uploading: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar
172K uploaded
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Error deploying artifact: Failed to transfer file: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar. Return code is: 401

[INFO] ------------------------------------------------------------------------
[INFO] Trace
org.apache.maven.lifecycle.LifecycleExecutionException: Error deploying artifact: Failed to transfer file: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar. Return code is: 401
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:564)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:493)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:463)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:311)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:224)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:143)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:334)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:125)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:280)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
        at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
        at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
        at org.codehaus.classworlds.Launcher.main(Launcher.java:375)
Caused by: org.apache.maven.plugin.MojoExecutionException: Error deploying artifact: Failed to transfer file: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar. Return code is: 401
        at org.apache.maven.plugin.deploy.DeployFileMojo.execute(DeployFileMojo.java:243)
        at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:443)
        at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:539)
        ... 16 more
Caused by: org.apache.maven.artifact.deployer.ArtifactDeploymentException: Error deploying artifact: Failed to transfer file: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar. Return code is: 401
        at org.apache.maven.artifact.deployer.DefaultArtifactDeployer.deploy(DefaultArtifactDeployer.java:94)
        at org.apache.maven.plugin.deploy.DeployFileMojo.execute(DeployFileMojo.java:239)
        ... 18 more
Caused by: org.apache.maven.wagon.TransferFailedException: Failed to transfer file: http://192.168.10.200:8081/artifactory/libs-releases/kr/seohak/uresort/WebLib/xFormsXmlSaxLib/1.0/xFormsXmlSaxLib-1.0.jar. Return code is: 401
        at org.apache.maven.wagon.providers.http.LightweightHttpWagon.put(LightweightHttpWagon.java:172)
        at org.apache.maven.artifact.manager.DefaultWagonManager.putRemoteFile(DefaultWagonManager.java:237)
        at org.apache.maven.artifact.manager.DefaultWagonManager.putArtifact(DefaultWagonManager.java:153)
        at org.apache.maven.artifact.deployer.DefaultArtifactDeployer.deploy(DefaultArtifactDeployer.java:80)
        ... 19 more
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Tue Jun 03 19:27:51 KST 2008
[INFO] Final Memory: 3M/6M
[INFO] ------------------------------------------------------------------------

크리에이티브 커먼즈 라이선스
Creative Commons License

acegi security 에서 예외별 처리방법

2008/05/23 10:17 | Posted by 포데브(엄지사랑) 엄지사랑

요구사항
사용자가 로그인했을때 실명인증여부를 판단하여 실명인증을 받지 않은 경우 실명인증을 받도록 한다.

문제점
로그인을 처리하는 acegi에서

        <property name="authenticationFailureUrl" value="/common/login.jsp" />

과같이 실패했을 경우 하나의 URL만이 설정된다. 원하는 방향은 실명인증에 실패했을경우 실명인증에 실패했다는 것을 알거나 별도의 URL로 이동하여 처리되도록 하고 싶은 것이다.

방법

    <bean id="authenticationProcessingFilter"
        class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
        <property name="authenticationFailureUrl" value="/common/login.jsp" />
        <property name="defaultTargetUrl" value="/" />
        <property name="filterProcessesUrl" value="/j_acegi_security_check" />
     <property name="exceptionMappings">
          <props>
            <prop key="kr.seohak.homepage.ui.common.RealNameCertificationException">/CUC/realNameCertification.jsp</prop>
          </props>
     </property>
    </bean>

위와같이 특정 Exception을 처리할수 있도록 "exceptionMappings"를 등록한다.
크리에이티브 커먼즈 라이선스
Creative Commons License
이전 1 2 다음