2012. 7. 18. 18:12 IT

배경 : 

1. shell script 짜는 것보다 자바 코딩이 더 쉽다. (사실은 그루비가.. )

2. 컴파일은 하기 싫다.



준비사항 : 

1. jdk가 설치되어야함 (대부분 있음)

2. groovy-all-X.X.X.jar 를 준비할것

3. groovy 문법을 모르면 java 문법이라도 알고 있어야 함. 



방법 : 

1. 대신 실행해줄 쉘을 만든다. 

touch groovy.sh

#/bin/sh

JAVA_HOME=/usr/local/java/jdk1.6.0_30

CP=/groovy/groovy-all-2.0.0.jar:.

echo $1 run

$JAVA_HOME/bin/java -classpath $CP groovy.ui.GroovyMain  $1

# 실행모드 변경

chmod 744 groovy.sh 


2. groovy example

# ls 명령을 실행한 결과를 출력해주는...  

touch hello.groovy

import java.util.*;

class HelloGroovy{

        public static void main(String[] args) {

                println args.length

                def result = "ls".execute().text;

                println result

        }

}


주의사항 :

1. 지나치게 중독되지 말 것.

2. 뭔가 안될 경우 classpath 설정을 확인할 것 


posted by smplnote
2012. 7. 18. 09:09 IT

배경 : gradle의 pmd plugin은 rule파일을 제대로 인식하지 못하고, csv 형태의 report파일 생성을 지원하지 않음.


해결책 : ant pmd task를 호출.


// apply plugin: 'pmd'


configurations {

    pmd // for code inspection

}

dependencies {

    pmd group:'pmd', name:'pmd', version:'4.2.5'  

}


task pmd << {

def ruleFilePath =  "..... /pmd-rule.xml";

ant.mkdir(dir:project.reporting.baseDir)

def reportFile = project.reporting.baseDir.toString() + "/pmd_" + new Date().format("yyyy-MM-dd") +".csv"

def excludesFiles = "*/test/**,*/sample/**,**/*Test*.java";

def includeDir = "*/src/**";

def checkDir = "../..";


ant.taskdef(name: 'pmd', classpath:configurations.pmd.asPath, 
             classname:"net.sourceforge.pmd.ant.PMDTask" );

ant.pmd( rulesetfiles: ruleFilePath,
failonerror: false,
maxRuleViolations: 9999,
shortFilenames: true){
formatter(type: 'csv', toFile:  reportFile)
fileset(dir: checkDir, includes: includeDir, excludes: excludesFiles)
};
}

기타 : 각각 프로젝트별로 pmd report를 만들고 병합하려고 했지만... 귀찮아서 통으로 돌리고 skip. 

posted by smplnote
2012. 7. 17. 19:41 IT



httpclient 를 쓰는데 POST 로 requestbody 에 데이터 전송하는 방법을 잊지않기 위해 기록함. 



import org.apache.http.*;

import org.apache.http.client.methods.*;

import org.apache.http.entity.*;

import org.apache.http.impl.client.*;

import org.apache.http.message.*;


// json string 전달을 위해 Builder를 사용. 

JsonBuilder builder = new groovy.json.JsonBuilder();

// make json object // 주의사항. 변수명을 json key 값과 같게 주면 문제가 생길 수 있음... 

builder {

id  myid

name myname

}


HttpPost method = new HttpPost("${RestUrl}/resources");

StringEntity requestEntity = new StringEntity(builder.toString() , "utf-8");

requestEntity.setContentType(new BasicHeader("Content-Type", "application/json"));

method.setEntity(requestEntity);


// header setting... 


HttpResponse response = httpclient.execute(method);

if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

   // do something...

}

posted by smplnote
2012. 7. 9. 16:03 IT

대상환경 : Linux  2.6.18-274.el5 ( RHEL release 5.7 (Tikanga) )


문제상황 : putty로 linux에 들어가보았더니  디렉토리의 색상이 파란색이어서 

검정 바탕의 putty 화면으로는 잘 보이지 않아 불편하더라.


원인 : LS_COLORS 환경변수의 디폴트 값이 파란색이라서 그렇다. 

echo $LS_COLORS 로 현재 값을 확인해 볼 수 있다. 

di=01;34


solution : LS_COLORS 의 해당 값을 변경한다. 

- 변경해야할 위치

a. /etc/DIR_COLORS.xterm ( 전역으로 변경시 )

b. ~/.dir_colors ( 내 환경만 적용시 )


#DIR 00;34  <== 기존

DIR 01;34    <== 신규



출처 자료 : http://www.bigsoft.co.uk/blog/index.php/2008/04/11/configuring-ls_colors 


posted by smplnote
2012. 7. 4. 11:19 IT

