이것땜에 오늘 또 하루를 날렸다.. 바쁜때에는 꼭 예상 밖의 일들이 터져서 하루를 피곤하게 만든다.

며칠 전부터, 개발서버 AIX 환경에서 매 요청 마다 Exception 이 계속 발생했는데,
대충, Struts2 의 FileUploaderInterceptor 에서 부터 시작하고, 결국에는 NoSuchFieldException 을 throw 하게 되는 콜스택을 보이는 예외이다.

사실 동작하는데 크게 문제는 없지만, 여간 신경쓰이는게 아니어서 해결하려고, Struts2 와 내부에서 사용하는 xwork2 의 소스까지 빌드해가면서 찾아낸 결론은,

AIX 에서는 IBM JDK (JDK6) 와 xwork 와의 호환성에 문제가 있어,
struts.xml 이나 properties 에서, struts.i18n.reload 와 devmode 옵션을 false 로 주어야 한다


는 것이다.

좀더 깊숙히 원인을 분석해본 결과, struts2 가 사용하는 xwork2 라이브러리에서, ResourceBundle 을 사용하는데,
Struts 의 Dispatcher 에서 사용하는 xwork 의 클래스 중에서 (LocalizedText 였나.. 기억이..) java.util.ResourceBundle 을 사용한다.

이때, xwork 의 옵션으로, 리소스를 동적으로 갱신 시에 리로드 할 수 있는 옵션을 줄 수 있는데, struts2 에서는 Dispatcher 에서 struts.i18n.reload 옵션값을 읽어, xwork 에 설정하도록 한다.
이때 reload 옵션이 true 인 경우, 위와 같은 문제가 생기는데, 옵션이 true 이면, ResourceBundle 의 claerCache() 메소드를 호출하거나 하는게 아니라, Reflection 기능을 사용하여, ResourceBundle 의 내부 HashMap, 그것도 private 로 선언된 놈(멤버변수명: cacheList) 을 setAccessible(true)를 써가면서 까지 가져와 직접 clear() 를 호출하도록 하고 있다.

여기에서 문제가 생기는데, Sun 의 JDK 의 경우, 위 map 의 변수명이 cacheList 이지만, IBM 의 JDK 의 구현 소스는 내부적으로 많이 다르고, cacheList 라는 Field 변수 자체가 없다. 그래서 오류가 나는 것이다.

이 기능을 안쓰거나, xwork 소스를 수정하는 방법이 있겠는데, 나는 회피하는 방법을 쓰려고 struts.i18n.reload 를 false 로 struts.xml 의 constant 선언으로 값을 주었지만 먹지를 않았다. 그래서 결국 xwork 와 struts 를 소스로 받아 세팅값이 먹혔는지 보기 위해 maven 으로 빌드까지 해가면서 파악 해보니, struts.i18n.reload 값에 앞서, devmode 를 false 로 해줘야 하는것을 알 수 있었다.

결국은 저렇게 세팅하나 잘못 바꿔서 하루를 날려버리는 참 어처구니 없는 일을 저지르고 말았다..
그래도 Reflection 의 강력한 기능과 Struts2 의 내부를 조금이나마 더 들여다 볼 수 있는 기회이기도 했다는데에 만족하고 있다.

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

MessageContext messageContext = MessageContext.getCurrentContext();
HttpServlet servlet = (HttpServlet)messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLET);
ServletContext servletContext = (ServletContext)servlet.getServletContext();

HttpSession session = (HttpSession)messageContext.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);

위와 같은 방식으로 가져올 수 있다
반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

오늘 아주 이놈땜에 몇시간을 삽질했는지 모르겠다.. 하루가 다 갔다.
ANT 로 컴파일 하도록 하였는데, Task 중, Javac 태스크에, 옵션 하나가 지정이 안되어서 아주 고생했다.

바로, encoding= 옵션!
encoding="utf-8" 처럼 지정해주지 않으면, 코드 내에 한글 등 다국어는 커파일 당시 OS 의 언어 설정으로 먹는 듯 하다.

하루 종일, LANG=C 인 환경에서, 필터 빼고 넣고 별 짓을 다하다가 찾아냈다..
반드시 주의하자!~ 다국어 지원 필요한 경우, .java 파일 자체 인코딩은 당연히 UTF-8 이어야 하고,
컴파일러에게도 인코딩을 지정해 주어야 한다!~
반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
Tomcat 에서는 server.xml 과 context.xml 에 리소스와 리소스 링크 추가해주면 잘 찾는데,
이상하게 Jeus 에서는 계속 네이밍 못찾는다고 나와서 요것조것 해보다 보니,

