DSL - Tistory

Download Report

Transcript DSL - Tistory

Domain Specific Language
socurites
도입 예제 – 보안 시스템
OpenIt 보안 시스템
이 회사에서는 고객 사업장에 무선 네트워크를 구성하고, 작은 장치들을 설치한다.
각 장치는 흥미로운 일이 일어날 때 4글자로 된 메시지를 보낸다.
예를 들어 서랍에 장착된 센서는 서랍이 열릴 때 <D2OP>라는 메시지를 보낸다.
장치 중에는 작은 컨트롤러 장치가 있다.
컨트롤러 장치는 4글자로 된 명령 메시지에 반응한다.
예를 들어 컨트롤러 장치는 <D1UL>라는 메시지를 받았을 때 문을 연다.
이러한 보안 시스템에서 핵심 부분은 컨트롤러 소프트웨어다.
컨트롤러 소프트웨어는 이벤트 메시지를 수신한다.
수신한 메시지에 어떻게 반응할지 계산한 후, 명령 메시지를 전송한다.
김대리의 컨트롤러
문을 닫는다
김대리
전등을 켠다
서랍을 연다
서랍을 연다
전등을 켠다
금고가 열린다
김대리의 컨트롤러에 대한 상태 다이어그램
상태 머신 프레임워크에 대한 클래스 다이어그램
프레임워크 소스 코드: 이벤트와 커맨드
프레임워크 소스 코드: 이벤트와 커맨드
프레임워크 소스 코드: 상태
프레임워크 소스 코드 : 상태
프레임워크 소스 코드: 전이
프레임워크 소스 코드 : 전이
프레임워크 소스 코드: 상태 머신
프레임워크 소스 코드 : 상태 머신
프레임워크 소스 코드 : 컨트롤러
김대리의 컨트롤러 프로그래밍하기
김대리의 컨트롤러 프로그래밍하기
프로그램의 유형
상태 머신
모델
컴파일
Generic
범용적
Framework
배포
Specific
특수한
Variable
설정 코드
김대리의
컨트롤러
박부장의
컨트롤러
최비서의
컨트롤러
김대리의 컨트롤러에 대한 XML 설정 코드
김대리의 컨트롤러에 대한 XML 설정 코드
프로그램의 유형
상태 머신
모델
컴파일
Generic
범용적
Framework
배포
XML
파서
XML
파서
XML
파서
Specific
특수한
Variable
설정 코드
김대리의
컨트롤러
박부장의
컨트롤러
최비서의
컨트롤러
커스텀 구문을 직접 만들어 보자
커스텀 구문을 직접 만들어 보자
프로그램의 유형
상태 머신
모델
컴파일
Generic
범용적
Framework
배포
설정 코드
커스텀
파서
커스텀
파서
커스텀
파서
커스텀
구문
커스텀
구문
커스텀
구문
김대리의
컨트롤러
박부장의
컨트롤러
최비서의
컨트롤러
Specific
특수한
Variable
DSL의 정의
특정 도메인에 관심을 집중해서 목적에 맞게 표현성을 한정시킨 컴퓨터 프로그래밍 언어
 컴퓨터 프로그래밍 언어
DSL은 컴퓨터가 무언가를 하도록 사람이 지시하는데 사용된다.
최신 프로그래밍 언어와 마찬가지로, DSL의 구조는 사람이 쉽게 이해할 수 있도록 만들어진다.
이와 동시에 DSL은 컴퓨터에 의해서 실행될 수 있어야 한다.
 언어적 본질
DSL은 프로그래밍 언어이므로, 언어로서 가져야 하는 유창함(fluency)을 지녀야 한다.
즉, 언어의 표현력이 개별적인 표현식에서만 나타나는 게 아니라, 표현식이 서로 조합되는 방식에서도 나타나야 한다.
 한정된 표현력
