[Mavericks] ipfw, pf를 이용하여 톰켓 포트포워딩 안될때 해결법

Published on: 2014. 4. 9. 15:12 by louis.dev

맥에서 이클립스를 사용하여 웹개발을 할때 기본적으로는 80포트를 사용할 수 없습니다. 그래서 톰켓으로 띄운 웹페이지에 접속할때 항상 8080같은 포트번호를 입력해 주어야 하는데, 매번 작업할때마다 포트번호를 적어주는게 너무 불편해서 톰켓에서 80포트를 사용하는 방법을 찾아 보았습니다.


인터넷에 찾아보면 ipfw, pf를 이용해서 포트포워딩을 하는 방법이 있는데, 이 방법으로 설정했을때 포트포워딩이 설정이 안되는 경우는 아래처럼 추가 설정을 해주면 됩니다.


재부팅시 자동 시작하기

$ sudo vi /Library/LaunchDaemons/enable-fw.plist

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

<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd >

<plist version="1.0">

<dict>

        <key>Label</key>

        <string>enable-fw</string>

        <key>Program</key>

<string>/usr/sbin/sysctl</string>

<key>ProgramArguments</key>

        <array>

<string>/usr/sbin/sysctl</string>

<string>-w</string>

<string>net.inet.ip.fw.enable=1</string>

</array>

        <key>RunAtLoad</key>

        <true/>

</dict>

</plist>

$ sudo launchctl load -w /Library/LaunchDaemons/enable-fw.plist

이렇게 하면 재부팅 시에도 포트포워딩이 정상적으로 동작을 하게 됩니다.








Windows 8 IIS에서 "모듈 DLL C:\Windows\System32\inetsrv\modrqflt.dll을(를) 로드하지 못했습니다. 데이터는 오류입니다" 에러 발생시

Published on: 2014. 1. 4. 01:32 by louis.dev

이벤트 뷰어에서

"모듈 DLL C:\Windows\System32\inetsrv\modrqflt.dll을(를) 로드하지 못했습니다. 데이터는 오류입니다."

라는 에러가 발생하면서 IIS 웹서버가 실행이 되지 않을때 해결방법은 아주 간단합니다.


1. 제어판 -> 프로그램 및 기능 -> 좌측에 Windows 기능 켜기/끄기 를 실행합니다.

2. 인터넷 정보 서비스 -> World Wide Web 서비스 -> 보안 -> 요청 필터링 항목을 체크하여 설치해줍니다.

3. 재부팅


재부팅 후 http://localhost 를 입력하면 웹서버가 제대로 동작하는지를 확인할 수 있습니다.


[iBatis] queryWithRowHandler 메소드를 사용한 RowHandler사용하기

Published on: 2013. 12. 18. 15:15 by louis.dev

iBatis는 DB쿼리문의 결과를 Java Object로 매핑시켜주는 Persistent Layer의 Framework로서 DB쿼리로 검색된 결과를 다양한 자바 오브젝트( Custom Object, List, Map 등)로 생성, 매핑 시켜주어 DB 쿼리 결과를 자바단에서 쉽게 사용할수 있도록 해줍니다.


그러나 수행한 쿼리의 Row수가 대량일 경우 iBatis는 문제를 일으키게 됩니다.


예를 들어 특정 쿼리로 검색된 row의 수가 천만건이 된다고 하면, iBatis는 해당 쿼리 결과를 자바 오브젝트에 매핑 시키기 위해 사이즈가 천만인 ArrayList 인스턴스를 생성하게 될것입니다. 그렇게 대량의 자바 인스턴스를 생성하게 되면 JVM에서 사용하는 메모리사이즈를 초과하게 되어 결국 Out of Memory Exception를 뿜으며 시스템이 뻗어버리게 됩니다.


위와 같이 대량의 데이터를 셀렉트 해오는 경우에는 RowHandler를 사용하여 Out Of Memory Exception을 피해갈수 있습니다.


RowHandler를 생성하는 방법은 com.ibatis.sqlmap.client.event.RowHandler 인터페이스를 impliments 하면 됩니다.

public class TestRowHandlerCallback implements RowHandler {
	@Override
	public void handleRow(Object arg0) {
		TestClass class = (TestClass) arg0;
		//TODO select된 row 하나하나가 Java Object로 생성되어 넘어온다.
	}
}

이렇게 만들어진 RowHandler는 SqlMapClient를 사용할때 queryWithRowHandler라는 메소드를 사용하여 RowHandler를 사용하도록 지정하면 됩니다.

