2007년 9월 28일 금요일

Java 중의 Annotation

Java 중의 Annotation 해석

프로그래밍, 특히 자바 프로그래밍의 최신 경향 중 하나는 metadata를 사용한다는 것이다. 메타데이터는 간단히 말해서 데이터에 대한 데이터이다. 메타데이터는 문서화에 사용될 수 있고 코드 의존성을 트래킹하는데 사용되며 심지어 초기 컴파일 시간 체크를 수행 할 때도 사용될 수 있다.

메타데이터의 가치

일반적으로 메타데이터의 효용은 세 가지로 나눌 수 있다. 문서화, 컴파일러 체크, 코드 분석. 코드 레벨의 문서화는 가장 자주 인용되는 사용법이다. 메타데이터는 메소드가 다른 메소드에 의존하고 있다는 것을 가르키는 유용한 방법을 제공한다. 또한 그들이 불완전한지, 특정 클래스가 또 다른 클래스를 레퍼런싱 하는지 등을 가르킨다. 이는 정말로 유용하지만 문서화는 메타데이터를 자바에 추가하는 것과 가장 관련이 적은 항목이다. 코드의 문서화에 있어서는 Javadoc이 사용이 쉽고 강력한 방식을 제공하고 있기 때문이다.

그렇다면 Annotation은 무엇인가?

어노테이션은 프로그램의 요소 예하면 클래스, 속성, 파라미터, 지역변수들을 연결시키는 연결고리로써 어노테이션을 해줌으로써 이런 요소들에 대한 메타정보를 클래스내에 포함시켜 관리할 수가 있다.

간단한 Annotation을 정의해보자!

어노테이션 정의는 상당히 쉽다고 볼수 있다. 어찌보면 Interface정의와 아주 흡사하다. @ + Annotation 유형 + ( 콤마로 분할된 name - value 쌍 ).
아래에 간단한 예를 보여주겠다.

소스열기

@Retention(RetentionPolicy.RUNTIME) 이 어노테이션은 우리가 정의한 SimpleAnnotation을 Class파일속에 넣어서 저장하고 VM이 구동될때 어노테이션을 자동으로 로딩하겠다는 명시이다.
또한 @Target(ElementType.METHOD)는 우리가 아래에 정의하는 어노테이션들을 클래스속의 메소드들을 묘사하는데 사용이 되여진다는 명시이다.

정의한 Annotation을 사용해보자!

소스열기

위에서 우리는 정의된 어노테이션이 메소드를 묘사할때 사용될것이라고 명시했었다. 따라서 이렇게 정의된 어노테이션을 사용할때는 반드시 메소드앞에 정의된 어노테이션을 사용하여야 한다. (만약 필드에 대하여 묘사를 하겠다고 정의를 하였다면 필드가 정의되기전에 이미 어노테이션으로 해당 필드에 대하여 묘사를 해야 한다.)

실행중인 프로그램에서 Annotation을 접근해보자!

일단 프로그램내의 요소와 Annotation이 연결이 되여지면 VM실행중 특정된 요소에 대한 정보를 알아낼수 있다. 여기서 보통은 Reflection을 이용하여 이런 정보에 대한 접근을 시도한다.
interface:java.lang.reflect.AnnotatedElement를 이용하여 Annotation에 대한 접근을 시도해보자...
java.lang.reflect.AnnotatedElement 인터페이스에는 아래와 같은 메소드들이 정의되여져 있다.

  1. boolean isAnnotationPresent(Class annotationType)
    특정된 요소에 Annotation이 존재 여부를 반환한다. 만약 Annotation이 존재하면 true를 반환하고 아니면 false를 반환하겠다.
  2. T getAnnotation(Class annotationType)
    특정된 요소에 Annotation이 존재하면 Annotation을 반환하고 아니면 null을 반환한다.
  3. Annotation[] getAnnotations()
    해당 요소에 존재하는 모든 Annotation들을 반환한다. (private은 제외)
  4. Annotation[] getDeclaredAnnotations()
    해당 요소에 존재하는 모든 Annotation들을 반환하다. (private도 포함)

소스열기

2007년 9월 14일 금요일

prototype 1.5.1.1 Javascript 프레임웍 사용기 - 제1부

복잡한 JavaScript는 이제 가라!!! 

사용자 삽입 이미지

Prototype LOGO

