2011년 5월 23일 월요일

The Interception Filter Pattern

2. The Interception Filter Pattern
Interception Filter 디자인 패턴은 요청을 가로채어 필터에 통과시킨 다음, 결과에 따라 요청을 반려시키거나 계속 진행하도록 한다.


Interception Filter을 J2EE 기반 기술에서 적용한 사례를 든다면 당연히 그 첫번째는 Servlet 스팩 2.3에서부터 지원하게된 Servlet Filter가 있을 것이다.
우리는 웹 애플리케이션에서 요청을 처릴 할 때 다음의 몇가지 문제에 대하여 고민하게 된다.
  • 정상적으로 확인된 클라이언트인가?
  • 클라이언트는 유효한 Session을 가지고있는가?
  • 클라이언트 IP는 신뢰할만한 네트워크로부터 왔는가?
  • Request에 신뢰를 위반할 사항이 있는가?
  • 클라이언트가 암호화된 자료를 받는다면 어떻게 지원할 것인가?
  • 클라이언트의 브라우저 유형을 지원하는가?

Interception Filter Pattern을 이용한 Servelt Filter는 위와 같은 문제점을 쉽게 해결할수 있는 방안을 제공한다.
그림에서 큰 회색박스는 웹 애플리케이션을 나타낸다. 필터들은 웹 애플리케이션에 들어오는 모든 Request, Response를 인터셉트하도록 되어 있다. 필터들은 그림에서 나타난 대로 3개의 스택 구조로 되어 있고 각각의 Request, Response는 엔드포인트에 도달하기 전에 모든 필터를 거쳐서 가야 한다. 각 필터는 Request, Response를 조작할 수도 있고, 또는 필요한 다른 어떤 일도 할 수 있다.

구조

Intercepting Filter pattern class diagram


Intercepting Filter sequence diagram


FilterManager와 FilterChain의 역할을 Servlet Filter에서는 Container가 담당한다.

역할
  • FilterManager :필터 관리자는 필터들을 순서대로 정리하고, 필터 체인에 필터 처리를 초기화 시켜 필터를 관리한다.
  • FilterChain: 필터 체인은 독립적인 필터들이 연속적으로 이루어진 구조이다.
  • FilterOne, FilterTwo, FilterThree: 특정한 목적지 또는 목표를 가진 독립적인 필터이다.
  • Target: 목표는 클라이언트가 요청한 목적지이다.

의도
클라이언트로 부터의 요청을 가로채어 필터에 통과 시킨 다음, 결과에 따라 요청을 반려하거나 계속 진행하도록 한다.

결론
  • 느슨하게 결합한 다루개와 통제를 집권한다.
  • 재사용 가능성을 개량한다.
  • 선언하고는 가동가능한 윤곽.
  • 정보 공유는 비능률적이다.(필터들간의 느슨한 결합으로 인하여 정보 공유는 비능률적이다.)

예제소스


BaseEncodeFilter.java
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class BaseEncodeFilter implements Filter {
private javax.servlet.FilterConfig myFilterConfig;
public BaseEncodeFilter() { }
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
filterChain.doFilter(servletRequest,
servletResponse);
}
public FilterConfig getFilterConfig() {
return myFilterConfig;
}
public void setFilterConfig(FilterConfig filterConfig) {
myFilterConfig = filterConfig;
}
public void init(FilterConfig filterConfig)
throws ServletException {
myFilterConfig = filterConfig;
}
public void destroy() {
myFilterConfig = null;
}
}


StandardEncodeFilter.java
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class StandardEncodeFilter extends BaseEncodeFilter {
public StandardEncodeFilter() { }
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
String contentType = servletRequest.getContentType();
if ((contentType == null) ||
contentType.equalsIgnoreCase("application/x-www-form-urlencoded")) {
System.out.println("StandardEncodeFilter Pass");
translateParamsToAttributes(servletRequest, servletResponse);
}
filterChain.doFilter(servletRequest, servletResponse);
}
private void translateParamsToAttributes(ServletRequest request,
ServletResponse response) {
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String)paramNames.nextElement();
String [] values;
values = request.getParameterValues(paramName);
System.out.println(paramName+" = " + values[0]);
if (values.length == 1)
request.setAttribute(paramName, values[0]);
else
request.setAttribute(paramName, values);
}
}
}


