EFL Windows 용 설치 하기

이 글이 글을 참조하여 소스로 빌드해보려 하였으나…

이건 머… autogen 돌릴 때 에러나고, 글에서 말하는 디렉토리도 못 찾겠고…

결국 gg…

그러나 윈도용 설치 파일을 찾아서 결국 설치 성공했다ㅎㅎ

http://dev.enlightenment.fr/~doursse/NSIS/

설치할 때 디폴트로 라이브러리가 설치 안되도록 설정 되어 있다는 건 함정=_=

첨에 설치했는데 테스트고 머고 에러가 나서 헤맸는데,

뒤지다 보니 윈도에서 개발하는 동영상이 있어서 보다가 깨달았음;;;

어쨌든 테스트도 잘 도는 거 같고…

이제 EFL 함 해보까?

mysql respawning too fast, stopped 해결

얼마전 부터 MySQL이 말썽을 부리기 시작했다.
부팅후 2~3일 정도 지나고 나면 갑자기 죽어 버리는 거다.
재설치를 해보고 별 짓을 다해봐도 리부팅 말고는 방법도 없다.
재부팅 하고 나면 또 2~3일간은 괜찮고….

[904539.515940] init: mysql main process (21214) terminated with status 1
[904539.516809] init: mysql main process ended, respawning
[904540.170259] init: mysql post-start process (21215) terminated with status 1
[904540.291704] type=1400 audit(1353159124.857:55): apparmor=”STATUS” operation=”profile_replace” name=”/usr/sbin/mysqld” pid=21238 comm=”apparmor_parser”
[904540.712887] init: mysql main process (21242) terminated with status 1
[904540.713022] init: mysql respawning too fast, stopped
로그를 봐도 이런 메시지뿐…
포기하고 지내다가 도저히 안되겠어서 구글님께 문의…
역시 구글님.. /etc/mysql/my.cnf 파일에 다음 한 줄을 추가하는 것으로 간단하게 해결!


innodb_buffer_pool_size = 16M


SeeAlso :
http://askubuntu.com/questions/127264/cant-start-mysql-mysql-respawning-too-fast-stopped
7

Tomcat 7 에서 jsessionId 가 URL에 붙지 않도록 하기

Tomcat 7 + Spring 3.0 사용 중인데,

언젠가 부터 URL 뒤에 ;jsessionid= 블라블라 가 붙어있다.

첨에는 별 신경을 안 썼는데, <c:url> 태그를 사용해서 만든 URL에 이게 붙는 바람에

조금 곤란하게 되는 일이 생겼다.

그래서 찾아보니, 서버에서 session 관리하는 방법 중에 URL에 session ID를 붙여서

하는 방법을 사용하기 때문이고, session 관련 기능을 쓰면 그렇게 된단다.

그래서 없애는 방법이 없나 좀 찾아 봤는데, Spring security 쪽에서 설정을 바꾸는 방법도 있다는데,

Spring security는 아직 쓰지도 않고 있으니 이건 아닌거 같고, Tomcat 7에서 web-app 설정을 추가해서

해결이 가능하다. 다음을 web.xml 에 추가해 주면 된다.

<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>

session 관리를 cookie를 통해서 하라고 설정하는 거 같다.

Servlet 3.0 이상에서 지원하는 거라서 Tomcat 7 이상이어야 되고, 첫 부분에 다음과 같이

버전을 3.0 으로 해줘야 한다.

<web-app version=”3.0″ xmlns=”http://java.sun.com/xml/ns/javaee”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd”>

일단 해결은 됐는데, 뭔가 좀 찝찝하기도 함=_=

SeeAlso :
 * http://www.gotoquiz.com/web-coding/programming/java-programming/disable-url-session-ids-jsessionid-in-tomcat-7-glassfish-v3/

안드로이드 사용자 조작 없이 백그라운드에서 패키지 설치하기

개발 중인 앱에 자동업데이트 기능이 필요하다.
수십에서 수백대가 설치되는데다 사용자가 일일이 조작할 수는 없는 상황이기 때문에
프로그램이 알아서 파일을 다운로드 받고 패키지 설치까지 하는 기능이 필요한 상황.

하지만, 알아본 바로는 마켓의 자동 업데이트를 통하지 않는 다음에야 사용자 확인 없이
패키지를 설치하는 것은 불가능하다. OTL
보안상 문제 때문인거 같은데…