Prototype 프레임웍은 Samstephenson이 제작한 Javascript 프레임웍이다. 그 목적은 Web 2.0으로 가면서 복잡하게 엉킨 Javascript를 간소화시키기 위함이다. Prototype은 스크립트 기반의 언어의 제한을 뛰여넘어 일반 컴파일 언어 (예하면, C++, Java와 같은) 수준에서 지원하고 있는 상속 및 추상클래스까지도 구현가능하게끔 하였다.
prototype.js는 현재 웹어플리케이션 프로토타입 개발용으로 많은 관심을 받고있는 프레임워크인 RubyOnRails에 통합되어 있으며, script.aculo.us, Rico 등과 같은 다양한 자바스크립트 프레임워크에서도 라이브러리 형태로 사용되어지고 있다.
예제와 참조문서를 읽었을때, Ruby프로그래밍 언어에 친숙한 개발자는 Ruby의 내장 클래스와 이 라이브러리에 의해 구현된 많은 확장 사이의 의도적인 유사성을 알아차리게 될것이다.
그럼 아래에 prototype 을 좀 더 쉽게 사용할 수 있게 끔 가이드(?) 하기 위하여 그에 대한 간단한 설명을 첨부할가 한다.

1. 기초 유틸리티

1.1. Prototype 객체

속성 및 방법
Version : 문자열은 prototype 프레임웍의 버전을 명시해준다.
ScriptFragment : 스크립트의 정규모드 유효성 체크를 해준다.
emptyFunction(): 빈 함수를 나타낸다. Function() {}
K(x): K메소드, 파라미터 자신을 리턴한다.
1.5부터는 JSON을 지원하면서 기능이 막강해졌다.

소스 열기

1.2. Class 객체

Class객체는 오로지 하나의 작용밖에 없다. 그건 바로 클래스정의에 대한 지원이다.

소스 열기

가장 보편적으로 사용하는 방식을 예로 들면 다음과 같다.

예제 열기