TestRowHandlerCallback callback = new TestRowHandlerCallback();
//getSqlMapClientTemplate().queryWithRowHandler("Test.rowHandlerTestQuery", callback);		//스프링 사용시
getSqlMapClient().queryWithRowHandler("Test.rowHandlerTestQuery", callback);

이렇게 queryWithRowHandler 메소드로 RowHandler를 지정하게 되면 iBatis는 List 인스턴스를 생성하지 않고 Row당 하나의 자바 오브젝트를 생성한 후 RowHandler의 handleRow 메소드를 실행시킵니다. 


이렇게 되면 아무리 많은 row가 검색되었다고 하더라도 List Object를 생성하지 않기 때문에 Out Of Memory Exception이 발생하지 않게 되어 안전하게 개발할 수 있습니다.






[Oracle 11g] group by로 그룹핑한 row들의 문자열 합치기(concat)

Published on: 2013. 12. 18. 13:23 by louis.dev

Oracle 11g에 LISTAGG라는 function이 추가되었습니다. 이 function은 group by로 그룹핑된 문자열 row들을 하나의 컬럼으로 결합시키는 역할을 하게 됩니다. 간단하게 예를 들어보도록 하겠습니다.



 DEPTNO

 NAME

 1

 김태희

 1

 전지현

 2

 성나정

 3

 고아라 


위의 데이터에서 부서번호(DEPTNO)가 1인 사원들의 이름을 한번에 뽑고 싶을 경우에는 아래와 같은 쿼리를 사용하면 됩니다.

SELECT
	deptno, LISTAGG(name, ',') within group (order by name) name
FROM
	test_tb
where deptno = 1
group by deptno;

LISTAGG(결합시킬 컬럼, ROW 사이의 결합 문자) within group (해당 그룹 사이의 정렬조건)

으로 간단하게 사용할 수 있습니다


위 쿼리를 실행하면 결과값은 아래처럼 나오게 됩니다.


DEPTNO 

NAME 

김태희, 전지현 



[Redis] 샤드를 지원하는 SharedJedisTemplate 만들기

Published on: 2013. 12. 9. 18:38 by louis.dev

spring-data-redis에서 제공해주는 RedisTemplate을 사용하면 @Cacheable 어노테이션을 사용할 수도 있고, Jedis를 이용한 Redis 사용을 쉽게 개발할수 있는 장점이 있습니다.


하지만 현재 spring-data-redis 1.1.0 버전에서 제공해 주는 RedisTemplate은 샤드를 지원해 주지 않고 있기 때문에 시스템 구성이 샤드로 되어 있는 경우 spring-data-redis의 RedisTemplate을 사용할 수가 없습니다.


그래서 샤드를 지원하는 레디스 템플릿을 만들어 보기 위해 구글링을 하던 중 중국 개발자가 만들어 놓은 ShardedJedisTemplate를 찾을수 있었고, 약간의 수정을 하여 Template 클래스를 만들었습니다.



1. RedisException

package net.krespo.redis.exception;

public class RedisException extends RuntimeException{
	private static final long serialVersionUID = 9150947297211556907L;

	public RedisException() {
		super();
	}

	public RedisException(String message, Throwable cause) {
		super(message, cause);
	}

	public RedisException(String message) {
		super(message);
	}

	public RedisException(Throwable cause) {
		super(cause);
	}

}

2. ShardedJedisPoolUtils

package net.krespo.redis.jedis.util;


import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.exceptions.JedisConnectionException;

/**
 * 레디스의 실행 및 실행결과를 리턴해주는 유틸
 * **/
public class ShardedJedisPoolUtils {
	
	/**
	 * 리턴값이 필요한 Command 실행
	 * */
	public static  T execute(ShardedJedisPool jedisPool, ShardedJedisReturnedCallback shardedJedisReturnedCallback) {
		ShardedJedis shardedJedis = null;
	    try {   
	    	shardedJedis = jedisPool.getResource();
	        T returnValue = shardedJedisReturnedCallback.doInShardedJedis(shardedJedis);
	    	return returnValue;
	    } 
	    //장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
	    catch (JedisConnectionException e) {
	    	if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
	    	return null;
	    }
	    finally{
	    	if (shardedJedis != null) {
	    		jedisPool.returnResource(shardedJedis);
	    	}
	    }
	}
	