아무튼 그대로 좌절할 수는 없어서 좀더 알아보니 일반 사용자 앱은 불가능하지만
제조사의 key로 싸인된 패키지는 방법이 있는 듯하다.. 하지만 이것도 기기 제조사에서
key를 받기가 어렵기 때문에 불가능 OTL

그러나, 이 방법이 가능한 또다른 경우는 해당 앱이 system app 인 경우이다.
이건 좀 희망이 있다. 비록 루팅을 한다거나, 커스텀 펌웨어를 만든다던가 해야 하지만.=_=

세상에 간단한 일은 없다고 조건이 다 충족되더라도 걍 되는건 아닌데…
자세한건 다음 글을 참조.

간단히 요약하면, 안드로이드에서 패키지를 관리하는 PackageManager 에서 사용자 확인 따위의 과정은
건너띄어 버리고, 실제 설치를 하는 함수를 바로 불러 버리는 거다.

하지만, 이 함수와 관련 인터페이스가 외부에 공개가 되지 않는 관계로, reflection 이라는 좀 고급 기술을 써야한다.
머.. spring 이라던지 이런 류의 프레임워크에서 다 reflection을 사용하여 구현되어 있다지만,
일반 자바 개발자가 흔히 쓸만한 기술은 아니지=_=;

암튼, 다음과 같이 해서 작동하는 건 확인완료.

==

1. Android.Manifest.xml 파일을 열고, android.permission.INSTALL_PACKAGES 퍼미션을 추가한다.
해당 권한은 제조사 key로 싸인된 앱이나 시스템 앱 처럼 시스템 권한을 가진 경우 사용 가능하다.

2. Activity 에 버튼을 하나 추가 하고, 클릭 시에 패키지 설치 코드가 실행되게한다.
직접 코드를 작성해도 되고, 위 글에 있는 소스를 사용해도 된다.

ApplicationManager am = new ApplicationManager(MyActivity.this);
am.installPackage(“/mnt/sdcard/myapp_new.apk”);

3. 버전을 다르게 하여 패키지를 2개 생성한다.

4. 루팅이된 디바이스에 두 개의 패키지 파일을 복사하고, 루트 기능을 사용할 수 있는
파일 관리자 앱을 이용하여 낮은 버전의 패키지를 /system/app 으로 복사한다.

5. 파일 권한 설정 메뉴로 해당 패키지 파일의 권한을 rw-r–r– , 즉 644 로 변경 하고,
user와 group ID는 0으로 설정한다.

6. 디바이스를 재부팅하고, 해당 앱이 어플서랍에 표시되면 시스템 앱 만들기 성공.

7. 아까 만들었던 높은 버전의 패키지 파일은 설치코드에서 지정한 것과 동일한 경로에 동일한
파일명으로 바꾼다.

8. 앱을 실행하고, 버튼을 클릭하면, 잠시 후 앱이 종료된다.

9. 어플리케이션 정보 화면에 들어가서 해당 앱의 버전이 변경되었는지 확인하면 끝!

==

이걸로 한 가지 문제는 해결이 됐는데… 업데이트 후 다시 실행하게 하는게 또 문제군=_=

Android 에서 Restlet Net extension HTTP client connector 사용 시 timeout 설정

 결론부터 말하자면 라이브러리 버그랄까…

안드로이드에서는 net extension의 HTTP client connector를 사용하면
connection timeout 과 read timeout을 설정해도 적용이 안된다.

Resetlet 문서를 보면 Internal Connector의 HTTP connector는
development only 를 추천한다고 당당히 써 있기도 한데다가
서버 다운으로 접속이 안될 때 자꾸 문제를 있으켜서 Net extention의 HTTP connector를 쓰기로 했다.

안드로이드에서는 자동으로 쓸수 있게 하는게 안된다는거 같고.. 다음과 같이 해줘야 한다.

final Engine engine = Engine.getInstance();
engine.getRegisteredClients().clear();
engine.getRegisteredClients().add(new HttpClientHelper(null));

그리고, read timeout 과 connection timeout을 설정하고, ClientResource에서
해당 client를 사용하도록 설정해 준다.

final Context context = new Context();

final Series<Parameter> parameters = context.getParameters();
parameters.add(“readTimeout”, Integer.toString(READ_TIMEOUT));