윗 예제를 보면 Animal이라는 클래스를 Class.create라는 메소드를 통하여 생성한다.
다음 initialize 생성자를 만들고 name, sound를 인자로 입력를 받는다.
밑에 보면 Dog라는 클래스도 생성해 주고 있는데 실제상 이 Dog클래스는 Animal 클래스를 상속받고 있는다.
Dog.prototype = Object.extend(new Animal(), 단순히 extend 메소드를 통하여 상위클래스를 쉽게 상속받을수가 있다.

1.3. Object 클래스에 대한 확장

Object는 모든 객체의 기초로 되는 클래스이다. 즉 모든 객체는 Object클래스를 상속받아서 구현이 되여진다. 1.5버젼으로 업그레드 되면서 Prototype은 Object클래스에 4개의 static 메소드를 추가했다.
static 메소드 그 첫번째:
syntax => Object.extend(destination, source)
설명 => source 파라미터의 모든 속성을 destination에 넘겨준다. 이렇게 함으로써 destination이 source상속 받은것과 같은 효과를 나타낸다.
static 메소드 그 두번째:
syntax => Object.inspect(object)
설명 => 파라미터로 지정된 오브젝트로 자신의 inspect메소드를 구현해야 한다.
static 메소드 그 세번째:
syntax => Object.clone(object)
설명=> 원 오브젝트의 모든 속성을 그대로 복사하여 새 오브젝트에 넣어둔다. 하지만 이런 복사는 deep복사인거 아니라 shallow복사이다.
Syntax => Object.keys(object)
설명=> 모든 오브젝트를 hash로 간주하여 처리하며 결과적으로 이런 속성들의 이름을 리턴한다. 하지만 추가된 요소들의 정열순서는 보장할수 없다. 사용자가 만약 각 요소가 정열이 되여질것을 원하면 자기 스스로 이부분의 코딩을 해야 한다.
Syntax => Object.value(object)
설명=> 모든 오브젝트를 hash로 간주하여 처리하며 결과적으로 이런 속성들의 값을 리턴한다.
Syntax => toJSON()
설명 => JSON 문자열을 리턴한다.

소스 열기

Clone예제 열기

Key예제 열기

Value예제 열기

1.4 Number 클래스 확장
Number은 모든 숫치유형의 기본 클래스이며 prototype에서는 그 인스턴스에 대하여 확장을 진행하였다.
syntax => toColorPart()
설명 => RGB색상을 16진법 색상 표시법으로 변환한다.
예 => var cRed=255, cGreen=100, cBlue=22;
var hexColor="#"+cRed.toColorPart() + cGreen.toColorPart() + cBlue.toColorPart();
syntax => succ()
설명 => 숫치에 1을 합하여 리턴한다.
syntax => times(iterator)
설명=> 여기서 iterator은 함수이며 iterator라는 함수를 여러번 수행하고 싶으로 이 메소드를 사용한다.

소스 열기

1.5 Try 객체
이 객체는 오로지 하나의 메소드만 제공해준다. these메소드 사용시 넘겨받은 인수는 메소드 핸들러 여야만 한다. 그 작용은 맨 처음 성공적으로 실행된 메소드의 반환치를 리턴하는것이다.

소스 열기

2 기초 도구류
이부분에서는 prototype 1.4.0 프레임웍의 일부 핵심 툴들을 정의하고 있으며 전체 프레임웍의 중요한 구성 부분이다.

2.1 $() 함수
$() 함수는 매우 빈번하게 사용되는 DOM의 document.getElementById() 함수에 대한 편리한 단축함수이다. DOM 함수처럼, 이것은 인자로 던져진 id를 가진 해당 엘리먼트를 반환한다. 하지만 DOM함수와는 달리, 이것은 여러개의 id를 사용할수 있는데, 이 경우에 $()는 요청된 엘리먼트들을 가진 Array 객체를 반환하게 된다. 이 함수의 다른 장점으로 id 문자열이나 엘리먼트객체 자체를 인자로 가질 수 있는데, 이것은 인자 형태를 가질수 있는 다른 함수를 생성할 때 매우 유용하게 사용되어 질 수 있다.

소스 열기

예제 열기

2.2 $F() 함수
$F() 함수는 또다른 유용한 단축함수로, 텍스트박스나 드랍다운 리스트와 같은 입력 컨트롤의 값을 반환한다. 이 함수는 엘리먼트 id나 엘리먼트객체 자체를 인자로 가질수 있다.

소스 열기

예제 열기

2.3 $A() 함수
$A() 함수는 전달된 한 개의 인자를 배열로 변환한다. Array 클래스에 대한 확장으로 이 함수는 열거가능한 목록이라면 그것을 쉽게 배열로 변환할 수 있더. 예를 들면, DOM 객체의 NodeLists를 효과적으로 배열로 바꾸는데 유용하게 쓰일 수 있다.

소스 열기

예제 열기

2.4 $R() 함수
$R() 함수는 new ObjectRange(lowerBound, upperBound, excludeBounds)과 동일한 단축함수이다. 아래는 each 메소드를 통해 반복(iterators)의 사용법을 보여주는 간단한 예제이다.

소스 열기

예제 열기

2.5 String 클래스에 대한 확장

Javascript에서 모든 문자열은 모두 String 클래스의 인스턴스들인바 이런 인스턴스들에 대한 오버레이션을 간편화하기 위하여 몇가지 메소드들을 제공하였다.

2.5.1 stripTags 메소드
태그를 없애는메소드로서 이정규 표현이라면 올바르게 태그를 없앨 수 없는 경우가 있다.

소스 열기

2.5.2 stripScripts 메소드
캐릭터 라인(this)으로부터,script블록을 삭제하는 메소드이다. 전술 Prototype오브젝트의ScriptFragment 프롭퍼티로부터 script 블록의 정규 표현 캐릭터 라인을 취득하고 있다.

소스 열기

2.5.3 extractScripts 메소드
캐릭터 라인(this)의 모든 script 블록의 내용을, 배열에 격납해 반환하는 메소드이다.
Prototype.ScriptFragment를 사용해, 글로벌 매치하는 정규 표현 오브젝트와 싱글 매치하는 정규 표현 오브젝트를 작성한다. m수식자는 무의미한 생각이 든다.
캐릭터 라인(this)으로부터 모든 script 블록을 추출해, 더욱 각각으로부터 script 블록의 내용(코드 부분)을 추출해 배열에 격납해, 반환하고 있다.
인수로 지정된 함수를, 배열 요소 모든 것을 차례로 인수로 지정해 실행해, 결과를 배열에 격납해 반환한다.

소스 열기

2.5.4 evalScripts 메소드
캐릭터 라인(this)으로부터, extractScripts 메서드로 취득한 script코드 모든 것을, eval함수로 실행하고 있다.
요소의 innerHTML 프롭퍼티에 소스를 설정하면(자), 태그등이 eval되여 실행이 되여지겠지만 script 블록은 실행되지 않는다. 이때 이런 소스를 실행시키는데 evalScripts 메서드가 도움이 된다.

소스 열기

2.5.5 escapeHTML 메소드
캐릭터 라인(this)의 HTML문 자를 이스케이프 해 반환한다. 즉 「text」(이)라고 하는 캐릭터 라인을 「<p>text</p>」로 변환한다.
예하면 "<"를 "&lt;"로 변환한다.

소스 열기

2.5.6 unescapeHTML 메소드
escapeHTML 메서드의 역.캐릭터 라인(this)의 태그를 없앤 다음, 안 이스케이프 해 반환한다.
예하면 "&lt;"를 "<"로 변환해준다.

소스 열기

2.5.7 toQueryParams 메소드
우선, 캐릭터 라인(this)을 쿠에리 캐릭터 라인으로 간주해, 선두 「?」보다 이후의 캐릭터 라인을 「&」으로 분할해 배열에 격납한다. inject 메서드는 Array 클래스의 추가 메서드이다. 제2인수의함수의 제2 인수(pairString)에 배열의 각 요소의 값이 들어온다.처리의 결과를 제일 인수(params)에 격납해 반환한다.이것을 반복해, 최종적인 결과를 격납한 것(params)를 반환합니다.inject의 제일 인수(은)는 반환치의 초기치이다.
즉 여기에서는, 배열의 각 요소의 「name=value」의name를 인덱스,value를 값으로 한 커스텀오브젝트가 반환되게 된다.
예를 들자면
var s = "sid=10&page=2&author=nate";
var qp = s.toQueryParams();
qp의 구조는
{sid:10,page:2,author:'nate'}
가 되여지겠다.

소스 열기

2.5.8 toArray 메소드
캐릭터 라인(this)을, split로 1 문자씩 배열에 격납해 반환한다. 단락 캐릭터 라인에 공문자열을 지정하는 것으로 1 문자씩에 분할한다.
예를 들면
var t = "abc";
var s = t.toArray();
결론적으로 s에 ['a','b','c']이라는 배열로 만들어 진다.

소스 열기

2.5.9 camelize 메소드
캐릭터 라인(this)이 「aaa-bbb」형식일 때, 「aaaBbb」형식으로 변환해 반환한다.CSS프롭퍼티를 오브젝트 모델 구문으로 변환하는 경우에 편리하다. 실제, 후술 하는 Element 오브젝트의 getStyle 메서드로 사용되고 있다.

소스 열기

2.5.10 capitalize 메소드
문자열중 맨 처음 캐릭터만 대문자로 표시하고 나머지는 모두 소문자로 변환시켜준다.
예하면 기입된 문자열이 "yust"라면 capitalize를 거치면 "Yust"로 된다.

소스 열기

2.5.11 startsWith 메소드
문자열 첫 시작부분에 특정된 문자패턴이 있는지를 체크하여 있으면 true을 반환하고 아니면 false를 반환한다.
var str = "CIM campus integrity movement";
str.startsWith('CIM');
이럴경우 true를 반환하게 된다.

소스 열기

2.5.12 endsWith 메소드
문자열 마지막부분에 특정된 문자패턴이 있는지를 체크하여 있으면 true을 반환하고 아니면 false를 반환하다.
var str = "CIM campus integrity movement";
str.endsWith('ment');
이럴경우 true를 반환하게 된다.

소스 열기

2.5.13 dasherize 메소드
문자열중 "_"를 일괄적으로 "-"로 바꿔준다.
예하면
'border_bottom_width'.dasherize();
// -> 'border-bottom-width'

소스 열기

2.5.14 blank 메소드
문자열이 공백이거나 공백만 있을경우 true를 반환한다.
''.blank();
//-> true
' '.blank();
//-> true
' a '.blank();
//-> false

소스 열기

2.5.15 empty 메소드
문자열이 공백이면 true를 반환한다.
''.empty();
//-> true
' '.empty();
//-> false

소스 열기

본 포스트는 계속 업뎃이 되여집니다...

Prototype 은 어떻게 DOM에 대한 확장을 하였는가?

이제 복잡한 DOM코딩은 가라! Prototype만으로 이를 해결한다!

사용자 삽입 이미지
사실상 Prototype에서 가장 주목을 끄는것은 그것이 DOM에 대한 확장성 이다. Prototype은 여러가지 간편한 메소드 (예하면 $()과 같은) 사용자한테 제공하여 DOM에 대한 코딩을 단순화 시켰다.
간단한 예를 들자면 사용자는 단순히 $('comments').addClassName('active').show() 와 같은 코드를 통하여 쉽게 id가 comments인 요소에 active스타일 시트를 추가하고 보여지게끔 한다.(당연 그전에는 hidden상태였겠지)
그렇다면 prototype은 어떻게 이런 쉬운 코딩만으로 DOM에 대한 접근을 가능하게 했을가?

Element.extend() 메소드

거의 대부분의 DOM 메소드들은 Element.Methods 라는 메소드에 의하여 캡슐화 되여지고 이런 엘리먼트 객체로 복사가 되여져 사용이 되여진다.

Element.hide('comments');
var div_height = Element.getHeight(my_div);
Element.addClassName(
'contactform', 'pending');


윗소스를 보면 comment 엘리먼트를 DOM에서 획득해오고 그에대하여 CSS스타일을 적용하는 것이다.
사실 윗소스도 상당히 간편하지만 prototype의 매력은 이뿐만이 아니다.
아래에 다른 예를 하나 더 추가하겠다.

var my_div = document.createElement('div');

Element.extend(my_div);
my_div.addClassName(
'pending').hide();

// insert it in the document
document.body.appendChild(my_div);


소스를 간단히 분석해보면 my_div라는 엘리먼트를 만든다.
다음 Element.extend 메소드에 해당 엘리먼트를 인자로 넘겨주면 Element.extend의 모든 메소드들이 해당 객체에 복사되여져 온다. 이로써 우리는 별도로 메소드 구현이 필요 없이 이미 구현이 되여진 메소드를 그냥 가져다 쓸수 있다.
하지만 실제 구현시 구지 이런 방식으로 엘리머트들에 메소드들을 복사 할 필요가 없다. 단지 $() 를 사용하여서 위와 같은 메커니즘으로 이 모든것을 구현할수 있다.

가령 contactform있다고 가정할 때 이 폼속의 모든 필드 값들을 QueriedString으로 만들어서 넘기고 싶으면 단지 아래 방식처럼 코딩하면 된다.

var contact_data = $('contactform').serialize();


$()를 통하여 contactform은 Element.extend의 모든 메소드들을 상속을 받게 되는데 여기서 serialize가 바로 그중에 한 메소드이다. 이 메소드의 작용은 예전에 포스트내용을 참조하게 쉽게 알수 있는데 바로 폼내의 모든 엘리먼트를 쿼리드스트링으로 만드는 작용을 한다.

Element.addMethods()를 이용하여 사용자 메소드를 추가할수 있다.

Prototype에서 제공해주는 메소드만 사용하여 일부 문제는 해결할수 있을지 모르지만 모든 문제는 해결할수 없다. 즉 사용자 정의 메소드를 추가하고 싶어질거다. prototype은 이런점까지 고려하여 메소드 추가확장기능을 지원한다.

var MyUtils = {
    truncate:
function(element, length){
        element = $(element);
       
return element.update(element.innerHTML.truncate(length));
    },
    updateAndMark:
function(element, html){
       
return $(element).update(html).addClassName('updated');
    }
}

Element.addMethods(MyUtils);

// now you can:
$('explanation').truncate(100);


MyUtils는 사용자 정의 클래스로서 사용자 정의 메소드들을 포함하고 있다. truncate와 updateAndMark 두메소드는 사용자 정의 메소드들로써 Element.addMethods를 통하여 prototype의 Element 클래스에 추가되여 질수 있다.

2007년 9월 10일 월요일

AbstractWizardFormController 사용기

단계별 Form 처리 컨트롤 - AbstractWizardFormController

소프트웨어 설치시 보면 한방에 설치가 되여지는것이 아닌 여러단계에 거쳐서 설치가 이루어진다. 보통보면 다음을 클릭하여 다음단계로 이동하고 완료를 클릭하여 설치를 끝마친다.
Spring Web MVC에도 이와 흡사한 방식으로 처리해주는 Controller가 있다.
그것이 바로 AbstractWizardFormController이다.

AbstractWizardFormController는 SimpleFormController와 비슷하며 그 메소드 구성만 봐도 거의 엇비슷한것을 발견할수 있다.
AbstractWizardFormController와 기타 컨트롤러 사이의 구별점을 열거하면 다음과 같다.

다시말하자면 AbstractWizardFormController는 요청을 통해 전해지는 사용자 입력값으로 폼 객체를 자동으로 설정하는 HTTP 폼 컨트롤러이다. 요청마다 새로운 폼 객체 인스턴스를 사용할 수도 있지만, sessionForm 속성을 true로 설정하면, 여러 차례의 요청 가운데서 객체를 공유할 수도 있다.

public AbstractWizardFormController() {
 // AbstractFormController sets default cache seconds to 0.
 super();

 // Always needs session to keep data from all pages.
 setSessionForm(true);

 // Never validate everything on binding ->
 // wizards validate individual pages.
 setValidateOnBinding(false);
}

  1. 폼 객체의 작용범위는 Session이며 sessionForm의 속성은 true이다. 왜냐면 여러페이지에 거쳐서 데이타를 손실없이 가지고 가야하니깐 request영역내에서만 데이타를 유지시키는것은 불가능한것이다.
  2. 또한 폼 데이타가 바인딩될때 데이타유효성체크를 하지 않는다. 즉 validateOnBinding속성이 false로 된다.
  3. 여러개 폼 뷰사이에서 전환이 가능하다.
  4. 상당히 명확한 웍프로세스 템플릿 메소드들을 가지고 있다. 예로, 처리를 완료할때는 processFinish()메소드를 호출하고 처리를 취소할때는 processCancel()메소드를 호출하면 된다.

위에 몇가지 사항들을 제외하고도 실제 해당 컨트롤러를 사용하기 위해서는 알아둬야 할점이 몇가지 있다.

/**
 * Parameter triggering the finish action.
 * Can be called from any wizard page!
 */
public static final String PARAM_FINISH = "_finish";

/**
 * Parameter triggering the cancel action.
 * Can be called from any wizard page!
 */
public static final String PARAM_CANCEL = "_cancel";

/**
 * Parameter specifying the target page,
 * appending the page number to the name.
 */
public static final String PARAM_TARGET = "_target";

/**
 * Parameter specifying the current page as value. Not necessary on
 * form pages, but allows to properly handle usage of the back button.
 * @see #setPageAttribute
 */
public static final String PARAM_PAGE = "_page";

내부적으로 프로세스 플러우를 처리하는 문자열 상수를 가지고 있는데 그것들로는
_finish, _cancel, _target, _page이다.
_finish는 임의의 폼페이지에서 호출이 되여질 수 있으며 폼 wizard를 끝마치고 싶을 때 호출한다.
_cancel또한 임의의 폼페이지에서 호출이 되여질 수 있으모 폼 wizard를 취소하고 싶을 때 호출한다.

/**
 * Set the wizard pages, i.e. the view names for the pages.
 * The array index is interpreted as page number.
 * @param pages view names for the pages
 */
public final void setPages(String[] pages) {
 if (pages == null || pages.length == 0)  {
  throw new IllegalArgumentException("No wizard pages defined");
 }
 this.pages = pages;
}

위저드 페이지를 세팅하는 메소드이다. 세팅된 페이지는 문자열 배열에 들어가지게 되고 문자열배열의 인덱스번호가 위저드 페이지 번호가 되여진다.

 /**
  * Set if "dirty back" is allowed, that is, if moving to a former wizard
  * page is allowed in case of validation errors for the current page.
  * @param allowDirtyBack if "dirty back" is allowed
  */
 public final void setAllowDirtyBack(boolean allowDirtyBack) {
  this.allowDirtyBack = allowDirtyBack;
 }

 /**
  * Set if "dirty forward" is allowed, that is, if moving to a later wizard
  * page is allowed in case of validation errors for the current page.
  * @param allowDirtyForward if "dirty forward" is allowed
  */
 public final void setAllowDirtyForward(boolean allowDirtyForward) {
  this.allowDirtyForward = allowDirtyForward;
 }

dirty back와 dirty forward 두가지 속성은 기본 dirty back = true로, dirty forward = false로 설정이 되여져 있는데 그 의미는 현재 머물고 있는 페이지에 validation 오류가 존재할 시 앞 혹은 뒤 페이지로의 이동 허용여부를 세팅한다. dirty back = true로 되여져있으면 현재 페이지에 validation 오류가 있을시 뒷페이지의 이동을 허용한다는 뜻이 되겠다.