Sitemesh 싸이트에서 번역한 자료입니다. 좀 허접하게 번역했지만.. 아마도 번역을 안해줘서...

 

SiteMesh는 Decorator Tag, Page Tag 2개의 tag 라이브러리를 제공한다. Decorator Tag는 decorator page를 생성할 때 사용되는 tag이고, Page Tag는 decorator 페이지 내에서 다른 decorator를 포함할 때 사용된다.

Decorator Tags

<decorator:head />

원래 웹페이지의 HTML <head> 태그의 내용을 추가한다. 속성은 없다.

<decorator:body />

원래 웹페이지의 HTML <body> 태그의 내용을 추가한다. body의 onload, onunload 이벤트의 바디 속성은 body.onload 와 body.onunload decorator에 의해 포함되어 쓰일 수 있다.

<body onload="<decorator:getProperty property="body.onload" />">
<body onload="alert('1');" bottommargin=5>

좀더 자세히 알기 위해서는 getProperty를 참조할 것. 속성은 없다.

<decorator:title [ default="..." ] />

Insert title of 원래 HTML 페이지의 title 태그로부터 얻은 title을 추가한다. title을 찾을 수 없다면, value값을 default로 지정할 수 있다.

<decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/>

원래 페이지의 속성을 추가한다. HTMLPage interface를 이용하여 해당 페이지의 속성들을 얻어낼 수 있다.

property : 추가할 속성의 이름 (key)
default : 속성을 발견하지 못헀을 때, default로 지정되는 값
writeEntireProperty : 1, yes, true, t, y 로 지정했을 때, 이름을 포함한 속성값(propertyName="propertyValue")이 그대로 쓰여진다.
예)

decorator: <body bgcolor="White"<decorator:getProperty property="body.onload" writeEntireProperty="true" />>
undecorated page: <body onload="document.someform.somefield.focus();">
decorated page: <body bgcolor="White" onload="document.someform.somefield.focus();">

<decorator:usePage id="..." />

decorator jsp에서 사용할 수 있는 Page Object id를 지정한다.
id : 지정할 ID
예1)

<decorator:usePage id="myPage" />
<% if ( myPage.getIntProperty("rating") == 10 ) { %>
  <b>10 out of 10!</b>
<% } %>

예2)

<decorator:usePage id="p" />
<%
	HttpServletRequest req = p.getRequest();
	StringBuffer printUrl = new StringBuffer();
	printUrl.append( req.getRequestURI() );
	printUrl.append("?printable=true");
	if (request.getQueryString()!=null) {
	    printUrl.append('&');
	    printUrl.append(request.getQueryString());
	}
%>
<p align="right">[ <a href="<%= printUrl %>">printable version</a> ]</p>

Page 태그

page 태그는 현재 페이지
The page tags, are used to apply decorators to inline or external content from within the current page.

<page:applyDecorator name="..." [ page="..." title="..." ] > .....body.... </page:applyDecorator>

특정 컨텐츠에 decorator를 적용한다. 해당 컨텐츠는 tag를 통해 body를 지정함으로서, 또는 page 속성을 지정하여 다른 page의 결과를 사용함으로서 인라인(inline)되게 할 수 있다.

name : 포함될 페이지에 적용될 decorator
page : 전체 page에서 쓸 수 있는 외부 자원을 상대적(relative), 절대적(absolute) 패쓰를 이용하여 지정한다.
title : Page.getTitle() 메소드 또는 decorator안에서 <decorator:title/> 를 사용하여 page의 title을 다시 지정(override)할 수 있다. <page:param name="title">...<page:param>에서 지정하여 식별이 가능하도록 한다.
Body : decorator가 적용될 내용.

<page:param name="..."> ... </page:param>

파라미터를 decorator로 넘긴다. 이 값은 Page.getProperty() 또는 <decorator:getProperty/>로부터 얻어온 값을 오버라이드할 수 있다.

name : 오버라이드될 파라미터의 이름
Body: 파라미터의 값.

DecoratorMappers

어떤 한 웹 페이지가 파싱이 될 때, 그것은 decorator에 매핑이 된다. 이 매핑은 DecoratorMappers의 체인에 의해 수행된다.
각 요청이 들어올 때마다 체인의 가장 첫번째 mapper는 어느 decorator가 쓰여져야 하는 지를 물어본다. 그래서 Page Object와 HttpServletRequest 객체를 reference로 받고, 해당 decorator가 쓰여지는지 알게 되면 그 decorator를 리턴하고, 모르면 null을 리턴한다.. 만약 null이 리턴 되면, 체인의 다음번 mapper에게 또다시 decorator 찾는 쿼리를 하게 된다.
이런 전체적인 프로세스는 체인에 더이상 mapper이 없거나, 체인에 있는 decorator가 valid한 decorator를 리턴할 때까지 반복된다. 만약 어떠한 mapper가 decorator를 리턴할 수 없는 상태면, 그 page는 전혀 장식이 되지 않고, 원래상태에 따라 화면이 표출될 것이다.

이런 체인의 mapper 호출 방식은 Chain of Responsibility 패턴으로 유명하다.

mapper의 예

  • 요청된 페이지의 path를 바탕으로 decorator를 결정한다.
  • 로케일, 시간 또는 브라우져에 따라 다른 decroator를 사용한다.
  • 검색 엔진 로봇에 맞은 간단한 decorator를 사용한다.
  • URL 파라미터, Request 속성 또는 meta-tag에 따라 decorator를 달리 사용한다.
  • 미리 저장된 사용자의 셋팅에 맞게 커스트마이즈된 decorator를 사용한다.

DecoratorMapper의 주요 구현은 ConfigDecoratorMapper이다. 이 클래스는 /WEB-INF/decorators.xml 파일을 읽어 mapping과 decorator를 읽는다. 적절한 decorator는 URL 패턴에 따라 적용되어 진다.

Mapper의 종류

Mapper 종류 내용
AgentDecoratorMapper browser에 따른 decorator를 선택할 수 있도록 한다.
browser 타입은 일반적인 경우와 같이 request.getHeader("User-Agent")를 통해 구해온다.
다른 mapper들이 특정 decorator를 지칭하여 반환하는 것과 달리 AgentDecoratorMapper는 적용될 decorator의 decorator page이름을 browser에 따라 수정한다.
예를 들어 decorator mapper가 main decorator를 선정했다면 decorator 페이지는 /decorators/main.jsp가 적용될 것이다. 하지만 http 클라이언트가 익스플러라면 main decorator에 /decorators/main-ie.jsp 장식자 페이지를 적용하게 된다.
모질라 기반 browser라면 /decorators/main-ns.jsp가 decorator page로 결정된다.
만약 선정된 decorator page를 찾는데 실패하면 기본 decorator page인 main.jsp가 적용될 것이다.
<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
    <param name="match.MSIE" value="ie" />
    <param name="match.Mozilla [" value="ns" />
    <param name="match.Opera" value="opera" />
    <param name="match.Lynx" value="lynx" />
</mapper>
ConfigDecoratorMapper DecoratorMapper의 디폴트 구현으로서, decorators.xml 파일을 읽어 decorator와 mapping된 데이터들을 읽는다.
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
    <param name="config" value="/WEB-INF/decorators.xml" />
</mapper>
CookieDecoratorMapper 쿠키값을 바탕으로 하는 decorator를 선정할 수 있다.
EnvEntryDecoratorMapper decorator 이름으로 web-app 환경 entry에 대한 레퍼런스를 허락한다.
FileDecoratorMapper 파일 이름을 주어 decorator의 이름을 취급한다.
<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
</mapper>
FrameSetDecoratorMapper page가 HTMLPage나 isFrameSet()의 리턴값이 true일 때, 특정 decorator를 선정할 수 있도록 해준다. 그 decorator의 이름은 주어진 property에서 지정할 수 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
</mapper>
InlineDecoratorMapper inline decorator를 사용할 때, 올바른 decoraotor가 무엇인지 사용할 때 선정할 수 있다.
LanguageDecoratorMapper browser에서 page 요청에 대해 "Accept-Language" HTTP 헤더를 이용하여 language 페이지를 결정할 때 선정할 수 있다.
locale에 따라서 decorator의 파일의 이름에 '-en'에 붙여져서 사용될 수 있도록 지정할 수 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper">
  <param name="match.en" value="en" />
  <param name="match.zh" value="zh" />
</mapper>
PageDecoratorMapper 메타 태그에 decorator 항목이 있을 때 장식자를 리턴한다.
PageDecoratorMapper는 여러 파라미터를 받는다. 밑의 예를 보면, PageDecoratorMapper는 첫번째 파라미터로 meta.decorator 프로퍼티를 받는다. 이 의미는 decorator의 META 프로퍼티의 값이 decorator 이름으로 쓰여질 수 있다는 것을 의미한다. decorator_test라는 이름의 장식자를 특정페이지에 적용하고 싶다면 <META name="decorator" content="decorator_test">와 같이 페이지에 메타 태그를 추가하거나 또는 <HTML decorator="decorator_test">와 같이 <HTML> 태그를 수정하여 사용한다.
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    <param name="property.1" value="meta.decorator" />
    <param name="property.2" value="decorator" />
</mapper>
decorators.xml에서 decorator_test decoration을 미리 정의
<decorator name="decorator" page="tv.jsp">
</decorator>
ParameterDecoratorMapper 설정에 정의된 파라미터와 동일한 스트링이 URL 쿼리 스트링에 존재할 때 정의해 놓은 decorator를 선정하도록 되어 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
    <param name="decorator.parameter" value="decorator" />
    <param name="parameter.name" value="confirm" />
    <param name="parameter.value" value="true" />
</mapper>

이 mapper는 3개의 parameter가 존재한다.
decorator.parameter : 특정 decorator의 이름을 지칭하는 리쿼스트 파라미터의 이름
parameter.name : 특정 리쿼스트 파라미터를 confirm하는데 사용하는 리쿼스트 파라미터의 이름
parameter.value : 특정 decorator 파라미터를 confirm하는데 사용하는 리쿼스트 파라미터의 값
만약 help.jsp 파일에 이 mapper에 test decorator를 적용하려면 다음의 코드로 호출하면 된다.