final Client client = new Client(context, Protocol.HTTP);
client.setConnectTimeout(CONNECTION_TIMEOUT);

final ClientResource cr = new ClientResource(requestUrl);
cr.setNext(client);

그런데, timeout이 전혀 안먹는다=_=
설정하는 방법이 잘못됐나 싶어 온갖 삽질을 동원하며 이리저리 테스트 해도 답이 나오질 않는다..
그래서, 결국 Restlet 소스를 뒤지기 시작했다.
(라이브러리 소스나 뒤지는 신세라니… OTL)

마침내 찾아낸 부분은… org/restlet/ext/net/internal/HttpUrlConnectionCall.java 파일의

            // These properties can only be used with Java 1.5 and upper
            // releases
            int majorVersionNumber = SystemUtils.getJavaMajorVersion();
            int minorVersionNumber = SystemUtils.getJavaMinorVersion();
            if ((majorVersionNumber > 1)
                    || ((majorVersionNumber == 1) && (minorVersionNumber >= 5))) {
                this.connection.setConnectTimeout(getHelper()
                        .getConnectTimeout());
                this.connection.setReadTimeout(getHelper().getReadTimeout());
            }

JDK 버전을 체크해서 1.5 이상 일때만 timeout을 설정하도록 하는 부분이었다.
먼가 의심스러워서, 안드로이드에서 버전값을 찍어 봤다.
… 둘다 0 이 나온다..=_=
이건 내가 잘못한건지 쟤들이 안드로이드용이라면서 안드로이드 고려를 못한건지…
도저히 판단이 안서는 상황이지만, 구국의 결단을 내려 라이브러리 소스를 직접 컴파일해 쓰기로 결정;;

            this.connection.setConnectTimeout(getHelper()
                    .getConnectTimeout());
            this.connection.setReadTimeout(getHelper().getReadTimeout());

요렇게 고쳐서 해결을 봐버렸다=_=

Spring, DbUnit 을 이용한 rollback test

Spring으로 개발 중에 DbUnit을 이용해서 DAO 코드를 테스트 하고 있다.
(Spring 3.1.0, DbUnit 2.4.8 사용 중이다)

책을 보다보니 rollback 테스트라는게 있어서 적용해 봤는데 잘 안되서 삽질 좀 했다=_=

==

rollback 테스트라는 개념은 테스트를 시작하기 전에 트랜잭션을 시작해 주고,
테스트 종료 시 rollback 시켜 버리는 것이다.
마지막에 rollback을 해버리니 테스트 중에 무슨 짓을 해버려도 상관없다. 심지어 데이터를 다 날려도..
따로 테스트 DB를 사용하지 않아도 되고, 같은 DB로 여러명이 동시에 테스트를 돌려도 서로
영향을 받지 않으니 꽤 유용할 거 같아서 적용을 해보기로 했다.

트랜잭션은 @Transactional 어노테이션을 사용해서 걸어준다.
우선 컨텍스트 설정 파일에 다음을 추가해 준다.

<tx:annotation-driven />

그리고, Test 클래스에 @Transactional 을 붙여 준다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={“/z/y/x/test-context.xml”})
@Transactional
public class AppDaoTest {

그냥 요렇게만 붙여 주면, 마지막에 그냥 rollback이 된다고 한다.

트랙잭션 시작 -> @Before 매소드 실행 -> @Test 매소드 실행 -> @After 매소드 실행 -> rollback

요런 순서로 진행이 되므로, @Before가 붙은 매소드에서 데이터 초기화 등을 해주면 된다.
AOP로 트랜잭션을 쓸때는 괜찮았는데, 어노테이션으로 하니가 CGLIB가 필요해서 maven에 추가해줬다.

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>

다음으로, DbUnit 에서 Spring 에서 트랜잭션을 시작한 것과 동일한 커넥션을 사용하도록 해주는 것이 핵심인데,
여기서 문제가 발생해서 고생을 좀 했다.=_=
원래 IDatabaseTester 를 사용해서 테스트 중인데, 참고한 책이나 구글신께 물어 봐도 이거 말고 다른걸 사용한
예제가 많이 나온다. 난 그걸로 하니까 먼가 문제가 자꾸 생겨서 이걸로 테스트 중이다.
어쨌든, 중요한건 동일한 커넥션을 쓰면 되니까..