증상 : 

Spring의 SpringJUnit4ClassRunner 클래스를 이용하여 Session Scope로 정의한 Bean을 테스트하려고 할때 

아래와 같은 에러가 발생함.


java.lang.IllegalStateException : No Scope registered for scope 'session' 


solution : session scope을 처리하는 bean을 SimpleThreadScope 으로 바꿔치기하면 됨 


test용 context.xml 에 다음을 추가. 


<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="session">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>


reference : http://blog.solidcraft.eu/2011/04/how-to-test-spring-session-scoped-beans.html



posted by smplnote
2012. 5. 11. 00:54 IT

WHY?

ear or war 방식의 배포환경에서 이미지 파일 하나 또는 js파일이나 jar 하나 바뀌었을때 빨리 재배포하고 싶었음.

또는 제약사항으로 인하여 로컬에서 테스트가 어렵고 서버에서만 확인이 가능한 경우의 프로그램 디버깅, 수정

또다른 케이스로는 CI환경이 구성되어 있지만 각 모듈의 오너가 달라 임의로 전체 ear을 서버에 배포시키기 부담될때.


HOW

사전제약사항 : jeus 에 특화된 명령을 사용.

1. 갱신할 파일을 준비한다. ex) xxx-face.png 

2. ear 파일에서 war를 추출한다.

jar xvf test.ear test-web.war

3. 새로운 이미지를 war에 갱신한다.

jar uvf test-web.war images/xxx-face.png

4. 정상적 으로 갱신되었는지 확인한다.

jat tvf test-web.war | grep xxx-face.png

5. ear을 update 한다.


jar uvf test.ear test-web.war

cf) application.xml 관련 오류가 난다면 대신 zip을 쓴다

zip -u test.ear test-web.war

6. redeploy

jeusadmin ..... redeploy test


lessons Learned

jar 명령도 잘 알아두면 도움이 된다.

deploy mode에 너무 겁먹지 마라.




posted by smplnote
2012. 4. 27. 11:00 IT

WHY?

ROLLBACK 하려고 하는데 다른 곳에서 참조한 문서들로는 잘 안먹더라...


example


@TransactionConfiguration(transactionManager="txManager", defaultRollback=true) // transactionManager id나 name을 명시..

public class YourRollbackTest {

@Transactional

@Test public void testRollbackTest() throws Exception{

                // do test 
         }

}



@Test 어노테이션이 붙은 곳에서 @Transactional을 사용하면 항상 rollback 처리해주네요.. 

posted by smplnote
2012. 4. 27. 09:23 IT

WHY?

프로젝트에서 SpringMVC의 controller를 점점 복잡하게 작성하는 경향이 발생함.(서비스 로직을 웹에서 구현하는 것으로 보임.. )

테스트 코드가 있어야 안전하게 리팩토링이 가능할테니... 

springframework이 버전을 올리면서 복잡해지는 것도 있지만 이런 장점들이 계속 쌓여 나가는 것이 마음에 든다.  



example


import static org.junit.Assert.*;

import static org.springframework.test.web.ModelAndViewAssert.*;

import org.springframework.mock.web.*;

import org.springframework.web.servlet.*;

import org.springframework.web.servlet.mvc.annotation.*;

import org.springframework.context.*;

import org.codehaus.jettison.json.JSONObject;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"file:src/.../xxx.xml" })

public class TistoryTest {

@Inject  ApplicationContext applicationContext;

@Inject AnnotationMethodHandlerAdapter handlerAdapter;

@Inject DefaultAnnotationHandlerMapping handlerMapping;

MockHttpServletRequest request;
MockHttpServletResponse response;
/// MockHttpSession session; // if you need session data...
ModelAndView mav;

        // 테스트할 spring MVC controller 
         YourTestController controller;

@Before
public void setUp() throws Exception {
response = new MockHttpServletResponse();
request = new MockHttpServletRequest();
/// session = new MockHttpSession(null);
}
@After
public void tearDown() throws Exception {
/// session.invalidate();
}

        // ViewName을 반환하는 일반적인 케이스를 위한 테스트 
@Test  public void testViewNameReturnMethod () throws Exception{
// [given]
                request.setRequestURI("/tistory.do");
                request.setMethod("GET");
request.addParameter("method"," viewNameReturnMethod "); // if you using method style
request.addParameter("yourParam","yourValue"); // set parameter
                /// saveSession("MYKEY","MYVALUE");

// [when]
handleInterceptor(controller);
                handlerAdapter.handle(request, response, controller);

// [then]
assertViewName(mav, "yourViewName"); // check viewname
String attr1 = assertAndReturnModelAttributeOfType(mav,
"yourAttribute1", String.class);
assertEquals(attr1,"expected result");
}

