package kr.co.inger.hotwind.jersey;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import kr.co.inger.hotwind.config.AppConfig;
import kr.co.inger.hotwind.utils.ClassUtils;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
/**
* Jersey요청 처리를 위해서 web.xml 대신에 Guice 바인딩으로 HTTP요청을 JAX-RS으로 처리하도록.
*
* ServletModule을 활용하여, Guice Module들으로 Servlet Mapping을 대신함.
*
* app.jerset-modules에 지정된 클래스FQN들으로 Guice에 바인딩하여 Jersey 리소스 클래스로 활용. 이렇게 Guice에
* 바인딩한 Jersey 리소스 클래스들을 또한 Guice을 통해서 초기화되고, 이들로부터 멤버들을 주입 받으므로, 아무런 추가 코드 없이
* Guice으로 @Inject 멤버들을 활용할 수 있다.
*
* @author jhyun
* @since 2012-09-03
*
* @see ServletModule
* @see GuiceContainer
* @link <a href="http://code.google.com/p/google-guice/wiki/ServletModule">
* ServletModule</a>
*/
public class JerseyServletModule extends ServletModule {
private static Logger logger = LoggerFactory
.getLogger(JerseyServletModule.class);
@Override
protected void configureServlets() {
//
Configuration config = AppConfig.load();
//
bindResources(config);
//
final Map<String, String> jerseyProperties = loadJerseyProperties(config);
logger.debug(String.format("jersey-properties = %s", jerseyProperties));
//
final String jerseyServeUrlPattern = config.getString(
"jersey-serve-url-pattern", "/*");
filter(jerseyServeUrlPattern).through(GuiceContainer.class,
jerseyProperties);
}
/** Jersey Servlet Filter 설정 로딩. */
private Map<String, String> loadJerseyProperties(Configuration config) {
final String pFilename = config.getString("jersey-properties-file",
"jersey.properties");
Properties ps = new Properties();
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream(pFilename);
if (in != null) {
try {
ps.load(in);
} catch (IOException e) {
logger.warn(String.format("LOAD FAIL = [%s]", pFilename));
} finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
logger.warn("CLOSE FAIL, WT...", e);
}
}
} else {
logger.debug(String.format("[%s] not found, skip.", pFilename));
}
return new HashMap<String, String>((Map) ps);
}
/**
* 모든 리소스 클래스들을 등록. 실제로 모듈로서 이들을 활용하지 않고(인스턴스로 만들지도 않음.), 단지 바인딩만 하여 이후 요청에
* 있어서 처리에만 활용한다.
*
* @param resourceClassFqns
*/
private void bindResources(final Configuration config) {
//
Set<Class<?>> classesSpecified = ClassUtils.findClassesByFqns(config
.getList("app.jaxrs-resources", new ArrayList<Object>()));
//
final List<Object> rootPackages = config.getList(
"app.jaxrs-resources-root-packages", new ArrayList<Object>());
final List<Object> annotations = config.getList(
"app.jaxrs-resources-annotations", new ArrayList<Object>());
Set<Class<?>> classesFound = ClassUtils
.findClassesByPackagesAndAnnotations(rootPackages, annotations);
//
Set<Class<?>> resourceClasses = Sets.union(classesSpecified,
classesFound);
logger.debug(String.format("scanned jaxrs resources = %s",
resourceClasses));
//
for (final Class<?> klass : resourceClasses) {
try {
bind(klass);
logger.info(String.format("jersey-resource bound -- %s", klass));
} catch (Exception exc) {
logger.warn(String.format("jersey-resource fail, skip -- [%s]",
klass), exc);
}
}
}
}