 …

@Inject
private DataSource dataSource;

private IDatabaseTester databaseTester;

@Before

public void setUp() {

final Connection conn = DataSourceUtils.getConnection(dataSource);
final DatabaseConnection dbConn = new DatabaseConnection(conn);

databaseTester = new DefaultDatabaseTester(dbConn);

databaseTester.setDataSet(getDataSet());
databaseTester.onSetup();
 }

 …

dataSource 를 inject 받은 다음에 connection을 외부에서 받아서 쓰는 DefaultDatabaseTester 객체를 만들었다.
DefaultDatabaseTester 는 커넥션을 만드는 방법은 모르고, 단지 외부에서 받은 커넥션을 사용할 뿐이다.

자.. 이제 테스트를 돌리면… 전부 실패=_=
이런..도대체 머가 문제지? 메시지를 보면 죄다 커넥션이 이미 close 됐다는 에러다.
헉.. 도저히 알 수 없는 상황;;;;

이런 저런 삽질하다가, 메시지를 자세히 살펴보니… setUp()은 정상적으로 진행되고, 그 다음에 에러가 나는거 같다.
그럼, setUp() 후에 커넥션이 닫혔다는 말인데… 도저히 이해가 안되는 상황…
DefaultDatabaseTester  를 쓰면 안되는가 싶어서 다른 것도 써보고, 이래저래 찾아 봤지만.. 미궁 속이다.

결국 log4jdbc 디버그 메시지를 찍고 DbUnit 소스까지 뒤져서 알아낸 사실은…

DefaultDatabaseTester.onSetup() 호출 마지막에 커넥션을 닫아 버린다는것=_=;;;

DefaultDatabaseTester는 AbstractDatabaseTester를 상속하고, AbstractDatabaseTester에서는
IOperationListener 를 사용해서 커넥션을 가져온 후, onSetUp() 호출 후, onTearDown() 호출 후 작업을 처리한다.
여기서 디폴트로 쓰는 리스너가 DefaultOperationListener 인데, 얘는, onSetUp(), onTearDown() 후 무조건
커넥션을 종료하도록 되어 있는 것이다;;

외부에서 커넥션을 받아쓰는 DefaultDatabaseTester 에서 이 동작을 오버라이딩 안 했다는건
좀 이해하기 어려운데.. 버그인지 먼지 모르겠지만.. 어쨌든 안되면 바꿔야지=_=
다행히(?) IOperationListener는 변경이 가능하다.

그래서, 아무것도 안하는 DummyOperationListener를 정의해 주고,

private class DummyOperationListener implements IOperationListener {
@Override
public void connectionRetrieved(IDatabaseConnection connection) {
// do nothing
}

@Override
public void operationSetUpFinished(IDatabaseConnection connection) {
// do nothing
}

@Override
public void operationTearDownFinished(IDatabaseConnection connection) {
// do nothing
}
}

IDatabaseTester 객체 생성 후, operation listener로 설정해 줬다.

 …

@Inject
private DataSource dataSource;
private IDatabaseTester databaseTester;


@Before
public void setUp() {

final Connection conn = DataSourceUtils.getConnection(dataSource);
final DatabaseConnection dbConn = new DatabaseConnection(conn);

databaseTester = new DefaultDatabaseTester(dbConn); databaseTester.setOperationListener(new DummyOperationListener());

databaseTester.setDataSet(getDataSet());
databaseTester.onSetup();
 }