help.jsp
help.jsp?decorator=test&confirm=true
SessionDecoratorMapper session 어트리부트에서 지정한 decorator를 선정하도록 되어 있다.
디폴트로 decorator를 session 속성에서 찾지만, decorator.parameter 속성을 통해서 오버라이드 될 수 있다.
PrintableDecoratorMapper URL 쿼리 스트링의 printable=true라는 문자열에 반응한다.
decorators.xml에 정의된 decorator중 printable decorator를 리턴할 것이다.
아래의 예는 다음을 의미한다. printable로 정의된 decoraotr는 printable=true 라는 리쿼스트가 들어올 때 해당 jsp가 적용된다.
<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
	<param name="decorator" value="printable" />
	<param name="parameter.name" value="printable" />
	<param name="parameter.value" value="true" />
</mapper>
RobotDecoratorMapper 검색엔진 로봇에서 식별되어 지는 특정 decorator를 선정하도록 되어 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
    <param name="decorator" value="robot" />
</mapper>

사용자 정의 mapper 환경 설정

sitemesh.xml

요청에 따라 적용될수 있는 mapper를 정의하기 위해서는 sitemesh.xml파일을 생성한다.

sitemesh.xml
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />
    <excludes file="${decorators-file}" />

    <page-parsers>
        <parser content-type="text/html"
            class="com.opensymphony.module.sitemesh.parser.HTMLPageParser" />
        <parser content-type="text/html;charset=ISO-8859-1"
            class="com.opensymphony.module.sitemesh.parser.HTMLPageParser" />
    </page-parsers>

    <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
            <param name="config" value="${decorators-file}" />
        </mapper>
    </decorator-mappers>
</sitemesh>

이 예에서 유일하게 적용된 mapper는 ConfigDecoratorMapper이다. 이 mapper는 웹페이지의 content-type이 text/html 이거나 text/html;charset=ISO-8859-1인 경우일때만 적용될 것이다. 다른 content-type(예, image/gif)의 page는 적용되지 않는다.

decorators.xml

부가적으로 패턴 매치를 이용하여 특정 파일들을 exclude하여 Sitemesh가 처리하지 않게 할 수 있다.
<excludes /> block을 이용하여 exlcude해야할 파일을 설정할 수 있다.