        // ajax 통신을 할 경우 직접 ResponseBody에 출력하기 때문에 response의 내용으로 테스트를 수행한다. 
@Test public void testJsonReturnMethod() throws Exception{
// [given]
                request.setRequestURI("/tistory.do");
                request.setMethod("GET");
request.addParameter("method","jsonReturnMethod"); // if you using method style
request.addParameter("yourParam","yourValue"); // set parameter
                /// saveSession("MYKEY","MYVALUE");

// [when]
handleInterceptor(controller);
                handlerAdapter.handle(request, response, controller);

// [then]
               JSONObject json = new JSONObject(response.getContentAsString());
               String result = json.getString("your_result_json_key");
assertEquals(result,"expected json value");
}
protected void handleInterceptor(Object controller) throws Exception {
for (final HandlerInterceptor interceptor : handlerMapping.getHandler(
request).getInterceptors()) {
interceptor.preHandle(request, response, controller);
}
}
/*  protected void saveSession(String key, Object value) {
session.putValue(key, value);
request.setSession(session);
}  */
}

[주의사항]
session scoped bean을 사용할 경우 다음 에러가 발생함 : 
java.lang.IllegalStateException: No Scope registered for scope 'session'
아래 참고자료를 이용하여 해결할 것.
ref : http://blog.solidcraft.eu/2011/04/how-to-test-spring-session-scoped-beans.html

posted by smplnote
2012. 4. 25. 11:06 IT

WHY?

윈도우에서 실행되는 데몬성 프로그램 중에서 복수개의 프로세스를 띄우면 안되는 프로그램이 있어서...


HOW?

1. tasklist 명령으로 해당 프로세스가 떠있는지 확인.

2. 유무에 따라 프로세스 실행


example

@echo off

set PROCEXIST=NO

set PCNAME="blahblah.exe"

tasklist /nh /fi "Imagename eq %PCNAME%" | find /C %PCNAME% && set PROCEXIST=YES


if /I "%PROCEXIST%"=="NO" goto :EXEC


echo %PCNAME% already exist.

tasklist /v /fi "Imagename eq %PCNAME%" /fo list

echo ******* press any key to exit *******

echo.

pause >NUL

goto :EXIT


:EXEC

blahblah.exe


:EXIT


References 

http://www.computing.net/answers/programming/dos-command-for-wait-5-seconds/11192.html

tasklist : http://technet.microsoft.com/en-us/library/bb491010.aspx

posted by smplnote
2012. 4. 16. 08:54 IT

- WHY?


gradle의 멀티 플로젝트 설정 가이드를 따라가면 늘 최상위 경로에 settings.gradle 을 구성하게된다.

당연히 전체 프로젝트에 대해 계층적인 구조를 가져가는 것이 상식이다.

하지만 eclipse 관점에서만 볼때, 모든 프로젝트는 항상 같은 레벨에서 관리가 된다. 

때문에 상위 경로에서 멀티 프로젝트를 관리하는 개념을 도입할때 어떻게 해야 할지 고민하게 된다.

eclipse project 단위로 형상을 관리할 경우, 상위 경로에 있는 멀티프로젝트 설정파일은 버전관리 대상에서 제외 되어 버리기 때문이다. 


물론... gradle user guide에서 설명을 안했을 뿐이지, 멀티프로젝트 관리를 반드시 계층적으로 해야 하는 것은 아니다. 


다음과 같이 설정할 수 있다.


- project-emma : multi-project관리용 root project

   settings.gradle

   build.gradle

- project-navi : child project 1. Type : java library

   build.gradle

- project-bovary : child project 2. Type: web application. it depends on project-navi

   build.gradle


[$project-emma/settings.gradle]

// define projects

include 'navi', 'bovary'


// define sub-projects location

project(':navi').projectDir = new File(rootDir, '../project-navi')

project(':bovary').projectDir = new File(rootDir, '../project-bovary')

[$project-emma/build.gradle]
// define subproject configuration
subprojects{
// define plugins
apply plugin: 'java'
repositories {
mavenCentral()
}
// set compile encoding
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
}
[$project-navi/build.gradle]
jar {
destinationDir = file("dist"); // 별도 위치에 저장하고 싶을 경우에만 명시.
}
[$project-bovari/build.gradle]
apply plugin: 'war' // compile -> war -> assemble
dependencies {
compile project(':navi') // navi project에 대한 의존성을 명시.
 }

당연하지만, 멀티프로젝트 관리용으로 빈 프로젝트를 만들어야 할 필요는 없다. (navi의 하위 경로에 지정해도 가능하다는 말임) 앞으로도 유용하게 사용할 수 있을 듯 싶음. 


posted by smplnote