 …

이제 테스트를 돌려보면… 짜잔~ 성공.

Jenkins + Sonar 사용 시 Unit test 실패

Spring MVC 어플리케이션을 위해 Jenkins를 이용해 CI 서버를 구축하고
Jenkins의 sonar 플러그인을 사용해 Sonar와 연결해 사용 중인데, sonar에서 실행하는
Unit test가 알수 없는 이유로 실패를 한다.
정확히는 sonar 에서 unit test를 위해 돌리는 cobertura 라는 놈이 문제인 듯… 한데…

java.lang.IllegalStateException: Failed to load ApplicationContext
Expecting a stackmap frame at branch target 47 in method z.y.x.controller.TestController.list(Lorg/springframework/ui/Model;)Ljava/lang/String; at offset 17
등의 에러가 발생한다. Jenkins에서 자체적으로 돌리는 Unit test는 문제가 없는걸로 봐서
Jenkins나 JUnit의 문제는 아닌 듯하고..
어째든 구글신께 열심히 물어본 결과, maven plugin 중에 surefire 라는 놈이 관련이 있는 듯하다.
maven의 pom.xml에 다음을 추가해 주고 빌드를 돌리니 문제가 없다.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12</version> <configuration> <argLine>-XX:-UseSplitVerifier</argLine> </configuration> </plugin>

Spring + Mybatis + tomcat 사용 중 “심각: Error listenerStar” 오류

아아 삽질의 연속 ㅠ.ㅜ

JDK 7, Spring 3.1, Mybatis, 3.1, tomcat 7, Ubuntu 12.04 사용 중이다.
로컬에서 Eclipse+tomcat 으로 개발 하던 어플리케이션을 서버에 배치해서 테스트 하려고 작업을 했다.
서버 설치도 다 됐고, 서버에 war 파일 올렸는데, 어플리케이션 시작이 안된다=_=
tomcat 로그에 찍히는 에러 메시지는 다음과 같이 달랑 한줄;;

2012. 6. 4 오후 11:06:18 org.apache.catalina.startup.HostConfig deployWAR
정보: Deploying web application archive /var/lib/tomcat7/webapps/app.war
2012. 6. 4 오후 11:06:20 org.apache.catalina.core.StandardContext startInternal
심각: Error listenerStart
2012. 6. 4 오후 11:06:20 org.apache.catalina.core.StandardContext startInternal
심각: Context [/app] startup failed due to previous errors
2012. 6. 4 오후 11:06:20 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc

도저히 이유를 알 수 없는 난감한 상황인데.. 구글신께 물어보니 spring 설정이 잘 못된 경우 저 에러가
날 수 있단다. 로컬에서는 잘됐는데 설정이 이상할리가.. 라고 생각했지만…
결국 설정을 하나씩 지워가며 테스트 했는데, mybatis 쪽 설정 의심되는 상황.
정확한 오류를 알 수 없어 전전긍긍하면서, 로그도 제대로 안 찍어 주는 tomcat를 원망하다 문득 깨달았다.
spring mvc template으로 프로젝트를 생성하면 log4j 설정이 console 로 로그를 출력하도록 한다는걸=_=
그래서 즉시 파일로 출력하도록 설정을 수정했다.

<?xml version=”1.0″ encoding=”UTF-8″?>

<!DOCTYPE log4j:configuration PUBLIC “-//APACHE//DTD LOG4J 1.2//EN” “log4j.dtd”>
<log4j:configuration xmlns:log4j=”http://jakarta.apache.org/log4j/”>

        <!– Appenders –>
        <appender name=”fileLog” class=”org.apache.log4j.DailyRollingFileAppender”>
                <param name=”File” value=”/var/lib/tomcat7/webapps/app/log/app.log” />
                <param name=”Append” value=”true” />
                <layout class=”org.apache.log4j.PatternLayout”>
                        <param name=”ConversionPattern” value=”%-5p: %c – %m%n” />
                </layout>
        </appender>

        <!– Application Loggers –>
        <logger name=”z.y.x”>
                <level value=”debug” />
        </logger>

        <!– 3rdparty Loggers –>
        <logger name=”org.springframework.core”>
                <level value=”debug” />
        </logger>

        <logger name=”org.springframework.beans”>
                <level value=”debug” />
        </logger>

        <logger name=”org.springframework.context”>
                <level value=”debug” />
        </logger>

        <logger name=”org.springframework.web”>
                <level value=”debug” />
        </logger>

        <!– Root Logger –>
        <root>
                <priority value=”debug” />
                <appender-ref ref=”fileLog” />
        </root>

</log4j:configuration>

엉엉.. 로그가 정말 잘 찍힌다ㅜ.ㅜ

ERROR: org.springframework.web.context.ContextLoader – Context initialization failed
org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [z.y.x.service.UserServiceImpl] for bean with name ‘userServiceImpl’ defined in file [/var/lib/tomcat7/webapps/hadpan_web/WEB-INF/classes/z/y/x/service/UserServiceImpl.class]: problem with class file or dependent class; nested exception is java.lang.UnsupportedClassVersionError: z/y/x/service/UserServiceImpl : Unsupported major.minor version 51.0 (unable to load class z.y.x.service.UserServiceImpl)
        at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1265)