Jeus 에서는 web.xml 에 resource-ref 를 추가 안해주면 못찾는구나.. 라는 결론이 나왔다.

아래와 같이 Jeus 와 web.xml 을 모두 세팅 해줘야 하더라..

1. JEUSMain.xml 설정

  
   <resource>
      <data-source>
         <database>
            <vendor>mysql</vendor>
            <export-name>cserverdb</export-name>
            <data-source-class-name>jeus.jdbc.driver.blackbox.BlackboxConnectionPoolDataSource</data-source-class-name>
            <data-source-type>ConnectionPoolDataSource</data-source-type>
            <stmt-query-timeout>60000</stmt-query-timeout>
            <property>
               <name>DriverClassName</name>
               <type>java.lang.String</type>
               <value>com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource</value>
            </property>
            <property>
               <name>URL</name>
               <type>java.lang.String</type>
               <value>jdbc:mysql://192.168.1.X:3306/cserverdb?autoReconnect=true</value>
            </property>
            <property>
               <name>User</name>
               <type>java.lang.String</type>
               <value>XXXXXX</value>
            </property>
            <property>
               <name>Password</name>
               <type>java.lang.String</type>
               <value>XXXXXX</value>
            </property>
            <action-on-connection-leak>Warning</action-on-connection-leak>
            <connection-pool>
               <pooling>
                  <min>2</min>
                  <max>30</max>
                  <step>1</step>
                  <period>3600000</period>
               </pooling>
               <wait-free-connection>
                  <enable-wait>true</enable-wait>
               </wait-free-connection>
            </connection-pool>
         </database>
      </data-source>
   </resource>

2.WAR 의 web.xml 에 아래와 같이 추가

	
       <resource-ref>
		<description>Datasource Contents Server</description>
		<res-ref-name>cserverdv</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>

3. iBatis 의 sqlmapConfig.xml 을 아래와 같이 설정
	<transactionManager type="JDBC" >
		<dataSource type="JNDI">
			<property name="DataSource" value="cserverdb"/>
		</dataSource>
	</transactionManager>

위에서, DataSource 에, java:comp/env/cserverdb 가 아니고, 그냥 cserverdb 임에 반드시 주의하자~! 요것땜에 많이 헤맸네~?

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
이번에 Tomcat / Eclipse 에서 개발하던 환경이 Jeus 로 올라가면서 동작하지 않아 난감한 상황이었는데,
결국 사소한 문제 때문에 작동하지 못한거여서 참으로 황당하네..

struts.xml 에서, package 정의와 include 시에 아래와 같은 사항에 주의해야 하겠다.

1. namespace 에 root 를 지정할 경우 주의점

 package 의 attribute 중에, namespace 를 지정할 때에, root 요소를 지정하는 경우, namespace="/" 가 아니라
 namespace="" 로 주어야 한다.
 즉, 값 안에 / 가 있어서는 안된다.

2. include 시에 주의 점

include file="/demo/db/user-navi.xml" 과 같이 해서는 안되고,
include file="demo/db/user-navi.xml" 과 같이, 앞의 "/" 를 빼도록 한다.
아직 테스트는 안했지만, 앞에 / 가 붙으면 절대 경로로 찾는 듯 하다. 절대경로 찾을 시 root 는 system 루트가 되는 듯 함.

이상 사소한 것들이지만, 작동이 안되는 우를 범하지 말도록 하자.




반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
웹 어플리케이션에서 클래스를, Class.forName() 으로 생성하는 것은 상당히 위험한 짓이다.
이는 또한 잘 생성되지도 않고, WAS 환경 하에서 되거나 안되거나 한다.

ContextClassLoader 를 사용하는 환경에서는, 자신이 클래스를 로드하기 위해 사용해야 하는 클래스로더를 제공하는 API 를 사용하여야 한다.

public static Class getClass(String name) throws Exception{
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      Class classInstance = null;
      try {
          classInstance = classLoader.loadClass(name.trim());
      } catch (ClassNotFoundException e) {
          e.printStackTrace();
          throw e;
      }
      return classInstance;
  }
대략 위와 같이 메소드를 작성하여 사용할 수 있다.

절대 Application Server 환경에서, forName 하지 말도록~!
반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,
프로퍼티 파일을 사용해서 sqlMapConfig 에 DataSource 를 지정할 때, 공백 하나 때문에 수 시간을 낭비했다..ㅠㅠ

properties 파일애내에서
key=value 로 정의 할 때,

value 부분의 공백을 주의하자!
공백 없이 넣어야 한다!~ 이런!!!