MultipartEncodeFilter.java
import com.oreilly.servlet.MultipartRequest;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class MultipartEncodeFilter extends BaseEncodeFilter {
public MultipartEncodeFilter() { }
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
String contentType = servletRequest.getContentType();
if (contentType.startsWith("multipart/form-data")) {
System.out.println("MultipartEncodeFilter Pass");
try {
String uploadFolder =
getFilterConfig().getInitParameter("UploadFolder");
if (uploadFolder == null)
uploadFolder = ".";
MultipartRequest multi =
new MultipartRequest(servletRequest,
uploadFolder,
1 * 1024 * 1024);
Enumeration params = multi.getParameterNames();
while (params.hasMoreElements()) {
String name = (String)params.nextElement();
String value = multi.getParameter(name);
System.out.println(name+" = " + value);
servletRequest.setAttribute(name, value);
}
Enumeration files = multi.getFileNames();
while (files.hasMoreElements()) {
String name = (String)files.nextElement();
String filename = multi.getFilesystemName(name);
String type = multi.getContentType(name);
File f = multi.getFile(name);
}
} catch (IOException e) {
System.err.println(e);
}
}
filterChain.doFilter(servletRequest, servletResponse);
}
}


encodeServlet.java
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class encodeServlet extends HttpServlet {
private static final String CONTENT_TYPE = "text/html; charset=EUC-KR";
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doProcess(request, response);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doProcess(request, response);
}
public void doProcess(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType(CONTENT_TYPE);
System.out.println("Servelt Pass");
request.setAttribute("isServletPass","servlet Pass OK!");
RequestDispatcher dispatcher =
request.getRequestDispatcher("/output.jsp");
dispatcher.forward(request, response);
}
}


web.xml
<?xml version = '1.0' encoding = 'EUC-KR'?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<description>Empty web.xml file for Web Application</description>
<filter>
<filter-name>StandardEncodeFilter</filter-name>
<display-name>StandardEncodeFilter</display-name>
<description>
</description>
<filter-class>StandardEncodeFilter</filter-class>
</filter>
<filter>
<filter-name>MultipartEncodeFilter</filter-name>
<display-name>MultipartEncodeFilter</display-name>
<description>
</description>
<filter-class>MultipartEncodeFilter</filter-class>
<init-param>
<param-name>UploadFolder</param-name>
<param-value>D:/</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MultipartEncodeFilter</filter-name>
<url-pattern>/encodeservlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>StandardEncodeFilter</filter-name>
<url-pattern>/encodeservlet</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>encodeServlet</servlet-name>
<servlet-class>encodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>encodeServlet</servlet-name>
<url-pattern>/encodeservlet</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>35</session-timeout>
</session-config>
<mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
</web-app>


Index.html
<form name="standard" method="POST" action="encodeservlet">
<table cellspacing="0" cellpadding="0" border="1" width="100%" align="left">
<tr>
<td colspan="2">스텐다드 전송</td>
</tr>
<tr>
<td>파라미터 1</td>
<td><input type="text" name="param1" size="15"/></td>
</tr>
<tr>
<td>파라미터 2</td>
<td><input type="text" name="param2" size="15"/></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="전송"/></td>
</tr>
</table>
</form>
<form name="multipart" method="POST" action="encodeservlet" enctype="multipart/form-data">
<table cellspacing="0" cellpadding="0" border="1" width="100%" align="left">
<tr>
<td colspan="2">Multipart 전송</td>
</tr>
<tr>
<td>파라미터</td>
<td><input type="text" name="param" size="15"/></td>
</tr>
<tr>
<td>첨부파일</td>
<td><input type="FILE" name="attfile" size="15"/></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="전송"/></td>
</tr>
</table>
</form>


output.jsp
<%@ page contentType="text/html;charset=EUC-KR"%>
<%
java.util.Enumeration keys = request.getAttributeNames();
String key = "";
while(keys.hasMoreElements()) {
key = (String)keys.nextElement();
out.println("<br>"+key+" : "+request.getAttribute(key));
}
%>

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...