음.. 예상과 달리 직접적으로 mybatis 관련된쪽은 아닌데… Unspported major.minor version 어쩌고 하는 메시지가 보인다.
또 구글신께 물어 봤지. 자바 버전 차이에 의해 발생할 수 있는 에러란다.
아.. 어플리케이션을 자바7으로 빌드했는데, tomcat7은 JRE6 에서 돌아가고 있었던 거다.

사용 중인 Ubuntu 서버의 tomcat7 실행 스크립트를 보니 다음과 같은 부분이 있다.

  • /etc/init.d/tomcat7

JDK_DIRS=”/usr/lib/jvm/default-java ${OPENJDKS} /usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-sun”

# Look for the right JVM to use
for jdir in $JDK_DIRS; do
    if [ -r “$jdir/bin/java” -a -z “${JAVA_HOME}” ]; then
        JAVA_HOME=”$jdir”
    fi
done
export JAVA_HOME

/usr/lib/jvm/default-java 라는 디렉토리가 있으면 젤 먼저 거기를 JAVA_HOME으로 지정하게 되어있다.
해당 파일을 확인해 보니 역시나 버전이 6이다.

$ ls -l default-java
lrwxrwxrwx 1 root root 23  6월  4 23:10 default-java -> java-1.6.0-openjdk-i386

버전 7를 사용하도록 심볼릭 링크를 바꿔줬다.

$ rm default-java
$ ln -s java-1.7.0-openjdk-i386 default-java

그리고 tomcat 재실행.

$ service tomcat7 restart

멀쩡하게 실행이 되는 구나 ㅜ.ㅠ

Spring 에서 Transaction 설정 시 Service 레벨에서 적용 안되는 문제

요즘 뒤늦게 spring을 쓴다고 삽질에 여념이 없다=_=
어제는 Transaction 설정을 추가했는데, 이럴수가 적용이 안되는 것이다;;;
STS에서 transaction 표시도 잘 되고, 설정은 몇 번이나 검토해도 틀린게 없는데 말이다.

maven을 위해 pom.xml에 다음과 같이 추가해 주고

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>

다음과 같이 spring 에 data source, transaction manager 빈을 추가하고,
service 클래스에서 transaction 이 사용하도록 설정을 했다.

<!– data source –>
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>
<property name=”driverClassName” value=”net.sf.log4jdbc.DriverSpy” />
<property name=”url” value=”jdbc:log4jdbc:postgresql://192.168.0.12:5432/db” />
<property name=”username” value=”user” />
<property name=”password” value=”passwd” />
<property name=”initialSize” value=”3″ />
<property name=”maxActive” value=”10″ />
<property name=”maxWait” value=”3000″ />
</bean>

<!– transaction manager –>
<bean id=”transactionManager”
class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource” ref=”dataSource” />
</bean>

<!–  transaction setting –>
<tx:advice id=”txAdvice” transaction-manager=”transactionManager”>
<tx:attributes>
<tx:method name=”get*” read-only=”true” />
<tx:method name=”list*” read-only=”true” />
<tx:method name=”find*” read-only=”true” />
<tx:method name=”*” />
</tx:attributes>
</tx:advice>

<aop:config>
<aop:advisor advice-ref=”txAdvice”
                                     
pointcut=”execution(* com.acroem.hadpan.service.*Service.*(..))” />
</aop:config>

그리고, MyBatis와 연동해서 쓰는지라 다음과 같이 MyBatis 설정도 추가했다.

<bean id=”sqlSessionFactory” class=”org.mybatis.spring.SqlSessionFactoryBean”>
<property name=”dataSource” ref=”dataSource” />
<property name=”typeAliasesPackage” value=”z.y.x.bean” />
</bean>

<bean id=”sqlSession” class=”org.mybatis.spring.SqlSessionTemplate”>
<constructor-arg ref=”sqlSessionFactory” />
</bean>

<bean class=”org.mybatis.spring.mapper.MapperScannerConfigurer”>
<property name=”basePackage” value=”z.y.x.dao” />
</bean>