	/**
	 * 리턴값이 필요 없는 Command 실행
	 * */
	public static void execute(ShardedJedisPool jedisPool, ShardedJedisCallback shardedJedisCallback) {
		ShardedJedis shardedJedis = null;
	    try {   
	    	shardedJedis = jedisPool.getResource();
	        shardedJedisCallback.doInShardedJedis(shardedJedis);
	    } 
	    //장애로 인해 레디스 커넥션이 맺어지지 않으면 커넥션풀에서 해당 커넥션을 제거한다.
	    catch (JedisConnectionException e) {
	    	if(shardedJedis != null) jedisPool.returnBrokenResource(shardedJedis);
	    }
	    finally{
	    	if (shardedJedis != null) {
	    		jedisPool.returnResource(shardedJedis);
	    	}
	    }
	}
}

3. ShardedJedisCallback

package net.krespo.redis.jedis;

import redis.clients.jedis.ShardedJedis;
public interface ShardedJedisCallback {
	void doInShardedJedis(ShardedJedis shardedJedis);
}

4. ShardedJedisReturnedCallback

package net.krespo.redis.jedis;

import redis.clients.jedis.ShardedJedis;

public interface ShardedJedisReturnedCallback {
	T doInShardedJedis(ShardedJedis shardedJedis);
}

5. AbstractRedisTemplate

package net.krespo.redis.template;

import net.krespo.redis.exception.RedisException;

public abstract class AbstractRedisTemplate {
	protected void handleException(RedisException e) throws RedisException {
		throw e;
	}
	
	protected RedisException wrapperException(Exception e) {
		return new RedisException(e.getMessage(), e);
	}
}

6. ShardedJedisTemplate

package net.krespo.redis.jedis;

import net.krespo.redis.exception.RedisException;
import net.krespo.redis.jedis.util.ShardedJedisPoolUtils;
import net.krespo.redis.template.AbstractRedisTemplate;
import redis.clients.jedis.ShardedJedisPool;

public class ShardedJedisTemplate extends AbstractRedisTemplate{
	protected ShardedJedisPool shardedJedisPool;
	
	public void setShardedJedisPool(ShardedJedisPool shardedJedisPool) {
		this.shardedJedisPool = shardedJedisPool;
	}
	
	
	public  T execute(ShardedJedisReturnedCallback shardedJedisReturnedCallback) throws RedisException {
		try {
			return ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisReturnedCallback);
		} catch (Exception e) {
			handleException(wrapperException(e));
			return null;		
		}
	}
	
	
	public void execute(ShardedJedisCallback shardedJedisCallback) throws RedisException {
		try {
			ShardedJedisPoolUtils.execute(shardedJedisPool, shardedJedisCallback);
		} catch (Exception e) {
			handleException(wrapperException(e));
		}
	}
}

사용법은 아래와 같이 사용하면 됩니다.

package net.krespo.redis.template.jedis;

import java.util.ArrayList;
import java.util.List;

import net.krespo.redis.jedis.ShardedJedisCallback;
import net.krespo.redis.jedis.ShardedJedisReturnedCallback;
import net.krespo.redis.jedis.ShardedJedisTemplate;

import org.junit.Assert;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

public class ShardedJedisTemplateTests {
	private JedisPoolConfig config;
	private List jedisShardInfos;
	private ShardedJedisPool pool;
	private ShardedJedisTemplate template;
	@Before
	public void init() {
		config = new JedisPoolConfig();
		jedisShardInfos = new ArrayList();
		
		JedisShardInfo shard1 = new JedisShardInfo("호스트1", 포트);
		JedisShardInfo shard2 = new JedisShardInfo("호스트2", 포트);
		shard1.setPassword("비밀번호");
		shard2.setPassword("비밀번호");
		
		jedisShardInfos.add(shard1);
		jedisShardInfos.add(shard2);
		
		pool = new ShardedJedisPool(config, jedisShardInfos);
		
		template = new ShardedJedisTemplate();
		template.setShardedJedisPool(pool);
	}
	
	@Test
	public void shardedJedisTemplateCallbackTest() {
		template.execute(new ShardedJedisCallback() {
			public void doInShardedJedis(ShardedJedis shardedJedis) {
				String status = shardedJedis.set("test:key", "testvalue");
				Assert.assertEquals("OK", status);
			}
		});
	}
	@Test
	public void shardedJedisTemplateReturnedCallbackTest() {
		String value = template.execute(new ShardedJedisReturnedCallback() {
					   		public String doInShardedJedis(ShardedJedis shardedJedis) {
								return shardedJedis.get("test:key");
							}
							
						});
		Assert.assertNotNull(value);
		Assert.assertEquals("testvalue", value);
		
	
	}
    
}