그리고, Tomcat 에서 JNDI 리소스는 되도록 server.xml 에 Global 로 등록하고,
Context.xml 에는 ResourceLink 걸어준다.

마지막으로, web.xml 에서, resource-ref 는 없어도 된다.

META-INF/context.xml 을 넣는 것은, Gloabal 이 아니고, Context 에만 해당되도록 하는 것이나, WAR 배포하면, 패스워드도 함께 주는 것이라 보안 상 위험할 수 있다.
반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

1. Commons Logging

 

Commons Loggin API는 자카르타 Commons에 포함되어 있는 프로젝트들이 로거로 사용하는 API이다. Commons Logging API는 자체적으로 로깅 기능을 구현하고 있지는 않으며, 로깅 요청을 Log4J나 자바1.4로깅 API와 같이 이미 존재하는 로깅 API에 전달하는 다리 역할을 한다. 즉, Commons Logging API를 사용하면 Log4J를 사용하든 자바 1.4의 로깅 API를 사용하든지에 상관없이 동일한 방식으로 로깅 코드를 작성할 수 있게 된다.

 

 

Loggin API를 사용하기 위해서는 다음의 두 클래스만 사용하면 된다.

- org.apache.commons.logging.Log

- org.apache.commons.logging.LogFactory

 

 

LogFactory는 사용자의 시스템에 알맞은 Log를 생성해주는 팩토리 클래스이다.

Log는 인터페이스라서 실제로 로그를 기록하는것은 Log 인터페이스의 구현체를 통해서 연결된 Log4J나 자바1.4의 로깅 API이다.

 

(사용예)

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

 

public class IbatisWithMysqlBoardDAO extends SqlMapClientDaoSupport implements BoardDAO {

...

 

     protected final Log logger = LogFactory.getLog(getClass());

 

     public List findBoardList(int currentPage, int countPerPage) throws SQLException {

     ...

          logger.debug("로그테스트");

     ...

     }

 

...

}

 

 

LogFactory는 다음과 같은 순서로 Log구현체를 선택하게 됩니다. (다음 생략...)

Log4J 라이브러리 파일을 CLASSPATH에 추가시켜주면 LogFactory는 탐색순서에 의해 Log구현체로 Log4J를 사용한다.(2순위)

 

 

Log구현체는 로그를 기록할 때 Commons Logging API의 로그 레벨을 실제로 사용하는 로깅 API의 로그 레벨로 알맞게 매핑시켜준다.

 Commons Logging 로그레벨 Log4J의 로그레벨  자바 1.4의 로그 레벨 
 TRACE DEBUG  FINEST 
 DEBUG DEBUG  FINE 
 INFO  INFO INFO
 WARN  WARN  WARNING
 ERROR  ERROR  SEVERE
 FATAL  FATAL  SEVERE

 

 

로그레벨의 판단을 위한 메소드

boolean isTraceEnabled()

boolean isDebugEnabled()

boolean isInfoEnabled()

boolean isWarnEnabled()

boolean isErrorEnabled()

boolean isFatalEnabled()

 

 

 

 

2. Log4J

 

Lo4J의 로그레벨(내림차순)

- Level.FATAL : 치명적인 에러

- Level.ERROR : 에러

- Level.WARN : 경고

- Level.INFO : 정보

- Level.DEBUG : 상세정보

 

 

Log4J의 구조

: Log4J는 크게 Logger, Appender, Layout의 3가지 요소로 구성되어 있다.

 

 

Appender

- org.apache.log4j.ConsoleAppender : 콘솔에 로그메시지 출력

- org.apache.log4j.FileAppender : 파일에 로그 메시지를 기록

- org.apache.log4j.RollingFileAppender : 파일에 로그 메시지를 기록하며, 파일이 일정 크기가 되면 다른 이름으로 저장하고, 새롭게 로그 메시지를 기록하기 시작한다.

- org.apache.log4j.DailyRollingFileAppender : 파일에 로그 메시지를 기록하며, 하루단위로 로그파일 변경

- org.apache.log4j.net.SMTPAppender : 로그메시지를 이메일로 전송한다.

- org.apache.log4j.nt.NTEventLogAppender : NT의 이벤트 로그 시스템에 로그 메시지를 전송한다. 윈도우즈 시스템만 사용 가능

 

 

Layout

: Layout은 org.apache.log4j.PatternLayout을 일반적으로 사용한다.

 

PatternLayout에서 지원하는 패턴

1) C : 로그메시지를 기록하려는 클래스의 이름 출력! 패키지 계층 제어 가능 ex) %C{2}