decorators.xml
<decorators>
    <excludes>
        <pattern>/plainPage.jsp</pattern>
        <pattern>/plain/*.jsp</pattern>
    </excludes>
</decorators>

/plainPage.jps와 /plain 디렉토리의 jsp 페이지는 장식이 전혀 되지 않는다. (패턴 매칭은 ConfigDecoratorMapper에서 사용되는 decorator 매핑처럼 정확하게 같은 룰을 따른다. )

일반적으로 <excludes /> 블럭은 decorators.xml 파일의 시작에서 추가되지만, 다른 XML 파일에서 정의할 수 있다.

디폴트 mapper 환경설정

만약 WEB-INF 디렉토리에서 sitemesh.xml이 발견되지 않으면, 디폴트 mapper 설정 화일이 사용되어 질 수 있다. 디폴트 mapper 환경설정파일의 정의는 sitemesh.jar안에 있는 sitemesh-default.xml의 설정파일이 적용된다. 그리고, 다음의 mapper들로 구성되어 진다.

  • PageDecoratorMapper
  • FrameSetDecoratorMapper
  • PrintableDecoratorMapper
  • FileDecoratorMapper
  • ConfigDecoratorMapper

디폴트로 오직 text/html 컨텐트 타입만 Sitemesh에 의해 decoration된다.

 

 

 

Freemarker 예제

Freemarker와 연동하여 decoration을 사용할 수 있다.

Freemarker lib

Freemarker lib을 사용한다.

web.xml 수정

WEB-INF/web.xml에 <web-app> 태그에 다음의 코드를 추가한다.

web.xml
<servlet>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
	<init-param>
		<param-name>TemplatePath</param-name>
		<param-value>/</param-value>
	</init-param>
	<init-param>
		<param-name>default_encoding</param-name>
		<param-value>ISO-8859-1</param-value>
	</init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <url-pattern>*.dec</url-pattern>
</servlet-mapping>

decorators.xml 수정

\.dec 파일을 레퍼런스하여 decorators.xml을 수정한다.

decorators.xml
<#include "/includes/decorators/header.dec">
    <h2>${title}</h2>
    ${head}
    <img src="${base}/images/logo.gif" border="0">
    <td valign="top" class="body">
        <div class="header">
            <span class="pagetitle">${title}</span>
        </div>
        ${body}
    </td>
<#include "/includes/decorators/footer.dec">

Context

FreemarkerDecoratorServlet은 당신이 필요로 하게될 정보, 즉 Context object들을 저장한다.

기본 context 속성

모든 리쿼스트, 리쿼스트 파라미터, 세션, 서블릿 context 속성 그리고 어플리케이션 변수를 얻을 수 있다.

예)

${Session["user"]}

어플리케이션안에서, 세션안에서, 리쿼스트안에서 변수를 찾아낼 수 있고, 지정할 수 있다.

<#assign ww=JspTaglibs["/WEB-INF/webwork.tld"]>

JspTaglibs라고 하는 변수를 생성하고, JSP 태그 라이브러리에서 로드할 수 있도록 쓸 수 있다.

<#assign ww=JspTaglibs["/WEB-INF/webwork.tld"]>
...
<@ww.property value="myVar"/>

Sitemesh context 속성

base request.getContextPath()
title page title을 파싱한다. (<title>...<title>)
head page head를 파싱한다.
body page body를 파싱한다.
page SiteMesh의 내부 Page object 를 얻

'web' 카테고리의 다른 글

Sitemesh 참조자료  (0) 2007.08.24
Sitemesh #4 Sitemesh 팁  (0) 2007.08.24
Sitemesh #2 Sitemesh 소개  (0) 2007.08.24
Sitemesh #1 Tiles에서 Sitemesh로 변환하기  (0) 2007.08.24
multi-part/form-data  (0) 2007.08.23
Posted by '김용환'
,

Sitemesh #2 Sitemesh 소개

web 2007. 8. 24. 05:22

이글은 webwork,sitemesh를 기반으로 한 프레임워크에 적합한 내용입니다. 그리고, 이 글은 모든 내용이 다 맞지 않습니다.

한글 자료가 거의 전무하여 적어 놓게 되었습니다. 회사이름은 밝히기 않기 위해. 대충 가명썼습니다..

 

소개

SiteMesh는 web-page layout이고, decoration(장식) 프레임웍이고, 일관된 look/fee, navagation, layout scheme를 필요로 하는 많은 페이지로 구성된 큰 사이트를 만드는것을 도와주는 web-application 통합 프레임웍이다. 일관성있는 요소들때문에 조직화하고, 변화와 수정에 탁월해야 한다. Sitemesh,는 웹 서버에 요구된 정적/동적 요청을 가로채어 요청된 페이지 자원을 파싱하여 설정된 속성과 렌더링할 데이터를 컨텐츠로부터 읽어들여 원래의 페이지에 decoration과 수정을 가해 최종 페이지를 생성한다.

대부분의 HTML 문서는 다음과 같은 decorator 패턴 양식을 가지고 있다.

  • meta tags (keywords, description, author)
  • stylesheet (CSS)
  • header
  • navigation
  • footer
  • copyright notice

naviation과 layout 스킴만 정하면 나머지는 공통부분으로 따로 정리할 수 있도록 도와주는 프레임웍이 Sitemesh 이다.


Figure 1. Normal Page Rendering


Figure 2. SiteMesh Page Rendering

 

간단히 맛보기

기본적인 jsp 코드는 다음과 같다.

simple.jsp
<html>
    <head>
        <title>Simple Document</title>
    </head>
    <body>
        Hello World! <br />
        <%= 1+1 %>
        </body>
</html>

위의 코드의 템플릿으로 만들어지는 페이지를 데코레이션을 사용하여 jsp 페이지를 동적으로 승화시킬 수 있다.

decorator.jsp
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<html>
    <head>
        <title> My Site - <decorator:title default="Welcome!" /> </title>
        <decorator:head />
    </head>
    <body>
        <h1><decorator:title default="Welcome!" /></h1>
        <p><decorator:body /></p>
    </body>
</html>

첫번째 라인에 sitemesh 태그라이브러리가 소개되고, <decorator:title> 엘리먼트는 장식될 페이지의 <title> 엘리먼트의 텍스트를 가져와 삽입한다. <decorator:body> 엘리멘트는 페이지의 본문을 장식한다.

Sitemesh에 모든 패턴에 사용할 decorator를 WEB-INF/decorators.xml파일에 설정한다.

decorators.xml
<decorators>

    <decorator name="mydecorator" page="/decorator.jsp">
        <pattern>/*</pattern>
    </decorator>

<decorators>

이런 식으로 밑의 파일처럼 특정 디렉토리 또는 패턴에 따라 다양하게 decoration이 가능하다.

decorators.xml
<decorators defaultdir="/decorators">

    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="anotherdecorator" page="decorator2.jsp">
        <pattern>/subdir/*</pattern>
    </decorator>

    <decorator name="htmldecorator" page="html.jsp">
        <pattern>*.html</pattern>
        <pattern>*.htm</pattern>
    </decorator>

    <decorator name="none">
        <!-- These files will not get decorated. -->
        <pattern>/anotherdir/*</pattern>
    </decorator>
</decorators>

환경 설정

cvs서버로부터 test_project프로젝트를 update하고, 그 기반에서 동작하는 것을 기준으로 한다.

  • sitemesh.jar가 [web-app home directory]/WEB-INF/lib에 위치해 있는지 확인한다. (sitemesh 2.1.1 gl 버젼의 jar파일이 저장되어 있음을 확인할 수 있을 것이다.)
  • [web-app home directory]/WEB-INF/web.xml의 <web-app> 태그안에 다음의 내용이 추가되어야 한다. webwork-cleanup - sitemesh - webwork 의 순서대로 등록해야 한다.
    web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    	version="2.4">
    
    .....fileter의 webwork-cleanup 정의 .....
             <filter>
    		<filter-name>sitemesh</filter-name>
    		<filter-class>
    			com.opensymphony.module.sitemesh.filter.PageFilter
    		</filter-class>
    		<init-param>
    			<param-name>pageEncoding</param-name>
    			<param-value>MS949</param-value>
    		</init-param>
    	</filter>
    
    .....fileter의 sitemesh 정의 .....
    
    
    .....filter-mapping의 webwork-cleanup 정의 .....
    	<filter-mapping>
    		<filter-name>sitemesh</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    .....filter-mapping의 sitemesh 정의 .....
  • [web-app home directory]/WEB-INF/sitemesh.xml 파일이 생성해야 한다. 필수 파일은 아니지만, 있어야 원하는 패턴을 지정할 수 있다.
    sitemesh.xml
    <sitemesh>
      <page-parsers>
        <parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
        <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
      </page-parsers>
    
      <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
          <param name="property.1" value="meta.decorator" />
          <param name="property.2" value="decorator" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
          <param name="match.MSIE" value="ie" />
          <param name="match.Mozilla [" value="ns" />
          <param name="match.Opera" value="opera" />
          <param name="match.Lynx" value="lynx" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
          <param name="decorator" value="printable" />
          <param name="parameter.name" value="printable" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
          <param name="decorator" value="robot" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
          <param name="decorator.parameter" value="decorator" />
          <param name="parameter.name" value="confirm" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
          <param name="config" value="/WEB-INF/decorators.xml" />
        </mapper>
      </decorator-mappers>	
    </sitemesh>
  • [web-app home directory]/WEB-INF/decorators.xml 파일이 생성되어야 한다.
    decorators.xml
    <decorators>
        <decorator name="defaultHeader" page="defaultHeader.jsp"/>
        <decorator name="defaultFooter" page="defaultFooter.jsp"/>
    
        <decorator name="default" page="default.jsp">
            <pattern>/*</pattern>
        </decorator>
    </decorators>

    헤더와 풋터 jsp를 지정한다.그리고, 디폴트 페이지를 모든페이지에 지정한다.

  • [web-app home directory]/WEB-INF/decorators 디렉토리에 템플릿으로 쓰일 default.jsp, defaultHeader.jsp, defaultFooter.jsp 파일을 생성한다.
    default.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    
    <head>
    <meta http-equiv=Cache-Control content=No-Cache>
    <meta http-equiv=Pragma content=No-Cache>
    <meta http-equiv="expires" content="0">
    <META HTTP-EQUIV="imagetoolbar" CONTENT="no">
    <meta http-equiv="Content-type" content="text/html; charset=euc-kr">
    <title><decorator:title default="퍼블 테스트" /></title>
    </head>
    
    <body bgcolor=ffffff bottommargin=0 topmargin=0 marginheight=0>
    <!-- TOP Menu -->
    <page:applyDecorator name="defaultHeader"/>
    <!-- //TOP Menu 영역 -->
    xxxx   <decorator:body/>   xxxx
    
    <!-- footer -->
    <page:applyDecorator name="defaultFooter"/>
    <!-- //footer 영역 -->
    </html>
    defaultHeader.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--head start-->
    Header<br>
    <!--head end-->
    defaultFooter.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--Footer start-->
    <br> Footer <Br>
    <!--Footer end-->
  • 하나의 액션 HelloWorld.java를 생성한다.
    HelloWorld
    import com.google.common.actions.GoogleBaseAction;
    
    public class HelloWorld extends GoogleBaseAction {
    	
    	public String execute() throws Exception {
    		return SUCCESS;
    	}
    }
  • [web-app home directory]/hello.jsp 코드를 작성한다.
    hello.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    Hello World
  • 결과
    Web browser
    Header
    xxxx Hello World xxxx 
    Footer

Sitemesh의 설정 파일 설명

decorators.xml

decorators.xml 은 여러 decorator의 정의와 특정 decorator가 적용될 페이지의 리스트가 설정되어 있다. decorator의 순서에 따라 적용되어 진다.

decorators.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<decorators defaultdir="/decorators">
    <!-- Any urls that are excluded will never be decorated by Sitemesh -->
    <excludes>
        <pattern>/exclude.jsp</pattern>
        <pattern>/exclude/*</pattern>
    </excludes>

    <!-- decorator 태그안에 page의 경로는 web-app/decorators/main.jsp가 된다.-->
    <decorator name="main" page="main.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="panel" page="panel.jsp"/>
    <decorator name="printable" page="printable.jsp"/>
    <decorator name="black" page="black.jsp"/>
    <decorator name="nopanelsource" page="nopanelsource.jsp"/>
    <decorator name="badpanelsource" page="badpanelsource.jsp"/>

    <decorator name="velocity" page="velocity.vm">
        <pattern>/velocity.html</pattern>
    </decorator>

    <decorator name="freemarker" page="freemarker.ftl">
        <pattern>/freemarker.html</pattern>
    </decorator>

    <decorator name="test" page="test.jsp">
        <pattern>/agent.jsp</pattern>
    </decorator>
</decorators>
  • decorators
    <decorators> 엘리먼트는 decorator들의 리스트를 정의하고 있다. <decorators defaultdir="/decorators">의 defaultdir="/decorators" attribute은 기본적으로 decorator page들이 위치하고 있는 경로를 나타낸다.
  • excludes
    <excludes> 엘리먼트는 decorator가 적용되지 않아야 할 패턴의 리스트이다.
    decorator name="main"의 main decorator는 모든 패턴의 리소스에 적용되며 main.jsp를 decorator page로 사용한다는 뜻이다.
    panel, printable, black, nonpanelsource, badpanelsource는 모두 패턴을 지정하지 않았고, freemaker, velocity는 특정페이지를 적용했다.
  • pattern
    <pattern> 엘리먼트는 decorator가 적용될 Request URI를 지정한다. 패턴이 적용되는 순서가 다르다. Request URI를 보고 다음의 순서대로 해당 decorator page를 찾게된다.
  1. 정확하게 단어가 맞는 패턴 (Exact word)
  2. 'abc*'나 'abc?'와 같은 컴플렉스 패턴 (Complext)
  3. '/', '*', '/*'와 같은 디폴트 패턴 (Default)

적절한 패턴이 설정되지 않은 decorator는 다른 decorator 내에서 <page:applyDecorator/>를 통해 포함할 때 사용되거나 decorator mapper(sitemesh.xml)에서 특정 decorator를 지정할 때 사용된다.

sitemesh.xml

sitemesh.xml은 decorator mapper 리스트가 설정되어 있다. 만일 Sitemesh가 해당 경로에서 설정 파일을 찾는데 실패하면sitemesh.jar 에 패키징 되어 있는 sitemesh-default.xml 파일로 대체된다.

sitemesh.xml
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />

    <page-parsers>
         <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>

    <excludes file="${decorators-file}" />

    <decorator-mappers>
	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
	    <param name="property.1" value="meta.decorator" />
	    <param name="property.2" value="decorator" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
		<param name="match.MSIE" value="ie" />
		<param name="match.Mozilla [" value="ns" />
		<param name="match.Opera" value="opera" />
		<param name="match.Lynx" value="lynx" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
		<param name="decorator" value="printable" />
		<param name="parameter.name" value="printable" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
		<param name="decorator" value="robot" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
		<param name="decorator.parameter" value="decorator" />
		<param name="parameter.name" value="confirm" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
		<param name="config" value="${decorators-file}" />
	</mapper>

	</decorator-mappers>
</sitemesh>
  • page parsers
    <page-parsers> 엘리먼트는 content-type에 따라 적용할 파서를 정의한다. SiteMesh는 현재 text/html을 파싱할 때 사용되는 FastPage Parser만 구현되어 있다. 나머지에 대해서는 디폴트로 DefaultPageParser가 사용가능하다.
    <page-parsers>
    	<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
    	<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>
  • decorator mapper
    decorator mapper는 Sitemesh에게 장식에 사용될 적합한 decorator를 설정해주는 역할을 한다. <decorator-mapper> 엘리먼트는 decorator mapper들을 정의한다. decorator mapper 추상 클래스는 링크드 리스트로 정의되어 있고, 적혀진 순서에 따라 decorator 체인으로 만들어진다.
    <decorator-mappers>
    	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    		<param name="property.1" value="meta.decorator" />
    		<param name="property.2" value="decorator" />
    	</mapper>
    </decorator-mappers>
    ....
  • excludes
    특정 웹 페이지(jsp)들을 모아 decoration이 적용되지 않도록 하는 설정파일을 지정한다.
    <excludes file="/WEB-INF/decorators.xml"/>
  • property
    변수화하여 쉽게 사용할 수 있도록 한다.
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />
    ...
    <excludes file="${decorators-file}" />
    ...
    <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
    	<param name="config" value="${decorators-file}" />
    </mapper>

ConfigDecoratorMapper는 decorator 파일들을 config로 지정할 수 있음을 의미하며, 여러 개의 config 파일을 포함할 수 있다.

Decorator를 이용한 일관성있는 Look

jsp와 이미 기존에 쓰이고 있는 CGI script가 사용할 수 있도록 도와줌으로서, 일관성있는 look을 제공한다.

 

Flow Diagram

web.xml에서 정의된 필터, 즉 PageFiletr에 의해 Sitemesh가 사용되어진다.


페이지를 Page 객체에 파싱한 후 DecoratorMapper에 의해서 Decorator를 판단한다. 그래서 sitemesh.xml 파일에 DecoratorMapper 선언된 순서대로 decorator를 사용하고 mapper에서 결국 decorator를 얻지 못하면 본래 모습으로 보여준다. 주요 DecoratorMapper는 /WEB-INF/decorators.xml에서 decorator와 mapping을읽어들이는 ConfigDecoratorMapper 이다.

 

 

SiteMesh 구조와 흐름

  1. request 단계
    모든 request는 PageFilter에서 가로채어진다. PageFilter는 Context 초기화 시점에 decorator.xml에 정의된 <exclude> 태그에 따라 요청된 request의 url-pattern에 따라 장식을 수행할지 여부를 결정한다.
  2. paring 단계
    PageFilter는 요청된 자원에 대한 웹 어플리케이션의 수행결과를 do(request, respose) 메소드를 호출하여 받아낸다. 응답 파라미터에는 ServletResponse가 아닌 HttpServletResponseWrapper를 상속받아 확장한 PageResponseWrapper 객체를 사용한다.
    따라서 페이지 아웃풋은 writer로 보내지 않고 content-type에 따라 선택된 파서가 PageResponseWrapper에서 캡처된 page 아웃풋 데이터를 파싱한다. 현재는 반환 page의 content-type이 text/html일 경우만 FastPageParser가 작동한다.
  3. decorator 선정 단계
    적합한 decorator를 결정한다. 이 과정은 mapper 클래스의 getDecorator()에 의해서 이뤄진다. 처음 decorator 선정을 시도한 mapper 클래스가 적합한 decorator를 얻어낸다면 리턴하고, 아니면 decorator 체인상의 상위 링크의 getDecorator() 메소들르 호출하게 된다. 정확한 decorator가 결정될 때까지 반복된다.
  4. decorator 단계
    decorator를 얻오고, decorator로부터 decorator page를 구해 올 수 있다면, PageFilter는 applyDecorator()내에서 decorator 페이지에 대한 요청을 생성하고, decorator page는 FastPageParser에 의해 파싱된 결과 page의 적절한 부분들을 커스텀 태그를 통해 가져와 출력 페이지를 작성한다.

참조

http://today.java.net/pub/a/today/2004/03/11/sitemesh.html

마소의 sitemesh 기사

Posted by '김용환'
,

이글은 webwork,sitemesh를 기반으로 한 프레임워크에 적합한 내용입니다. 그리고, 이 글은 모든 내용이 다 맞지 않습니다.

한글 자료가 거의 전무하여 적어 놓게 되었습니다. 회사이름은 밝히기 않기 위해. 대충 가명썼습니다..

 

Concept

Tiles Layout은 만들어진 템플릿 jsp를 기준으로 extends 태그를 통해 확장하는 구조를 가지고 있는 반면, Sitemesh Layout은 action과 pattern을 이용하여 쉽게 장식을 할 수 있다. Lucy의 기본 프레임인 Webwork와 Sitemesh는 같은 Opensympony 프로젝트에 같이 포함되어 있어서 궁합(?)이 아무래도 Tiles보다는 높다.

Tiles는 특정 템플릿에 적용되는 여러 jsp(보통 하나의 Action에 해당되기도 한다.)에 일일히 지정해야 하는 불편함이 있어서, 환경설정 파일이 길어지는 단점이 있다. 하지만, Sitemesh는 action별로 분류하고, 서비스에 맞게 pattern(예, '*')을 지정하여 임의의 jsp 혹은 action을 그룹단위로 묶어 처리한다.

Tiles를 Sitemesh로 변환하기에 앞서 먼저 xwork.xml의 서술된 action과 result를 보고 활용해야 한다. Sitemesh는 요청받은 URL을 기준으로 처리하기 하기 때문에 action의 이름(예, index.gl)을 가지고 처리하는 것이 Sitemesh에서 쉽게 처리할 수 있다.
첫번째, 환경 설정을 먼저 해야 한다. Sitemesh를 쓰기 위해서는 당연히 web.xml에서 기술하고, 관련된 WEB-INF/web/sitemesh.xml 파일과 WEB-INF/web/decorators.xml 파일을 생성해야 한다.
두번째, Tiles 환경 설정파일(tiles.xml 라고 하자.)에서 Layout 템플릿을 Sitemesh 법칙에 맞게 변경한다. Tiles에 종속적인 태그라이브러리는 당연히 Sitemesh가 제공하는 태그 라이브러리로 바꾸면 된다.
그리고, Action과 jsp파일의 패턴을 템플릿에 적용시킨다.

간단하지 아니한가?! 이 글을 쓰는 시점에 game1을 Tiles에서 Sitemesh로 바꿨더니 줄 수가 1/3정도로 줄어들었다. 만약 처음부터 Sitemesh로 개발하면, 스크롤할 필요도 없이 잘 끝낼 수도 있다.

이 설명이 다인가 하고 놀랬을 터이지만, 놀라지 마라. 상세하고 친절한 설명이 계속 진행된다.

변환 가이드

1. web.xml에서 sitemesh를 적용한다.

  • 가장 먼저 tiles 관련 설정을 web.xml에서 제거한다.
  • [web-app home directory]/WEB-INF/web.xml의 <web-app> 태그안에 다음의 내용이 추가되어야 한다. webwork-cleanup - sitemesh - webwork 의 순서대로 등록해야 한다.
    web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    	version="2.4">
    
    .....fileter의 webwork-cleanup 정의 .....
             <filter>
    		<filter-name>sitemesh</filter-name>
    		<filter-class>
    			com.opensymphony.module.sitemesh.filter.PageFilter
    		</filter-class>
    		<init-param>
    			<param-name>pageEncoding</param-name>
    			<param-value>MS949</param-value>
    		</init-param>
    	</filter>
    
    .....fileter의 webwork 정의 .....
    
    
    .....filter-mapping의 webwork-cleanup 정의 .....
    	<filter-mapping>
    		<filter-name>sitemesh</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    .....filter-mapping의 webwork 정의 .....
    
    </web-app>

2. sitemesh.xml파일을 생성한다.

[web-app home directory]/WEB-INF/sitemesh.xml 파일을 생성한다.

디폴트로 여러 decoration 환경 설정을 포함할 수 없기 때문에, com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper 클래스를 사용해야 한다. 이 클래스는 <param> 태그의 이름을 오름차순 정렬하여 우선순위를 정하기 때문에, config.1, config.2 와 같이 우선순위가 높은 decorator를 지정할 수 있도록 해야 한다.

sitemesh.xml
<sitemesh>
	<excludes file="/WEB-INF/decorators.xml"/>

	<page-parsers>
		<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
		<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
	</page-parsers>

	<decorator-mappers>
		<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
			<param name="property.1" value="meta.decorator" />
			<param name="property.2" value="decorator" />
		</mapper>

		<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
			<param name="decorator.parameter" value="decorator" />
			<param name="parameter.name" value="confirm" />
			<param name="parameter.value" value="true" />
		</mapper>

                  <mapper class="com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper">
                            <param name="config.1" value="/common/decorators/decorators.xml" />
                            <param name="config.2" value="/WEB-INF/decorators.xml" />
                  </mapper>
	</decorator-mappers>
</sitemesh>

google 소스 트리에서 web/common/decorators/ 디렉토리에 공통으로 쓰일 decorators.xml 파일이 있고, 하위 폴더에 common-decorators 디렉토리가 있어 공통으로 쓰일 Layout 템플릿을 지정할 수 있다. 현재는 'underLayout'라는 이름으로 지정한 decorator page를 설정하고 있다.

web/common/decorators/decorators.xml
<decorators defaultdir="/common/decorators/common-decorators">
    <decorator name="underLayout" page="underLayout.jsp"/>
</decorators>

3. decorators.xml파일을 생성한다.

[web-app home directory]/WEB-INF/decorators.xml 파일을 생성한다. 정의된 defaultdir를 통해 파일안에서 상대 경로를 써서 Layout 페이지를 지정할 수 있다.

decorators.xml
<decorators defaultdir="/WEB-INF/decorators">
</decorators>

4. Tiles의 Layout 템플릿 정의를 Sitemesh의 decorator로 수정한다.

Tiles와 약간 다른 부분이다. Tiles는 임의의 파일을 메인 Layout 템플릿으로 지정하고, 이안에 저장될 스크립트, 상위메뉴, 우메뉴등등을 지정한다. 그리고, content 또는 body 부분을 "/"로 지정하여 extends한 Tiles 태그에서 적용될 jsp페이지를 적는다.

Sitemesh는 먼저 decorator 태그를 이용하여 태그를 지정하여 부분 Layout 템플릿을 정의한다. 그리고 나서, 메인 Layout 템플릿을 정의한다. 마지막으로 Tiles의 흔적이 남는 tiles디렉토리도 tiles에서 decorators로 변경해야 한다.

tiles.xml
<definition name=".layout.master.main" path="/WEB-INF/tiles/renewal_2006/layout/game1Layout.jsp">
    <put name="script" value="/share/tiles/game_script.jsp"/>
    <put name="common_activex" value="/common/common_activex.jsp"/>
    <put name="topmenu" value="/share/tiles/header_casual.jsp"/>
    <put name="rightmenu" value=".layout.master.rightmenu"/>
    <put name="content" />
    <put name="footer" value="/share/tiles/game1MainFooter.jsp"/>
</definition>
decorators.xml
<decorator name="script" page="/share/decorators/game_script.jsp"/>
<decorator name="common_activex" page="/common/common_activex.jsp"/>
<decorator name="topmenu" page="/share/decorators/header_casual.jsp"/>
<decorator name="rightmenu" page="renewal_2006/layout/rightMenuLayout.jsp"/>
<decorator name="footer" page="/share/decorators/game1MainFooter.jsp"/>
<decorator name="submenu" page="/share/decorators/right_casual.jsp"/>

<decorator name=".layout.master.main" page="renewal_2006/layout/game1Layout.jsp">
</decorators>

5. 메인 Layout 템플릿 소스를 Sitemesh의 정의에 맞게 수정한다.

game1Layout.jsp에 page 태그와 decorator 태그를 이용하여 수정한다. 쉽게 설명하면, page 태그는 이미 정의된 부분 Layout템플릿을 사용하는 것이고, decorators 태그는 실제 적용될 jsp 파일의 title, body 태그에서 정의된 내용을 참조하기 위함이다. (자세한 내용은 매뉴얼을 꼭 참조하라)

<tiles:insert> 일리먼트는 <page:applyDecorator> 일리먼트로 수정한다. 그리고, 실제 데이터가 들어갈 부분 content attribute을 <decorator:body/>로 바뀐다.

xwork.xml에서 action에서 result로 지정되어 dispatch된 jsp파일의 내용이 들어가게 된다. 이렇게 함으로서, tiles에 의존적이 않던 jsp 코드는 전혀 수정할 필요가 없게 된다. 만약, tiles.xml에서 정의된 content attribute에 정의된 show.jsp가 있다면, 이 내용 자체가 <decorator:body/>에 그대로 적용될 것이다. 유의할 점은 body 태그를 쓴다는 것이다.

Before,game1Layout.jsp,
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>
<tiles:importAttribute scope="request" ignore="true"/>
<tiles:insert attribute="script"/>
<tiles:insert attribute="common_activex"/>
<tiles:insert attribute="topmenu"/>
<tiles:insert attribute="content"/>
<tiles:insert attribute="rightmenu"/>
<tiles:insert attribute="footer"/>
game/show.jsp
<script> 불라 불라 </script>
<table> 불라 불라 </table>
After,game1Layout.jsp
<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
<page:applyDecorator name="script"/>
<page:applyDecorator name="common_activex"/>
<page:applyDecorator name="topmenu"/>
<decorator:body/>
<page:applyDecorator name="rightmenu"/>
<page:applyDecorator name="footer"/>

6. 개별 페이지를 Layout템플릿에 적용시킨다.

  • Tiles의 definition이 Sitemesh의 decorator을 이용하여 메인 Layout 템플릿이 변경되었으니, 적용될 각 jsp 또는 action을 지정하면 된다. '*' 같은 pattern을 이용하여 Sitemesh를 잘 활용하여 한줄이라도 아껴쓰자.
    tiles.xml
    <definition name=".layout.master.main.goldwing" extends=".layout.master.main.goldwing.default">
    	<put name="gamegen" value="/WEB-INF/tiles/goldwinglayout/inpage/goldwinggen.jsp"/>
    </definition>
    decorators.xml
    <decorator name=".layout.master.main.goldwing.default" page="/WEB-INF/tiles/goldwinglayout/masterMainLayout.jsp">
             <pattern>goldwinglayout/inpage/goldwinggen.jsp</pattern>
             <pattern>/goldwing/*.gl</pattern>
    </decorator>
  • xwork.xml에 정의된 action을 이용하여 패턴화한다. xwork.xml에서 정의된 same Action을 참조하여 tiles.xml에서 사용되고 있음을 확인하고, decorators.xml에 decorator를 적용시킨다.
    xwork.xml
    <action name="same" class="com.google.game1.action.SameGameAction" >
    	<result name="main" type="tiles">.same.main</result>
    	<result name="iframe" type="tiles">.same.iframe</result>
    	<result name="rank" type="tiles">.same.rank</result>
    	<result name="includedrank" type="tiles">.layout.master.includedrank.casual</result>
    	<result name="search" type="tiles">.layout.master.searchrank.casual</result>
    </action>
    tiles.xml
    <definition name=".same.main" extends=".layout.master.main">
    	<put name="content" value="/same/layout/content_same.jsp"/>
    </definition>
    
    <definition name=".same.rank" extends=".layout.master.main">
    	<put name="content" value="/same/rank/rank_same.jsp"/>
    </definition>
    
    <definition name=".same.iframe" extends=".layout.master.main">
    	<put name="content" value=".layout.master.content.iframe"/>
    </definition>
    decorators.xml
    <decorator name=".layout.master.main" page="/WEB-INF/tiles/renewal_2006/layout/game1Layout.jsp">
    	<pattern>/same.gl</pattern>
    </decorator>
  • xwork.xml의 action을 수정한다
    xwork.xml에는 여전히 Tiles의 흔적이 남아 있다.바로 action의 result 태그에 type으로 지정되었다. 이를 dispatcher로 바뀌거나 아예 그 부분을 삭제한다. type을 지정하지 않으면, dispatcher 타입이다.
    Before,xwork.xml
    <action name="same" class="com.goole.game1.action.GoogleAction" >
    	<result name="main" type="tiles">.same.main</result>
    	<result name="iframe" type="tiles">.same.iframe</result>
    	<result name="rank" type="tiles">.same.rank</result>
    	<result name="includedrank" type="tiles">.layout.master.includedrank.casual</result>
    	<result name="search" type="tiles">.layout.master.searchrank.casual</result>
    </action>
    After,xwork.xml
    <action name="same" class="com.google.game1.action.SameGameAction" >
    	<result name="main">/same/layout/content_same.jsp</result>
    	<result name="iframe">/share/decorators/iframe_casual.jsp</result>
    	<result name="rank">/same/rank/rank_same.jsp</result>
    	<result name="includedrank">/share/rank/includedrank_casual.jsp</result>
    	<result name="search">/share/rank/searchrank_casual.jsp</result>
    </action>
  • 모든 jsp 파일에서 tiles에서 decorators로 변경된 path를 적용한다.
    이클립스를 검색을 이용하여 파일의 내용에 tiles가 들어간 xml, jsp파일을 검색해서 모두 변경해야 한다.
    Before, content_same.jsp
    <jsp:include page="/share/tiles/channel_casual.jsp"/>
    After, content_same.jsp
    <jsp:include page="/share/decorators/channel_casual.jsp"/>
  • Tiles의 insert 페이지를 변환한다.
    Tiles가 적용환 jsp파일에 <tiles:insert> 태그가 적용된 페이지를 <page:applyDecorator> 태그로 수정하고, decorators.xml에 decorator패턴으로 지정한다.
    jsp
    <tiles:insert page="/cross/bbs/pagelist.jsp"/>
    decorators.xml
    <decorator name="pageList" page="/cross/bbs/pagelist.jsp"/>
    jsp
    <page:applyDecorator name="footer"/>
  • 큰 Layout 템플릿에 속해 있는 일부 템플릿을 다른 템플릿으로 교체하는 경우
    Tiles는 이런 경우 extends를 이용하여 큰 Layout 템플릿을 extends하고, 해당 attribute만 put을 함으로서, overwrite가 가능하다. 그러나 Sitemesh는 새롭게 Layout을 설정해야 하고 서로 다르게 적용되어야 한다.
    예를 들어보자. 메인 Layout은 header, footer, rightmenu, leftmenu Layout을 사용하고 있다. 그 중 headerLayout만 다르고, 나머지 Layout은 같이 쓴다. a.jsp는 headerLayout.jsp라는 헤더 Layout을 사용하고, 그 외 모든 jsp 파일에서는 newHeaderLayout.jsp를 사용한다.
    메인 Layout에 <page:applyDecorator>를 이용하여 특정 템플릿 jsp를 정의한 decorator page을 정의만 할 수 있기 때문에(Tiles처럼 extends를 할 수 없음) a.jsp와 기타 jsp 파일은 서로 다른 메인 Layout을 사용해야 한다.
    <decorator name=".layout.master.main.goldwing.default" page="masterMainLayout.jsp">
    	<pattern>/a.jsp</pattern>
    </decorator>
    
    <decorator name=".layout.master.main.goldwing.default.norightmenu" page="masterMainLayout1.jsp">
    	<pattern>/*.jsp</pattern>
    </decorator>
  • Layout이 필요없는 페이지
    총 3가지 방법이 있다.
    • decorators.xml 파일에서 exclude 태그를 사용
    • jsp파일에서 메타 태그를 이용하여 decorator의 page가 null인 것을 지정
    • EmptyAction을 사용하여 page가 null인 decorator를 패턴으로 지정
      이 중, 첫번째 방법으로 Layout을 적용하는 것을 따로 빼어낼 수 있다.
under.jsp(common_google)
<%@ page language="java" pageEncoding="MS949" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Untitled</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<META name="decorator" content="underLayout"/>
<style>
...
...
decorators.xml
<decorators>
..
    <exclude>
        <pattern>/teasing.gl</pattern>
    </exclude>
...
 </decorators>
xwork.xml
<package name="empty" extends="com.google.news">
  <action name="teasing" class="com.google.news.action.auth.EmptyAction">
    <result name="success">/empty/m.jsp</result>
  </action>
</package>
  • ControllerURL 처리 방법
    • Inceptor 처리
    • 해당 controllerURL의 내용을 클래스로 전환.
  • Action에 Request 파라미터가 추다되어도 Sitemesh 적용
    search.gl action에 지정한 decorator 패턴에 그대로 적용된다.
    search.gl?m=list 의 경우도 <pattern>/search</pattern>와 똑같은 decorator를 사용한다. 따로 설정을 해 줄 필요 없다.

 

Posted by '김용환'
,

배경

웹서버에서 로컬 pc로 파일을 송수신 할 수 어려움이 있어서, 그 방법으로 rz,sz 명령어를 이용하여 SecureCRT를 이용하여 파일을 송수신하도록 한다.

설치

rzsz.zip을 다운받는다.

wget ftp://omen.com/pub/zmodem/rzsz.zip
unzip rzsz.zip
make linux

사용하기

pc로 다운받기. pc의 secureCRT가 설치된 디렉토리의 download디렉토리에 저장된다.

sz file

서버로 올리기.

rz file
Posted by '김용환'
,

배경

tcl기반의 expect 스크립트는 동작이 완료되지 않는다..

특히 기존 스크립트는 set timeout 5를 하지만, 실제로 timeout이 되지 않아서.. 속을 썩이고 있었다.

proc do_restart {HOST_NAME} {
set timeout 5
        spawn /usr/local/bin/rlogin -l www $HOST_NAME
        expect -re "]# "
        send "cd /home/www\r\n"
        expect -re "]# "
        send "exit\r\n"
        #expect -re "]# "
        interact
}

중간에 문제가 생기면, 마치 이런 상태가 된다. 이 프로세스를 죽이려면, 해당 서버에 들어가서 프로세스를 죽여야 하는 불상사가 생긴다.

Connection closed.
spawn /usr/local/bin/rlogin -l www iza123
Last login: Thu Jun 28 18:23:42 from 9.1.0.2
#################################################################
# This Server is assigned Web Service 
#################################################################
exit
^M

그래서, expect에서 문제가 생겼을 때 expect 자체에서 해결방법은 찾기 어려웟, 대신 timeout을 제대로 주어. Shell로 빠져나오게 하는 방법은 알아냈다.

#!/usr/bin/expect -f
proc do_restart {HOST_NAME} {
spawn /usr/local/bin/rlogin -l www $HOST_NAME
        expect -re "]# " {
                send "cd /home/www\r\n"
        } timeout {
 send_user "### Time out during connecting $HOST_NAME!! ###\r\n"
                exit
        }
        expect -re "]# "
        send "exit\r\n"
        #expect -re "]# "
        interact
}

if {$argc < 1} {
 puts "Usage : restart <project name>"
 exit
}

set NUM 1000
set HOST [lindex $argv 0]

puts "Target Servers $HOST"
for {set i 0} {$i < $NUM} {incr i 1} {
    do_restart $HOST
}

puts "Target Servers $HOST, test completed"

expect에서 문제가 생겼을 때 제대로 쉘로 되돌아올 수 있게 할 수 있다.

Connection closed.
spawn /usr/local/bin/rlogin -l www ida2
Last login: Thu Jun 28 18:30:37 from 1.1.0.1
#################################################################
# This Server is assigned Web Service 
#################################################################
### Time out during connecting ida2!! ###
[dev1:/home1/knight/test]

하지만 expect 쉘 자체 성능은 꽤나 좋지 않습니다. 타임아웃으로 shell이 종료되는 것은 expect가 좋지 않다는 것!!

Perl로 이동

expect 기능이 perl에도 있음을 찾아냈다. CPAN이라는 그룹에서 만든 expect는 tcl기반이 아니었다.

Expect기능이 perl의 모듈로 되어 있어서, e65008서버에 expect.pm (perl module)을 설치하였다. 그리고, 이 expect로 사용성 테스트해보았는데, ssh, rlogin으로 spawn을 만번정도 각각 테스트를 해보았는데, 한번도 fail나지 않았다.

아주 훌륭하지 않은가.

Expect 설치

expect 모듈을 설치한다. make install은 root계정으로 해야한다.

wget expect모듈 (wget http://nchc.dl.sourceforge.net/sourceforge/expectperl/Expect-1.20.tar.gz)
tar zxvf Excpect-1.20.tar.gz
cd Expect-1.20
perl Makefile.PL
make
make install

현재 expect 모듈 위치는 다음과 같다.
perl의 expect 모듈을 이용하여 wrapper를 만든다.
path가 걸려있는 /usr/local/bin에 펄 코드를 위치시켜 놓아, shell script에서 바로 호출할 수 있도록 한다.

#!/usr/bin/perl
use Expect;

my $spawn;
my $timeout = 10;
my $result;
my $command;
my $prompt  = '[\]\$\>\#]\s$'; 

if ($#ARGV < 0) 
{
    printUsage();
    exit 0;
} 

while($#ARGV >= 0) 
{
    my $option = shift(@ARGV);
    if($option eq "-s") 
    {
        $spawn = trim(shift(@ARGV));
    } 
    elsif($option eq "-timeout") 
    {
        $timeout = trim(shift(@ARGV));
    } 
    elsif($option eq "-r") 
    {
        $result = trim(shift(@ARGV));
    } 
    elsif($option eq "-c") 
    {
        $command = trim(shift(@ARGV));
    }
}

if (!$spawn) 
{
    print "spawn is not given.";
    exit -1;
}

#if (!$result) 
#{
#    print "expect value is not given.";
#    exit -1;
#}

if (!$command) 
{
    print "command is not given.";
    exit -1;
}

my $exp = Expect->spawn($spawn)
    or die "Cannot spawn ".$spawn.": $!\n";

my $qr_result;
if ($result eq "") {
   $qr_result = $prompt; 
} else {
   $qr_result = $result;
}
print $qr_result;
$exp->expect($timeout,
             [qr "$qr_result" => \&exec],
             [timeout => \&timeouterr],
);

sub timeouterr
{
    die "###### timeout!! ######\n";
}

sub printUsage 
{
    print "Usage\n";
    print "  expect.pl -s [spawn] -r [expect value] -c [command] \n";
    print "  expect.pl -s [spawn] -r [expect value] -c [command] -timeout [timeout time] \n";
    print "\n";
    print " ex) ./expect.pl -s \"rlogin -l knight iabcde.google.com\" -r \"] \" -c \"restart.sh;exit\" -timeout 10 \n";
    print " * default timeout value is 2 seconds.\n";
}

sub exec
{
    my $lexp = shift;
    $lexp->send("$command\n");
    exp_continue;
}

sub debug 
{
    print $_[0]."\n";
}

sub trim($) 
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

자 코드를 만들었으니, 제대로 동작이 되는지 확인한다.

perl -c expect.pl

문제가 없으면, 다음의 결과가 나올 것이다.

[a50236:/usr/local/bin]# perl -c expect.pl
expect.pl syntax OK

하지만, 다음의 종속 모듈때문에 링킹 에러가 나는 경우가 존재한다.

[a50236:/data/env/project]# perl -c /usr/local/bin/expect.pl 
Can't locate IO/Pty.pm in @INC (@INC contains: /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/site_perl/5.8.0 /usr/lib/perl5/site_perl /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi /usr/lib/perl5/vendor_perl/5.8.0 /usr/lib/perl5/vendor_perl /usr/lib/perl5/5.8.0/i386-linux-thread-multi /usr/lib/perl5/5.8.0 .) at /usr/lib/perl5/site_perl/5.8.0/Expect.pm line 22.
BEGIN failed--compilation aborted at /usr/lib/perl5/site_perl/5.8.0/Expect.pm line 22.
Compilation failed in require at /usr/local/bin/expect.pl line 2.
BEGIN failed--compilation aborted at /usr/local/bin/expect.pl line 2.

문제는 IO/Pty.pm 모듈의 종속 모듈인데, 다운받는다.

wget IO-Tty모듈  (wget http://www.cpan.org/modules/by-module/IO/IO-Tty-1.07.tar.gz)

IO/Pty.pm을 설치한다. make install은 root계정으로 해야한다.

wget expect모듈 (wget http://nchc.dl.sourceforge.net/sourceforge/expectperl/Expect-1.20.tar.gz)
tar zxvf Excpect-1.20.tar.gz
cd Expect-1.20
perl Makefile.PL
make
make install

테스트 bash shell script는 다음과 같이 만든다.

[esz18:/home/www/work]# cat expect.sh
#!/bin/bash
eval 'exec expect.pl -s "rlogin -l knight dev1.google.com" -c "exit" -timeout 3'

제약사항

물론 이 코드는 커보러스/rlogin 환경에서만 적절히 사용될 수 있다. 환경에 따라 커스터마이징을 할 필요가 있다.

참조

http://search.cpan.org/~rgiersig/Expect-1.20/Expect.pod
http://iama.rrecktek.com/syslog/installsnare.pl

'perl' 카테고리의 다른 글

bash는 float 변수 연산이 안된다.  (0) 2007.10.21
펄 해쉬 이야기 #2  (0) 2007.10.19
펄 Hash 관련 정보 #1  (0) 2007.10.19
패턴 매칭  (0) 2007.09.23
패턴 매칭  (0) 2007.09.23
Posted by '김용환'
,

multi-part/form-data

web 2007. 8. 23. 03:34

제 자신을 위해서 좀 상세하게 씁니다.

 

<html>
<head>
<title>File manipulation test</title>
</head>

<body>
<form name="uploadForm" method="post" action="upload.jsp">
이름<input type=text name="name"><br>
전화번호
<input type=text name="phone"><br>
사진
<input type=file name="att"><br>
<input type=submit>
</form>
</body>
</html>

 

이것을 가능하게 만들기 위한 방법이 multipart/form-data 이며, 클라이언트(HTML) 서버모듈을 모두 고쳐주어야 하지요.

<html>
<head>
<title>File manipulation test</title>
</head>

<body>
<form name="uploadForm" method="post"
enctype="multipart/form-data"
action="upload.jsp">
이름<input type=text name="name"><br>
전화번호
<input type=text name="phone"><br>
사진
<input type=file name="att"><br>
<input type=submit>
</form>
</body>
</html>

 

서버에 다음의 형식으로 전송됩니다.

-----------------------------7d13603712507ca
Content-Disposition: form-data; name="name"
김용환
-----------------------------7d13603712507ca

Content-Disposition: form-data; name="phone"111-1111

-----------------------------7d13603712507ca

Content-Disposition: form-data; name="att"; filename="a.txt"

Content-Type: text/plain
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

 

스펙(http://www.w3.org/TR/html401/interact/forms.html#adef-enctype)을 보니까 enctype은 다음과 같이 나와있군요.

enctype = content-type [CI]

This attribute specifies the content type used to submit the form to the server (when the value of method is "post"). The default value for this attribute is "application/x-www-form-urlencoded". The value "multipart/form-data" should be used in combination with the INPUT element, type="file".

 

17.13.4에 잘 정리되어 있습니다.. 참고하세요

17.13.4 Form content types

17.13.4 Form content types

The enctype attribute of the FORM element specifies the content type used to encode the form data set for submission to the server. User agents must support the content types listed below. Behavior for other content types is unspecified.

Please also consult the section on escaping ampersands in URI attribute values.

application/x-www-form-urlencoded  

This is the default content type. Forms submitted with this content type must be encoded as follows:

  1. Control names and values are escaped. Space characters are replaced by `+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by `%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., `%0D%0A').
  2. The control names/values are listed in the order they appear in the document. The name is separated from the value by `=' and name/value pairs are separated from each other by `&'.

multipart/form-data  

Note. Please consult [RFC2388] for additional information about file uploads, including backwards compatibility issues, the relationship between "multipart/form-data" and other content types, performance issues, etc.

Please consult the appendix for information about security issues for forms.

The content type "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.

The content "multipart/form-data" follows the rules of all multipart MIME data streams as outlined in [RFC2045]. The definition of "multipart/form-data" is available at the [IANA] registry.

A "multipart/form-data" message contains a series of parts, each representing a successful control. The parts are sent to the processing agent in the same order the corresponding controls appear in the document stream. Part boundaries should not occur in any of the data; how this is done lies outside the scope of this specification.

As with all multipart MIME types, each part has an optional "Content-Type" header that defaults to "text/plain". User agents should supply the "Content-Type" header, accompanied by a "charset" parameter.

Each part is expected to contain:

  1. a "Content-Disposition" header whose value is "form-data".
  2. a name attribute specifying the control name of the corresponding control. Control names originally encoded in non-ASCII character sets may be encoded using the method outlined in [RFC2045].

Thus, for example, for a control named "mycontrol", the corresponding part would be specified:

Content-Disposition: form-data; name="mycontrol"

As with all MIME transmissions, "CR LF" (i.e., `%0D%0A') is used to separate lines of data.

Each part may be encoded and the "Content-Transfer-Encoding" header supplied if the value of that part does not conform to the default (7BIT) encoding (see [RFC2045], section 6)

If the contents of a file are submitted with a form, the file input should be identified by the appropriate content type (e.g., "application/octet-stream"). If multiple files are to be returned as the result of a single form entry, they should be returned as "multipart/mixed" embedded within the "multipart/form-data".

The user agent should attempt to supply a file name for each submitted file. The file name may be specified with the "filename" parameter of the 'Content-Disposition: form-data' header, or, in the case of multiple files, in a 'Content-Disposition: file' header of the subpart. If the file name of the client's operating system is not in US-ASCII, the file name might be approximated or encoded using the method of [RFC2045]. This is convenient for those cases where, for example, the uploaded files might contain references to each other (e.g., a TeX file and its ".sty" auxiliary style description).

The following example illustrates "multipart/form-data" encoding. Suppose we have the following form:

 <FORM action="http://server.com/cgi/handle"       enctype="multipart/form-data"       method="post">   <P>   What is your name? <INPUT type="text" name="submit-name"><BR>   What files are you sending? <INPUT type="file" name="files"><BR>   <INPUT type="submit" value="Send"> <INPUT type="reset"> </FORM>

If the user enters "Larry" in the text input, and selects the text file "file1.txt", the user agent might send back the following data:

   Content-Type: multipart/form-data; boundary=AaB03x   --AaB03x   Content-Disposition: form-data; name="submit-name"   Larry   --AaB03x   Content-Disposition: form-data; name="files"; filename="file1.txt"   Content-Type: text/plain   ... contents of file1.txt ...   --AaB03x--

If the user selected a second (image) file "file2.gif", the user agent might construct the parts as follows:

   Content-Type: multipart/form-data; boundary=AaB03x   --AaB03x   Content-Disposition: form-data; name="submit-name"   Larry   --AaB03x   Content-Disposition: form-data; name="files"   Content-Type: multipart/mixed; boundary=BbC04y   --BbC04y   Content-Disposition: file; filename="file1.txt"   Content-Type: text/plain   ... contents of file1.txt ...   --BbC04y   Content-Disposition: file; filename="file2.gif"   Content-Type: image/gif   Content-Transfer-Encoding: binary   ...contents of file2.gif...   --BbC04y--   --AaB03x--

 

Posted by '김용환'
,

html 4.0의 select-optgroup

web 2007. 8. 23. 01:54

스펙을 보나가 요상한게 있어서..

 

<head>
<body>
<FORM action="http://somesite.com/prog/someprog" method="post">
 <P>
 <SELECT name="ComOS">
     <OPTION selected label="none" value="none">None</OPTION>
     <OPTGROUP label="PortMaster 3">
       <OPTION label="3.7.1" value="pm3_3.7.1">PortMaster 3 with ComOS 3.7.1</OPTION>
       <OPTION label="3.7" value="pm3_3.7">PortMaster 3 with ComOS 3.7</OPTION>
       <OPTION label="3.5" value="pm3_3.5">PortMaster 3 with ComOS 3.5</OPTION>
     </OPTGROUP>
     <OPTGROUP label="PortMaster 2">
       <OPTION label="3.7" value="pm2_3.7">PortMaster 2 with ComOS 3.7</OPTION>
       <OPTION label="3.5" value="pm2_3.5">PortMaster 2 with ComOS 3.5</OPTION>
     </OPTGROUP>
     <OPTGROUP label="IRX">
       <OPTION label="3.7R" value="IRX_3.7R">IRX with ComOS 3.7R</OPTION>
       <OPTION label="3.5R" value="IRX_3.5R">IRX with ComOS 3.5R</OPTION>
     </OPTGROUP>
 </SELECT>
</FORM>
</body>
</head>

 

익스플러어 7.0는 lable값이 보이고,

 firefox 2.0.0.4는 option태그안의 값이 보이는 특성을 가지고 있었다..

 

 

 

 

 

 

Posted by '김용환'
,

어제 스터디하다가 궁금한 내용을 또 찾아봅니다.

 

결론은.. RFC문서에서 정해놓은 BNF 식에 맞춰 해당 content type이 미리 정의되어있습니다.

type := discrete-type / composite-type

discrete-type := "text" / "image" / "audio" / "video" /

                      "application" / extension-token

composite-type := "message" / "multipart" / extension-token

extension-token := ietf-token / x-token

ietf-token := <An extension token defined by a

                    standards-track RFC and registered

                    with IANA.>

 

(ase insensitive하다는 걸 꼭 기억해주세요.)

Text/html은 여기에 나와있지 않지만, ietf-token에서 따라가다 보면 나옵니다. 이 글의 맨 마지막에 나옵니다.

참고로, 확장성을 위해서 ietf-token을 넣어둔것이죠. 그래서 content –type의 전체 리스트는 명확히 한정되어 있지 않습니다..

 

 

추적 내용

 

Html 4.0 스펙을 찾아가서 (http://www.w3.org/TR/html401/types.html#type-content-type) 보았습니다.

6.7 Content types (MIME types)

This type is represented in the DTD by %ContentType;. Content types are case-insensitive.

 

Examples of content types include "text/html", "image/png", "image/gif", "video/mpeg", "text/css", and "audio/basic". For the current list of registered MIME types, please consult [MIMETYPES].

 

Html 4.0 DTD 스펙에는 다음과 같이 content type 정의하고 있습니다. (http://www.w3.org/TR/html401/sgml/dtd.html#ContentType)

<!ENTITY % ContentTypes "CDATA"
    -- comma-separated list of media types, as per [RFC2045]
    -->

 

[RFC2045]

"Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", N. Freed and N. Borenstein, November 1996. Note that this RFC obsoletes RFC1521, RFC1522, and RFC1590.

 

 

IETF 2045

http://www.ietf.org/rfc/rfc2045.txt

제목은 다음과 같습니다.

Multipurpose Internet Mail Extensions  (MIME) Part One:  Format of Internet Message Bodies

 

 

5.1.  Syntax of the Content-Type Header Field

 

   In the Augmented BNF notation of RFC 822, a Content-Type header field

   value is defined as follows:

 

     content := "Content-Type" ":" type "/" subtype

                *(";" parameter)

                ; Matching of media type and subtype

                ; is ALWAYS case-insensitive.

 

     type := discrete-type / composite-type

 

     discrete-type := "text" / "image" / "audio" / "video" /

                      "application" / extension-token

 

     composite-type := "message" / "multipart" / extension-token

 

     extension-token := ietf-token / x-token

 

     ietf-token := <An extension token defined by a

                    standards-track RFC and registered

                    with IANA.>

 

     x-token := <The two characters "X-" or "x-" followed, with

                 no intervening white space, by any token>

 

     subtype := extension-token / iana-token

 

     iana-token := <A publicly-defined extension token. Tokens

                    of this form must be registered with IANA

                    as specified in RFC 2048.>

 

     parameter := attribute "=" value

 

     attribute := token

                  ; Matching of attributes

                  ; is ALWAYS case-insensitive.

 

     value := token / quoted-string

 

     token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,

                 or tspecials>

 

     tspecials :=  "(" / ")" / "<" / ">" / "@" /

                   "," / ";" / ":" / "\" / <">

                   "/" / "[" / "]" / "?" / "="

                   ; Must be in quoted-string,

                   ; to use within parameter values

 

여기서 파라미터는 ; charset=us-ascii 이런거 되겠지요..

Extended-token으로 정의되어 있는 부분은 다음과 설명이 되어 있습니다. X-application-type 이런거 그 예가 되겠지요..iana RFC2048을 참조하라고 되어 있네요.

(1)   Private values (starting with "X-") may be defined

          bilaterally between two cooperating agents without

          outside registration or standardization. Such values

          cannot be registered or standardized.

 

    (2)   New standard values should be registered with IANA as

          described in RFC 2048.

 

 

재미있는 것은 위의 스펙에서는 왜 text/html이 보이지 않는 걸까요?

이건 따로 스펙이 있습니다. (http://www.ietf.org/rfc/rfc2854.txt)

제목 : The'text/html' Media Type

MIME media type name:      text

   MIME subtype name:         html

 

위의 ietf-token 토큰이 여기에 해당되지요..

Html content type 전체 리스트는 구하기 힘들지만, 대충은 알아볼 수 있을 것이라 생각됩니다..

'web' 카테고리의 다른 글

multi-part/form-data  (0) 2007.08.23
html 4.0의 select-optgroup  (0) 2007.08.23
HTTP post 길이 제한??? (있다, 없다)  (0) 2007.08.23
session clustering  (0) 2007.08.22
쿠키 제한 값? size and length of cookie limit  (0) 2007.08.22
Posted by '김용환'
,

포스트 요청은  바디안에 정보가 들어가 있네요.

 

HTTP 1.1 길이 제한없습니다. 그러나, Http 1.0 길이 제한 있을 있습니다.

스펙상 content-length값을 받기 때문에 해당값이 없으면, 문제가 생길 있습니다. 또한 content-length값을 user agent 어떻게 받아들이냐에 따라 달라질 것입니다. , 유효값의 범위가 명확지 않기 때문에 user agent 다르게 처리할 있는 것이지요.

그래서, http 1.0 쓰는 브라우져 혹은 서버에서는 이번 문제가 있어서 파일이 multi-part 전송에 에러가 있지요.(전혀 그런 얘기를 들어본 있어요..)

 

참조

http://news-wap.com/ResearchTopic/summer2003/j2ee/webcontainer/http.htm

 

POST 요청 메소드

POST 메소드는 일반적으로 동적 자원에 접근하기 위해 사용된다. 전통적으로, POST 요청은 요청 종속적인 정보를 전송하기 위한 수단이며 서버에게 상당히 많은 양의 복잡한 정보를 전송할 필요가 있을 사용한다.

POST 요청은 multi-part 메시지들을 요청 몸체 속으로 캡슐화한다. 예를 들어, 텍스트나 이진 파일들을 업로드하기 위해 POST 요청을 사용할 있다. 이와 유사하게, 직렬화 가능한 자바 객체나 미가공 바이트들을 서버에게 보내기 위해 애플릿 내에서 POST 요청을 사용할 있다. 그래서 POST 요청은 요청 내용에 따라 폭넓은 선택을 제공한다.

GET POST 요청에는 차이가 있다. GET 요청에서는 요청 매개변수들이 요청 URL 추가된 질의 문자열로 전송된다. 그러나, POST 요청에서는 요청 매개변수들이 요청의 몸체 내에 넣어져서 전송된다. 이것은 가지 결과를 초래한다. 먼저, GET 요청은 완전한 요청 정보를 URL 자체에 추가시키기 때문에, 브라우저들이 페이지를 북마크하여 나중에 재방문할 있도록 해준다. 타입과 요청 매개변수들이 얼마나 민감한 것인가에 따라 바람직할 수도 있고 그렇지 않을 수도 있다. 번째로, 어떤 서버들은 요청 URL 길이에 대한 제한을 있다. 이러한 제한은 요청 URL 추가될 있는 정보의 양을 제한한다. 하지만 HTTP1.1 최대 길이 제한을 두고 있지 않다. HTTP1.0 서버/클라이언트는 매우 길이에 대해서는 지원하지 않을 수도 있다.

 

 

참조 HTTP 1.0 스펙

http://raonism.net/CSdb/protocol/rfc1945-kr.html

 

8.3 POST

POST 요구 메시지는 메시지의 entity body에 포함되어 있는 자원을 Request-Line에 있는 Request-URI에 지정되어 있는 대로 서버에서 수용해달라고 요청할 때 쓰인다. , POST는 다음과 같은 기능을 수행하기 위한 한 가지 방법으로 설계되었다.

  • 기존 문서에 주석을 붙일 때 (오홋)!!!
  • BBS 게시판, 메일링 리스트, 뉴스그룹, 또는 글 모음 장소 등에 글을 올릴 때
  • 어떤 프로그램의 실행을 위해 form과 같은 특정 규격의 데이타를 넘겨줄 때
  • 부가적인 동작을 통해 데이타베이스를 확장하고자 할 때

POST method에 의해 수행되는 실제 동작은 서버에 의해 결정되고 통상 Request-URI에 의해 좌우된다. 포스팅되는 대상은, 하나의 화일이 어느 디렉토리에 자리하게 되고 뉴스가 포스팅되는 뉴스그룹에 올려지고 레코드가 데이타 베이스가 등록되는 등과 똑같은 방식으로 지정된 URI에 놓이게 된다.

POST는 대상 서버에 하나의 자원으로서 생성될 필요가 없고 추후의 참조를 위해 접근 가능해야 할 필요도 없다. , POST method에 의해 수행되는 동작은 포스팅 되는 entity URI에 의해 지정될 수 있는 자원이 아니어도 된다는 것이다. 이 경우의 적절한 응답 결과 코드는 200 (ok) 또는 204 (no content)가 될 것인데, 응답 메시지에 entity가 포함되어 있느냐 있지 않느냐에 따라 구분이 될 것이다. 어떤 자원이 대상 서버에 생성되는 경우라면 응답 결과 코드는 201(created)이 되어야 하고 상태 정보나 생성된 새 자원에 대한 정보를 알려주는 entity가 포함되어 있어야 한다.

HTTP/1.0의 모든 POST 요구 메시지에는 Content-Length가 반드시 있어야 하며, 서버가 이에 대한 정보를 확보하지 못하게 되면 400(bad request) 메시지를 응답해야 한다.

(A valid Content-Length is required on all HTTP/1.0 POST requests. An HTTP/1.0 server should respond with a 400 (bad request) message if it cannot determine the length of the request message's content.)

응용 프로그램에서는 POST 요구 메시지에 대한 응답을 캐싱할 필요가 없다. 왜냐하면 서버가 추후의 요구 메시지에 대한 응답으로서 똑같은 응답을 할 것인지 알 수가 없기 때문이다.

 

여기서 저는 Content-length 길이에 대해서는 다음에 대해서 나와있지만, 유효값(0이상의 값, 적용되지 않을 때 정책은 나와있음) 은 나와있지 않습니다.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

 

 

 

HTTP 1.1

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

 

POST파트에 HTTP 1.0Content내용이 빠져있습니다. 그래서 길이 제한이 없다고 하는군요.

'web' 카테고리의 다른 글

html 4.0의 select-optgroup  (0) 2007.08.23
HTTP content type(text/html) 전체 리스트 뽑아보기  (0) 2007.08.23
session clustering  (0) 2007.08.22
쿠키 제한 값? size and length of cookie limit  (0) 2007.08.22
apache redirect 설정.  (0) 2007.06.14
Posted by '김용환'
,

session clustering

web 2007. 8. 22. 19:56

Session clustering에 대한 조사입니다.

 

Session clusteringWAS에서 대부분 제공되고 있나 봅니다. 톰캣, 웹 스피어 등등

 

Session clustering의 특징을 요약해 보겠습니다.

-       여러대의 JVM에서 돌아가는 서버들이 하나의 공통된 HTTP Session table을 사용한다.

-       Load balancing도 같이 된다. (의미 때문에)

-       Server 2.2 스펙에서는 하나의 세션에 대해서 여러 리쿼스트가 여러 jvm에 있어서는 안된다고 되어 있어서 각 WAS별로 솔루션을 제공하고 있다.

n  ) websphere에서는 클러스터내의 한 서버에서 session 처리가 실패하면 클러스트터내의 다른 서버로  session table을 보내고, session처리가 가능하게 하도록 함.

 

http://publib.boulder.ibm.com/infocenter/wasinfo/v4r0/index.jsp?topic=/com.ibm.websphere.v4.doc/wasa_content/001102.html

0.11.2: What is session clustering?

The Session Manager session support allows multiple application server instances to share a common pool of sessions, known as a session cluster. A session cluster is the binding of the session to more than one active application server Java virtual machine (JVM) sharing a common HTTP session table.

The implementation of clustering in IBM WebSphere Application Server allows failover. This preserves session data integrity and the common pool of sessions in the event of a system failure in one or more of the clustered JVMs running servlets within a group of servers.

The session clustering implementation also allows load balancing, whereby the session workload is distributed among the JVMs that comprise the cluster.

Session clustering requires an affinity mechanism so that all requests for a particular session are directed to the same Java Virtual Machine (JVM) in the cluster. This conforms to the Servlet 2.2 Specification in that multiple requests for a session cannot coexist in multiple JVMs. One such solution provided by IBM WebSphere Application Server is Session Affinity in a server group; this solution is available as part of the WebSphere plug-ins for Web servers. If one of the servers in the cluster fails, it is possible for the request to be rerouted to another server in the cluster. The new server can access session data from the common SESSIONS table. This is transparent to the servlet, browser, and user.

The same Web application must be present on each of the servers that can access the session. This can be accomplished by installing a Web module into a server group. Each of the servers in the group can then access the Web application; if a persistence mechanism is used, sessions can fail over between servers.

Manually cloned environments (that is, those not in WebSphere server groups) can share session data between servers if the identical Web application is installed with the same virtual host name on each of the servers. These environments also require an affinity mechanism to ensure that the session is active in only one JVM at any given time.

If the JVM fails during the writing of session information in the session database, the update to the database does not get committed. Still, the common pool of sessions continues to function, including the session being processed at the time of failure.

For non-catastrophic failures (such as when the JVM remains functional), any session changes that cannot be completed are rolled back. The session reverts to its state prior to the start of the persistence operation. If instead the write operation is completed successfully and the changes are committed, the session is still accessible, regardless of the failure.

 

<톰캣 5>

http://tomcat.apache.org/tomcat-5.0-doc/cluster-howto.html

 

serialization을 이용하여 클러스터링을 할 수 있다.

·         All your session attributes must implement java.io.Serializable

·         Uncomment the Cluster element in server.xml

·         Uncomment the Valve(ReplicationValve) element in server.xml

·         If your Tomcat instances are running on the same machine, make sure the tcpListenPort attribute is unique for each instance.

·         Make sure your web.xml has the <distributable/> element

Cluster Architecture

Component Levels:

        Server

          |

        Service

          |

        Engine

       /     \

   Cluster ReplicationValve

      |

   Manager

      |

  Session

 

 

TODO

현재 이 것을 사용할 여부를 테스트를 해봐야 한다.

 

쿠키 베이스 단위로 우리는 진행중이지만, 클러스터링을 통해서 jvm단에서 공유하는 common session table을 넘겨주고 처리하는 작업이 부하를 많이 줄 수 있는 상황인데..

좀 더 생각해보면, 중간에 cache server를 두어서 common session Table을 여러 jvm에서 같이 보는 것은 어떨까??

그러면, 쿠키 베이스로 가지 않고도 할 수 있지 않을까??

Posted by '김용환'
,