범용 프로그래밍 언어는 많은 기능을 제공한다.
다양한 데이터 타입을 제공하고, 제어문이 있으며, 데이터 구조를 추상화할 수도 있다.
이들 기능은 모두 유용하지만, 배우고 사용하기는 어렵다.
반면에 DSL은 특정 도메인에서 필요한 거의 최소한의 기능만을 제공한다.
따라서 DSL만으로는 소프트웨어 시스템 전체를 개발할 수 없다.
대신에 DSL은 시스템에서 특정 부분을 만들 때 사용한다.
집중된 도메인
한정된 언어는 작은 도메인에 제대로 집중해야만 쓸모가 있다.
특정 도메인에 관심을 집중해야만, 한정된 언어는 빛을 발한다.
이 설정 코드는 DSL인가?
이 설정 코드는 DSL인가?
DSL의 종류
DSL에는 외부 DSL, 내부 DSL, 그리고 언어 워크벤치가, 3가지 종류가 있다.
외부 DSL(external DSL)
- DSL을 적용할 시스템에서 메인 언어로 사용하는 언어와는 다른 언어다.
- 외부 DSL은 흔히 커스텀 구문을 직접 정의하는 형식으로 사용된다.
- 하지만 이미 있는 프로그래밍 언어의 구문을 사용할 때도 많다(예를 들어 XML이 주로 사용된다).
- 외부 DSL로 작성한 스크립트는 텍스트 파싱 기법을 사용해서, 호스트 어플리케이션에 있는 코드로 파싱될 때가 많다.
예) 정규 표현식, SQL, Awk, 스트럿츠나 하이버네이트에서 활용하는 XML 설정 파일 등
내부 DSL(internal DSL)
- 범용 언어를 활용하는 특별한 방식이다.
- 내부 DSL로 작성된 스크립트는 범용 언어 안에서도 유효한 코드다.
- 하지만 언어의 기능 중 일부만을, 특별한 형식으로 사용해 전체 시스템에서 조그만 부분만을 처리한다.
- 따라서 내부 DSL로 작성한 스크립트는 호스트 언어보다는 커스텀 언어에 가까워야 한다.
예) 호스트 언어를 이처럼 특별한 형식으로 사용하는 전형적인 예는 Lisp
언어 워크벤치(Language Workbench)
- DSL을 정의하고 개발하는 데 특화된 IDE다.
- 무엇보다도 언어 워크벤치를 사용하면 DSL 구조를 정의할 수 있을 뿐만 아니라,
DSL 스크립트를 작성할 수 있는 커스텀 편집 환경을 만들 수도 있다.
첫 자바 코드 예제는 DSL인가?
자바로는 내부 DSL을 만들 수 없나?
이건 어떤가?
이건 어떤가?
언어와 시맨틱 모델
입력 DSL
파퓰레이트
시맨틱 모델
[실습]
ANTLR 파서 생성기를 사용해서
웹로그 파서 개발하기
NCSA 포맷 웹로그
203.226.192.157 \
-\
-\
30/Mar/2012:17:38:42 +0900
"GET /upload/adm/banner/main/tmp/bottom_P_L_2.jpg HTTP/1.1“\
200 \
20048
METHOD URL PROTOCOL
CLIENT_IP
USER_NAME
RFC931
LOG_DATE
REQUEST
STATUS
CONTENT_LENGTH
정규식 웹로그 파서
정규식
(\\d+.\\d+.\\d+.\\d+) (-) (-) ([^\\s]+ [^\\s]+) \\"([^\\s]+) ([^\\s]+) ([^\\s]+)\\" (\\d+) (\\d+)
정규식 웹로그 파서 테스트 케이스
웹로그 DSL을 만들어 보자
DSL
client_ip | user_name | rfc931 | log_date+1 | method/url/protocol | status | content_length
[출력용]
실습 Step by Step
(발표자료에는 포함하지 않음)
[실습 준비물]
JDK 1.6 이상
Eclipse
M2Ecplise 플러그인
antlr 파서 생성기
openit.weblog.parser.zip 프로젝트 템플릿
인터넷
ANTLRWorks 실행하기
1.
antlrworks-1.4.3.jar를 다운로드한다.
2.
C:\에 antlr 디렉터리를 만든다.
3.
다운로드한 antlrworks-1.4.3.jar를 C:\ antlr\에 복사한다.
4.
ANTLRWorks를 실행한다.
java -Xmx512m -jar antlrworks-1.4.3.jar
문법 파일 만들기
1.
편집기에서 아래와 같이 쓴 후,
grammar Weblog;
2.
Weblog.g라는 이름으로 저장한다.
렉싱 문법 만들기
렉싱 문법 테스트하기
1.
하단의 [Interpreter] 탭을 연다.
2.
왼편의 입력창에, 파싱하려는 로그를 입력한 후, 실행버튼을 누른다.
파싱 문법 만들기
1.
시맨틱 모델을 만들기 위한 구문을 추가한다.
여기에서는 추상 구문 트리(AST: Abstract Syntax Tree)를 시맨틱
모델로 사용한다.
코드 생성 옵션 추가하기
1.
렉서와 파서 코드를 생성하기 위한 옵션을 추가한다.
2.
메뉴에서 [Generate] -> [Generate Code]를 실행한다.
3.
AntlrWorks가 설치된 디렉터리의 하위 디렉터리에 output 디렉토리가
만들어지고, 여기에 렉서와 파서 코드가 생성된다.
생성된 렉서/파서 테스트하기
1.
메뉴에서 [Run] -> [Debug..]를 실행한다.
2.
팝업창의 [Input Text]에 테스트하려는 로그를 입력한 후,
[OK]를 누른다.
javac를 실행할 수 있도록, JAVA 경로가 환경변수에 등록되어야 함
3.
하단의 [Debugger] 탭을 누른다.
4.
[Go to End] 버튼을 누르면, AST가 정상적으로 생성됨을 확인할 수 있
다.
웹로그 파서 프로젝트 만들기
1.
이클립스에서 템플릿 프로젝트를 연다.
2.
생성된 코드를 복사할 패키지를 만든다.
com.samsung.sds.weblog.dsl.parser
com.samsung.sds.weblog.dsl.lexer
3.
생성된 렉서 코드와 파서 코드를, 템플릿 프로젝트에 복사한다.
웹로그를 파싱하기 위한 로더 클래스 테스트 케이스 만들기
1.
src/test/java에 com.samsung.sds.weblog.dsl.loader 패키지를 만든다.
2.
WeblogLoaderTest 클래스를 만든다.
3.
프로퍼티 변수와 init 메서드를 만든다
(RegExParserTest에서 복사한다.)
웹로그를 파싱하기 위한 로더 클래스 테스트 케이스 만들기
1.
props4RegEx 변수를 props4Dsl로 이름을 리팩토링한다.
(Alt + Shift + R)
2.
is4RegEx 변수를 is4Dsl로 이름을 리팩토링한다.
3.
프로퍼티 파일 위치를 /regex.properties에서 /dsl.properties로 변경한
다.
웹로그를 파싱하기 위한 로더 클래스 테스트 케이스 만들기
1.
테스트 메서드를 만든다. RegExParserTest 클래스에서
run_RegExWeblogParser 메서드를 복사한다.
2.
메서드명을 run_RegExWeblogParser에서
run_WeblogLoader로 변경한다.
3.
props4RegEx를 props4Dsl로 이름을 리팩토링한다.
4.
regex_0001를 web_0001로 변경한다.
5.
클래스명을 RegExWeblogParser를 WeblogLoader로 바꾼다.
웹로그를 파싱하기 위한 로더 클래스 만들기
1.
컴파일 에러가 나므로 WeblogLoader 클래스를 만든다.
2.
생성자를 만든다.
웹로그를 파싱하기 위한 로더 클래스 만들기
1.
run 메서드와, getWeblog 메서드를 각각 만든다.
2.
테스트 케이스를 실행시켜, 실패하도록 한다.
테스트 케이스 녹색불 뜨도록 만들기 - 생성자
1.
생성자의 인자명을 property에서 dsl로 바꾼다.
2.
dsl 멤버 필드를 추가한 후, 생성자의 인자를 멤버 필드에 할당한다.
테스트 케이스 녹색불 뜨도록 만들기 - run
1.
run 메서드의 인자명을 property에서 line으로 변경한다.
2.
아래와 같이 run 메서드를 구현한다.
테스트 케이스 녹색불 뜨도록 만들기 - run
1.
run 메서드에, 아래의 코드를 추가한다..
테스트 케이스 녹색불 뜨도록 만들기 – 필드 연결하기
1.
필드를 연결하는 부분에 아래 메서드를 호출한다.
j = mapContinuationField(logTypeVal[i], attribute, subList, j);
2.
mapContinuationField 메서드를 만든다.
3.
weblog 지역 변수를 멤버 필드로 리팩토링한다.
테스트 케이스 녹색불 뜨도록 만들기 – 필드 분할하기
1.
필드를 분할하는 부분에 아래 메서드를 호출한다.
j = mapSplitField(logTypeVal[i], attribute, subList, j);
2.
mapSplitField 메서드를 만든다.
테스트 케이스 녹색불 뜨도록 만들기 – getWeblog
1.
getWeblog 메서드를 아래와 같이 구현한다.
테스트 케이스 녹색불 뜨도록 만들기–getAttributeWithoutDelimeter
1.
테스트 케이스를 실행한다.
2.
토큰에서 구분자를 제거한다. getAttributeWithoutDelimeter 메서드를
아래와 같이 만든다.
테스트 케이스 녹색불 뜨도록 만들기
1.
아래 부분을 다음과 같이 변경한다.
2.
테스트 케이스를 실행한다
코드 리팩토링하기 - run
1.
run 메서드를 아래와 같이 리팩토링한다.
한걸음 더 나가보기
감사합니다