2) d : 메시지 기록 시간 출력! 포멧 지정 가능! 포멧은 java.text.SimpleDateFormat과 같은 포맷 ex) %d{yyyy-MM-dd HH:mm:ss}

3) p : 로그 메시지의 우선순위 출력

4) m : 로그 메시지 자체를 출력

5) M : 로그 메시지를 기록하려는 메소드의 이름 출력

6) n : 플렛폼의 라인 구분자를 출력

7) % : %%는 '%'자체를 출력

 

 

 

Log4J 설정파일 다루기

log4j.rootLogger = [level], appender_name, ...

 

log4.logger.logger_name = [level|INHERITED], appender_name,...

log4j.additivity.logger_name = true|false

 

log4j.appender.appender_name = [appender_calss_name]

log4j.appender.appender_name.option1 = value1

log4j.appender.appender_name.option2 = value2

 

log4j.appender.appender_name.layout = [layout_calss_name]

log4j.appender.appender_name.layout.option1 = value1

log4j.appender.appender_name.layout.option2 = value2

 

 

 

Log4J 설정파일 예

 

log4j.rootLogger=WARN, FILE
log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.FILE.File=d:/dev/log/error.log
log4j.appender.FILE.Threshold=ERROR
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[%d] %-5p %l - %m%n

 

log4j.logger.com.kth.swaf.web.filter=INFO, FILTER
log4j.appender.FILTER=org.apache.log4j.ConsoleAppender
log4j.appender.FILTER.Threshold=INFO
log4j.appender.FILTER.layout=org.apache.log4j.PatternLayout
log4j.appender.FILTER.layout.ConversionPattern=%-5p - %m%n

 

log4j.logger.com.kth.swaf=WARN, SWAF
log4j.appender.SWAF=org.apache.log4j.ConsoleAppender
log4j.appender.SWAF.Threshold=WARN
log4j.appender.SWAF.layout=org.apache.log4j.PatternLayout
log4j.appender.SWAF.layout.ConversionPattern=[%d] %-5p - %m%n

 

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

web.xml 에 설정하는 방법도 있다. 이게 확실하고 깔끔한 방법이다.
하지만, WEB-INF 밑에 JSP 를 두는 방법으로도 가능하다.

단, 이때는, href 나 Form Submit 할 때, 직접 WEB-INF/abc.jsp 처럼 접근할 수 없으므로 주의해야 한다.
WEB-INF 밑의 JSP 파일 접근 하려면, Struts 의 Action 에 Mapping 하거나 하여 Framework 이 Page를 Return 하도록 하는 방법을 사용해야 한다.

이왕이면 .jsp 요청은 받아들이지 않게 하는게 좋을것이다.
반응형

'Software Development > JavaSE&EE' 카테고리의 다른 글

iBatis 에서 JNDI 설정 시 주의사항  (0) 2009.10.25
Commons Logging 과 Log4J  (0) 2009.10.16
변수명 표기법 종류  (0) 2009.10.12
OAuth - Open Source 보안인증 API  (0) 2009.09.23
RuntimeException 의 특성  (0) 2009.08.12
블로그 이미지

Good Joon

IT Professionalist Since 1999

,

Naming Rule

종류

  1. PascalCasing : 단어가 시작 때 마다 대문자를 사용
  2. camelCasing : 첫단어는 소문자. 그 다음 단어부터는 대문자를 사용
  3. Underscore : 단어 마다 '_'로 구분
  4. sHungarian : 각 변수마다 특성을 앞에 기술

세부사항

1. PascalCasing

파스칼 표기법은 단어의 시작을 모두 대문자로 사용하는것이다. ex) ThisIsAVariable

2. camelCasing

카멜은 영어로 낙타다. (-_-a) 낙타와같은 모양이라서 이렇게 이름을 지었다고하는데... 정 말일까? 첫단어의 머리는 소문자로 그외에는 모두 파스칼 표기법과 같다.
ex) thisIsAVariable

3. Underscore

Underscore는 '_' 요거다. 이것으로 단어와 단어사이를 구분한다.
ex) this_is_a_viariable
ex2) This_IS_A_Variable

4. sHungarian

헝가리안 표기법은 헝가리 출신의 Microsoft사의 개발자 Charles Simony에 의해 사용 되었으며 변수명 앞에 그 타입을 써주는 방법이다. 사용하지마라는 사람들도 많이 있다.
ex) sThisIsAVariable
ex2) sThis_is_a_variable

접두어 설명
f flag
c counter
l long
p pointer
u unsigned int

반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,