JNDI DataSource Loading for TDD

Tomcat 등의 Servlet Container를 사용하여, 웹애플리케이션을 개발할 때, DataSource를 Servlet Container의 Context 에 JNDI Resource로 bind 하여 사용하는 경우가 많다.

test case를 실행하기 위해 JNDI remote provider 를 제공하는 application server (glassfish, jboss 등)를 사용할 수도 있으나, 이러한 것은 test의 원자성을 저해하기 때문에 test 환경 자체에서 JNDI resource를 생성할 수 있는 방법을 생각해 보았다.

Sun에서 제공하는 File System Service Provider를 이용하는 것이다. 사용법은 매우 간단하다. 단순히 naming context의 initail context factory 를 com.sun.jndi.fscontext.RefFSContextFactory 로 지정하기만 하면 된다.

다음은 간단히 만들어 본 class 이다. 이 class는 context xml 파일을 읽어서 JNDI resource를 loading해 주는 역할을 한다. test를 수행하기 전에 JNDILoader.init()을 실행 해주면 다른 작업 없이 test case를 실행시킬 수 있을 것이다.

package com.fguy.test;

import java.io.File;
import java.io.IOException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class JNDILoader {
private static final Logger LOG = Logger.getLogger(JNDILoader.class);

private static final boolean initialized = false;
private static final String CONTEXT_XML = "WebContent/META-INF/context.xml";

private JNDILoader() {

}

public static final void init() throws ParserConfigurationException,
SAXException, IOException, DOMException, NamingException {

if (!initialized) {
Context context = getNamingContext();

List resourceNames = new ArrayList();
Map> references = new HashMap>();

NodeList contextResourceNodeList = getContextResourceNodeList();
for (int i = 0; i < contextResourceNodeList.getLength(); i++) {
Node item = contextResourceNodeList.item(i);
// print comment;
if (LOG.isDebugEnabled()
&& item.getNodeType() == Node.COMMENT_NODE
&& item != null) {
LOG.debug(item.getNodeValue());
}

// register to JNDI
if ("resource".equalsIgnoreCase(item.getNodeName())
&& "javax.sql.DataSource".equals(item.getAttributes()
.getNamedItem("type").getNodeValue())) {
NamedNodeMap attributes = item.getAttributes();
String name = attributes.getNamedItem("name")
.getNodeValue();
Map reference = references.get(name);

if (reference == null) {
reference = new HashMap();
}

for (int j = 0; j < attributes.getLength(); j++) {
String n = attributes.item(j).getNodeName();
String v = attributes.item(j).getNodeValue();
if (!"name".equals(n)) {
reference.put(n, v);
}
LOG.debug(attributes.item(j));
}

resourceNames.add(name);
references.put(name, reference);
}

if ("resourceparams".equalsIgnoreCase(item.getNodeName())) {
NodeList parameters = item.getChildNodes();
String name = item.getAttributes().getNamedItem("name")
.getNodeValue();
Map reference = references.get(name);

if (reference == null) {
reference = new HashMap();
}

for (int j = 0; j < parameters.getLength(); j++) {
Node paramItem = parameters.item(j);
if ("parameter".equalsIgnoreCase(paramItem
.getNodeName())) {
NodeList children = paramItem.getChildNodes();
String n = null;
String v = null;
for (int k = 0; k < children.getLength(); k++) {
Node child = children.item(k);
if ("name"
.equalsIgnoreCase(child.getNodeName())) {
n = child.getNodeValue();
} else if ("value".equalsIgnoreCase(child
.getNodeName())) {
v = child.getNodeValue();
}
LOG.debug(child);
}
reference.put(n, v);
}
}
references.put(name, reference);
}
}
for (String name : resourceNames) {
Reference reference = new Reference("javax.sql.DataSource",
"org.apache.commons.dbcp.BasicDataSourceFactory", null);
Map referenceMap = references.get(name);

for (String key : referenceMap.keySet()) {
reference
.add(new StringRefAddr(key, referenceMap.get(key)));
}

context.rebind("java:comp/env/".concat(name), reference);
}
}
}

private static final NodeList getContextResourceNodeList()
throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new File(CONTEXT_XML));
return doc.getFirstChild().getChildNodes();
}

private static final Context getNamingContext() throws NamingException {
System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
System.setProperty(Context.PROVIDER_URL, "file:///tmp");

return new InitialContext();
}
}

댓글

이 블로그의 인기 게시물

단위테스트를 위한 주민등록번호 생성

낡은 방식으로 PHP를 사용하고 있는 조직의 개발환경 개선 방안 구상

프로그래머가 되기까지...