그러나 당최가 transaction이 동작을 하지 않는다=_= service 쪽의 매소드에 일부러 성공하는 SQL과 실패하는 SQL을
연속으로 실행 했는데, rollback 되지 않고 첫 번째 결과가 무조건 commit 이 되는 것이다;;
이래저래 설정을 바꿔보고, 이것 저것 실험을 해봐서 얻은 결론은 DAO 레벨에서는 transaction이 작동하는데,
service 레벨에서는 안한다는것.
삽질 끝에 service 클래스에서 @Service 어노테이션을 제거하고, 설정 파일에 bean 설정으로 추가 했더니..
동작한다! 먼가 해결의 실마리가 보이는 듯하지만 도대체가 이유를 알 수 없는 상황…-_-

다시 이래저래 설정을 바꿔가면서 실험해보고, 관련 글들을 찾아서 읽어 봤는데…
결론은 component scan의 과용과 spring context 설정에 대한 무지로 인한 설정 오류… 랄까..-_-a

STS에서 Spring MVC Template 프로젝트를 사용하여 프로젝트를 생성했는데, 이렇게 하면
기본적으로 계층 구조를 갖는 두 개의 context가 생성된다.
root context
 |- servlet context

그리고, root context의 설정 파일은 /WEB-INF/spring/root-context.xml 에,
servlet context 의 설정파일은 /WEB-INF/spring/appServlet/servlet-context.xml 에 저장된다.

참고로, root context의 빈은 servlet context 에서 참조 가능하나, 그 반대는 안되고,
root context와 servlet context에 동일한 빈이 있으면, root context의 빈은 무시될 수 있다고 한다.

여기서 servlet context 설정 파일에 <context:component-scan basePackage=”z.y.x” /> 를 넣은 것이 화근.
위의 data source, transaction, mybatis 관련 설정은 모두 root context의 설정에 추가 되어 있으며,

root context 설정 파일에도
<context:component-scan basePackage=”z.y.x” /> 가 추가되어있다.

여기서 문제는 AOP 설정은 다른 context에는 영향을 미칠 수 없다는 것과
root context와 servlet context에 동일한 빈이 있으면, root context의 빈은 무시될 수 있다는 것.

servlet context에서  <context:component-scan basePackage=”z.y.x” /> 을 해버렸기 때문에,

@Component, @Control, @Service, @Repository 가 붙은 모든 빈은 root context에서 무시될 가능성이 높다.
거기다 transaction 경계를 설정 하는 AOP 설정이 root context에 있으니…
root context 설정에서 component scan 했다고 하더라도 모조리 무시되니 root context 내에서는 AOP 설정이 안되고,
AOP 설정이 servlet context에는 적용되지 않으니, 결국 어디에도 transaction 설정이 되지 않는 것이지=_=

DAO 같은 경우에는 root context에 MyBatis 설정이 있으니, component scan에는 걸리지 않고
root context의 빈으로 등록되어 transaction이 잘 적용됐던 것이지. 덴장 OTL
망할놈의 STS는 context 간의 관계를 알리가 없으니 설정에 있으면 transaction 표시를 해줬던 것이고;

머.. 암튼 root context 설정에서는 요렇게,

<context:component-scan basePackage=”z.y.x.service” />

servlet context 설정에서는 요렇게,

<context:component-scan basePackage=”z.y.x.controller” />

해주는 것으로 모든 문제 해결!

git gc 실행 시 fatal: Out of memory, malloc failed 에러

git gc를 하다보니 난데없는 Out of memory 에러가 났다.

git 에서 메모리를 과하게 쓰는건지….

어쨌든 이 문제는 repack 명령을 사용하여 임시적으로 해결이 가능하다.

git repack -adf –window=2

window 갯수가 디폴트가 10 라고 하는거 같은데, –window 옵션을 숫자를 에러가 안 날때까지

적당히 줄여 주면 된다.

그리고 다시 git gc를 하면 문제없이 수행이 된다.

그런데 gc –aggressive 를 할 경우에는 또 해당 에러를 만날 수도 있다.

좀 난감했는데, config 를 통해 window 메모리 크기를 설정할 수 있다.

git config pack.windowMemory 128m

이 값 역시 에러가 안날 때 까지 적당히 줄여 주면 된다.

써보지는 않았지만 다음 config 도 같이 사용하면 문제 해결에 도움이 되는거 같다.

git config pack.packSizeLimit 20m