SlideShare ist ein Scribd-Unternehmen logo
1 von 23
Downloaden Sie, um offline zu lesen
모델링 연습 리뷰 
신림프로그래머 최범균 2014-11-25
요구사항 1 
• 요청 메시지의 A옵션이 1인 클라이언트C1과 B옵 
션이 2인 클라이언트 C2는 서브넷S1의 IP 대역에 
서 네트워크 설정(IP 포함)을 할당받는다. 
• 맥주소가 M3인 클라이언트C3와 M4인 클라이언 
트 C4는 서브넷S2의 IP 대역 중에서 앞 쪽 절반에 
서 네트워크 설정을 할당받는다. 
• 요청 메시지의 E옵션이 5인 클라이언트C5와 맥주 
소가 M6인 클라이언트C6은 서브넷S2의 IP 대역 
중에서 뒤 쪽 절반에서 네트워크 설정을 할당받는 
다. 
• 맥주소 일치가 우선한다. 
• 임대 IP는 클라이언트 단위로 관리된다. 
2
그림으로 보면 
C1 
C2 
C3 
(M3) 
C4 
(M4) 
C5 
IP 
대역 
S1 
IP 
대역 
S2 
A=1 
B=1 
C6 
(M6) 
E=1 
3
그림에서 도출 
C1 
C2 
C3 
(M3) 
C4 
(M4) 
C5 
IP 
대역 
S1 
IP 
대역 
S2 
A=1 
B=1 
C6 
(M6) 
E=1 
옵션으로 
클라이언트 
구분 
맥주소로 
클라이언트 
구분 
다른 조건을 따르는 클라이언트들이 
한 대역으로 묶임 
한 대역을 
나눠 쓸 수 
있음 
4
요구사항 2 
• 응답 옵션 
– IP 대역 별로 응답 옵션을 다르게 설정 
– IP 풀 별로 응답 옵션을 다르게 설정 
– 클라이언트 그룹(클래스) 별로 응답 옵션을 다르 
게 설정 
– 특정 조건을 충족하는 클라이언트들 별로 응답 옵 
션을 다르게 설정 
– 같은 응답 옵션이 존재할 경우 우선 순위 
• 클라이언트별 > 클라이언트 그룹 > IP 풀 > 대역 
• 네트워크 설정(DNS, GW, 서브넷마스크) 
– IP 대역 별로 네트워크 설정 
– IP 풀 별로 다른 네트워크 설정 
• IP 풀에 네트워크 설정이 있을 경우, 우선 적용 
5
최초 끄적임 
6
영역 구분 
7
설정 영역 
8
Optional 써 봄 
9 
public 
interface 
ClientFinder 
{ 
OpFonal<? 
extends 
Client> 
find(DhcpMessage 
message); 
} 
public 
interface 
Client 
{ 
public 
OpFonal<ClientClass> 
getClientClass(); 
... 
} 
public 
class 
ClientClass 
{ 
private 
Pool 
pool; 
public 
OpFonal<Pool> 
getPool() 
{ 
return 
OpFonal.ofNullable(pool); 
} 
... 
}
사용 가능 IP 범위 찾기 
public 
class 
UsableIpRangeFinderImpl 
implements 
UsableIpRangeFinder 
{ 
private 
ClientFinder 
clientFinder; 
@TransacFonal 
@Override 
public 
RangeResult 
find(DhcpMessage 
message) 
{ 
if 
(message 
== 
null) 
throw 
new 
IllegalArgumentExcepFon(); 
OpFonal<? 
extends 
Client> 
clientOpt 
= 
clientFinder.find(message); 
OpFonal<Pool> 
poolOpt 
= 
clientOpt.flatMap(c 
-­‐> 
c.getClientClass()).flatMap(cc 
-­‐> 
cc.getPool()); 
if 
(!poolOpt.isPresent()) 
return 
emptyResult(); 
Pool 
pool 
= 
poolOpt.get(); 
return 
new 
RangeResult( 
pool.getIpRange(), 
getNetworkConfig(pool), 
getMergedOpFons(clientOpt.get())); 
} 
private 
NetworkConfig 
getNetworkConfig(Pool 
pool) 
{ 
NetworkConfig 
nc 
= 
pool.getNetworkConfig(); 
return 
nc 
!= 
null 
? 
nc 
: 
pool.getSubnect().getNetworkConfig(); 
} 
private 
DhcpOpFons 
getMergedOpFons(Client 
client) 
{ 
... 
// 
다음 장에 코드 표시 
} 
10 
// 
OpFonal 
대신 null 
사용 경우 
Client 
client 
= 
clientFinder.find(message); 
if 
(client 
== 
null) 
return 
emptyResult(); 
if 
(client.getClientClass() 
== 
null) 
return 
emptyResult(); 
Pool 
pool 
= 
client.getClientClass().getPool(); 
if 
(pool 
== 
null) 
return 
emptyResult();
응답 옵션 생성 부분 
11 
// 
UsableIpRangeFinderImpl 
클래스 
private 
DhcpOpFons 
getMergedOpFons(Client 
client) 
{ 
DhcpOpFons 
cOpFons 
= 
client.getDhcpOpFons(); 
ClientClass 
clientClass 
= 
client.getClientClass().get(); 
DhcpOpFons 
ccOpFons 
= 
clientClass.getDhcpOpFons(); 
Pool 
pool 
= 
clientClass.getPool().get(); 
DhcpOpFons 
poolOpFons 
= 
pool.getDhcpOpFons(); 
DhcpOpFons 
subnetOpFons 
= 
pool.getSubnect().getDhcpOpFons(); 
return 
subnetOp9ons.merge(poolOpFons).merge(ccOpFons).merge(cOpFons); 
} 
// 
DhcpOpFons 
클래스 
public 
DhcpOpFons 
merge(DhcpOpFons 
other) 
{ 
DhcpOpFons 
newOpFons 
= 
new 
DhcpOpFons(this.opFonMap); 
if 
(other 
== 
null 
|| 
other.isEmpty()) 
return 
newOpFons; 
other.opFonMap.values().forEach(ov 
-­‐> 
newOpFons.add(ov)); 
return 
newOpFons; 
}
클라이언트 찾기 
• 두 종류의 클라이언트 매칭 
12 
public 
class 
HardwareAddressClient 
implements 
Client 
{ 
private 
HardwareAddress 
hardwareAddress; 
... 
} 
public 
class 
MatchClient 
implements 
Client 
{ 
private 
List<MatchPredicate> 
predicates 
= 
new 
ArrayList<>(); 
public 
boolean 
match(DhcpMessage 
message) 
{ 
return 
predicates.stream() 
.allMatch(p 
-­‐> 
p.match(message)); 
} 
... 
} 
1. 하드웨어 주소 
2. 
조건 일치
클라이언트 찾기 
13 
public 
class 
ClientFinderImpl 
implements 
ClientFinder 
{ 
private 
HardwareAddressClientRepository 
hardwareAddressClientRepository; 
private 
MatchClientRepository 
matchClientRepository; 
@Override 
public 
OpFonal<? 
extends 
Client> 
find(DhcpMessage 
message) 
{ 
if 
(message 
== 
null) 
return 
OpFonal.empty(); 
// 
맥주소 일치가 먼저 
OpFonal<HardwareAddressClient> 
hwAddrClient 
= 
hardwareAddressClientRepository.findByHardwareAddress(message.getChaddr()); 
if 
(hwAddrClient.isPresent()) 
return 
hwAddrClient; 
// 맥주소 일치 없으면, 조건 충족하는 Client 
검색 
List<MatchClient> 
clients 
= 
matchClientRepository.findAll(); 
for 
(MatchClient 
mclient 
: 
clients) 
if 
(mclient.match(message)) 
return 
OpFonal.of(mclient); 
return 
OpFonal.empty(); 
} 
...
MatchClient의 MatchPredicate 
• 다양한 MatchPredicate 가능성 
– 인터페이스/종류별 하위 타입으로 설계 
14
JPA 적용 
• DB 연동은 JPA를 사용하기로 결정 
– 기본 데이터 타입은 단순 매핑 설정 사용 
– InetAddress 등에 커스텀 변환기 사용 
• 적용하기 위한 몇 가지 코드 변경 
– DhcpOptions 필드 à List<DhcpOption> 
– MatchPredicate 계층 à 단일 클래스 
15
일부 매핑 설정 예 
16 
@Entity @Table(name = "SUBNET_CONFIG") 
public class SubnetConfig { 
@Id @Column(name = "ID") 
private Long id; 
@Column(name = "SUBNET") 
@Convert(converter = SubnetConverter.class) 
private Subnet subnet; 
@Embedded 
private NetworkConfig networkConfig; 
...// DhcpOptions는 다다다...음 장에 
@Embeddable 
public class NetworkConfig { 
@Column(name = "SUBNETMASK") 
@Convert(converter = SubnetMaskConverter.class) 
private SubnetMask subnetMask; 
@Column(name = "GATEWAY") 
@Convert(converter = InetAddressConverter.class) 
private InetAddress gateway; 
@Column(name = "DNSLIST") 
@Convert(converter = IpListConverter.class) 
private IpList domainServers; 
SUBNET_CONFIG 
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ 
ID: 
int 
SUBNET: 
VARCHAR 
SUBNETMASK: 
VARCHAR 
GATEWAY: 
VARCHAR 
DNSLIST: 
VARCHAR
커스텀 변환기 
• 값 타입과 DB 한 개 컬럼 간의 변환 위함 
17 
@Entity @Table(name = "SUBNET_CONFIG") 
public class SubnetConfig { 
@Id @Column(name = "ID") 
private Long id; 
@Column(name = "SUBNET") 
@Convert(converter = SubnetConverter.class) 
private Subnet subnet; 
... 
} 
public class Subnet { 
private InetAddress networkAddress; 
private int bits; 
... 
} 
SUBNET_CONFIG 
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ 
ID: 
int 
SUBNET: 
VARCHAR 
SUBNETMASK: 
VARCHAR 
GATEWAY: 
VARCHAR 
DNSLIST: 
VARCHAR 
Java 
new 
Subnet("192.168.0.1", 
24) 
컬럼 값 
192.168.0.1/24
커스텀 컨버터 구현 예 
18 
@Converter 
public class SubnetConverter implements AttributeConverter<Subnet, String> { 
@Override 
public String convertToDatabaseColumn(Subnet subnet) { 
if (subnet == null) return null; 
return subnet.toString(); 
} 
@Override 
public Subnet convertToEntityAttribute(String dbData) { 
if (dbData == null || dbData.isEmpty()) return null; 
return new Subnet(dbData); 
} 
}
커스텀 컨버터 구현 예 
19 
// List<InetAddress>와 "123.0.2.1,192.168.0.254" DB 데이터 간 변환 처리 
@Converter 
public class IpListConverter implements AttributeConverter<IpList, String> { 
@Override 
public String convertToDatabaseColumn(IpList attribute) { 
if (attribute == null || attribute.isEmpty()) return ""; 
else return attribute.toString(); 
} 
@Override 
public IpList convertToEntityAttribute(String dbData) { 
if (dbData == null) return null; 
String[] ips = dbData.split(","); 
List<InetAddress> addresses = new ArrayList<>(); 
for (String ip : ips) { 
try { 
addresses.add(InetAddress.getByName(ip)); 
} catch (UnknownHostException e) { 
throw new RuntimeException(....생략, e); 
} 
} 
return new IpList(addresses); 
} 
}
JPA 적용 과정에서의 모델 변화 
• DhcpOptions 구현 변경 
– 모델과 DB간 불일치 
20 
@Entity 
@Table(name = "CLIENT_MATCH") 
public class MatchClient implements Client { 
// @Embedded ?? 
private DhcpOptions options; 
public DhcpOptions getDhcpOptions() { 
return options; 
} 
... 
} 
// @Embeddable ?? 
public class DhcpOptions { 
// ?? 
private Map<DhcpOption, OptionValue> optionMap; 
} 
CM_DHCP_OPTIONS 
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ 
CM_ID: 
int 
LIST_INDEX: 
int 
OPTION_CODE: 
int 
OPTION_VALUE: 
String 
키 
vs 
인덱스 
관리 화면에서 
입력한 순서대로 
보여줄 필요
JPA 적용 과정에서의 모델 변화 
• DhcpOptions 구현 변경 
– 모델과 DB간 불일치 
21 
@Entity @Table(name = "CLIENT_MATCH") 
public class MatchClient implements Client { 
private DhcpOptions options; 
public DhcpOptions getDhcpOptions() { 
return options; 
} 
... 
} 
@ElementCollection 
@CollectionTable(name = "CLIENT_MATCH_DHCP_OPTION", 
joinColumns = @JoinColumn(name = "CLIENT_MATCH_ID")) 
@OrderColumn(name = "LIST_INDEX") 
private List<OptionValue> options = new ArrayList<>(); 
public DhcpOptions getDhcpOptions() { // 메서드 시그너쳐 유지 
return new DhcpOptions(options); 
} 
CM_DHCP_OPTIONS 
-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ 
CM_ID: 
int 
LIST_INDEX: 
int 
OPTION_CODE: 
int 
OPTION_VALUE: 
String
JPA 적용 과정에서의 모델 변화 
• MatchClient 구현 변경 
– @Embeddable 타입의 상속 지원하지 않음 
– 계층을 단일 클래스로 변경 
22
23 
끝

Weitere ähnliche Inhalte

Was ist angesagt?

나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
daewon jeong
 

Was ist angesagt? (20)

Lambda 란 무엇인가
Lambda 란 무엇인가Lambda 란 무엇인가
Lambda 란 무엇인가
 
프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop프론트엔드스터디 E05 js closure oop
프론트엔드스터디 E05 js closure oop
 
Java8 & Lambda
Java8 & LambdaJava8 & Lambda
Java8 & Lambda
 
7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성
 
Java8 람다
Java8 람다Java8 람다
Java8 람다
 
나에 첫번째 자바8 람다식 지앤선
나에 첫번째 자바8 람다식   지앤선나에 첫번째 자바8 람다식   지앤선
나에 첫번째 자바8 람다식 지앤선
 
Javascript 교육자료 pdf
Javascript 교육자료 pdfJavascript 교육자료 pdf
Javascript 교육자료 pdf
 
자바 8 학습
자바 8 학습자바 8 학습
자바 8 학습
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
자바8 람다 나머지 공개
자바8 람다 나머지 공개자바8 람다 나머지 공개
자바8 람다 나머지 공개
 
프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function프론트엔드스터디 E04 js function
프론트엔드스터디 E04 js function
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
UML distilled 1장 스터디 발표 자료
UML distilled 1장 스터디 발표 자료UML distilled 1장 스터디 발표 자료
UML distilled 1장 스터디 발표 자료
 
Javascript
JavascriptJavascript
Javascript
 
스위프트 성능 이해하기
스위프트 성능 이해하기스위프트 성능 이해하기
스위프트 성능 이해하기
 
Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저Startup JavaScript 6 - 함수, 스코프, 클로저
Startup JavaScript 6 - 함수, 스코프, 클로저
 
Javascript 함수(function) 개념, 호출패턴, this, prototype, scope
Javascript 함수(function) 개념, 호출패턴, this, prototype, scopeJavascript 함수(function) 개념, 호출패턴, this, prototype, scope
Javascript 함수(function) 개념, 호출패턴, this, prototype, scope
 
골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료골때리는 자바스크립트 발표자료
골때리는 자바스크립트 발표자료
 
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
Startup JavaScript 5 - 객체(Date, RegExp, Object, Global)
 
일단 시작하는 코틀린
일단 시작하는 코틀린일단 시작하는 코틀린
일단 시작하는 코틀린
 

Ähnlich wie 모델링 연습 리뷰

SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
Sangmin Lee
 
읽기 좋은 코드가 좋은 코드다 Part one
읽기 좋은 코드가 좋은 코드다   Part one읽기 좋은 코드가 좋은 코드다   Part one
읽기 좋은 코드가 좋은 코드다 Part one
Ji Hun Kim
 
Surface flingerservice(서피스 플링거 연결 jb)
Surface flingerservice(서피스 플링거 연결 jb)Surface flingerservice(서피스 플링거 연결 jb)
Surface flingerservice(서피스 플링거 연결 jb)
fefe7270
 
13th chapter12 slide
13th chapter12 slide13th chapter12 slide
13th chapter12 slide
웅식 전
 

Ähnlich wie 모델링 연습 리뷰 (20)

12장 상속 (고급)
12장 상속 (고급)12장 상속 (고급)
12장 상속 (고급)
 
Kubernetes & helm 활용
Kubernetes & helm 활용Kubernetes & helm 활용
Kubernetes & helm 활용
 
Ryu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST APIRyu with OpenFlow 1.3, REST API
Ryu with OpenFlow 1.3, REST API
 
파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄파이썬 데이터베이스 연결 1탄
파이썬 데이터베이스 연결 1탄
 
SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8SpringCamp 2013 : About Jdk8
SpringCamp 2013 : About Jdk8
 
Clean code appendix 1
Clean code appendix 1Clean code appendix 1
Clean code appendix 1
 
읽기 좋은 코드가 좋은 코드다 Part one
읽기 좋은 코드가 좋은 코드다   Part one읽기 좋은 코드가 좋은 코드다   Part one
읽기 좋은 코드가 좋은 코드다 Part one
 
[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화[스프링 스터디 2일차] 서비스 추상화
[스프링 스터디 2일차] 서비스 추상화
 
Before OTD EDU Assignments
Before OTD EDU AssignmentsBefore OTD EDU Assignments
Before OTD EDU Assignments
 
TR 069 클라이언트 검토자료 3편
TR 069 클라이언트 검토자료 3편TR 069 클라이언트 검토자료 3편
TR 069 클라이언트 검토자료 3편
 
Ai C#세미나
Ai C#세미나Ai C#세미나
Ai C#세미나
 
Surface flingerservice(서피스 플링거 연결 jb)
Surface flingerservice(서피스 플링거 연결 jb)Surface flingerservice(서피스 플링거 연결 jb)
Surface flingerservice(서피스 플링거 연결 jb)
 
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
GKAC 2015 Apr. - Battery, 안드로이드를 위한 쉬운 웹 API 호출
 
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개[Pgday.Seoul 2018]  PostgreSQL 11 새 기능 소개
[Pgday.Seoul 2018] PostgreSQL 11 새 기능 소개
 
Refactoring - Chapter 8.2
Refactoring - Chapter 8.2Refactoring - Chapter 8.2
Refactoring - Chapter 8.2
 
13th chapter12 slide
13th chapter12 slide13th chapter12 slide
13th chapter12 slide
 
Programming Cascading
Programming CascadingProgramming Cascading
Programming Cascading
 
Linux blue borne-vulnerabilities
Linux blue borne-vulnerabilitiesLinux blue borne-vulnerabilities
Linux blue borne-vulnerabilities
 
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
#17.스프링프레임워크 & 마이바티스 (Spring Framework, MyBatis)_국비지원IT학원/실업자/재직자환급교육/자바/스프링/...
 
Cloudera Impala 1.0
Cloudera Impala 1.0Cloudera Impala 1.0
Cloudera Impala 1.0
 

Mehr von beom kyun choi

ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료
beom kyun choi
 

Mehr von beom kyun choi (20)

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)
 
DDD 준비 서문래
DDD 준비 서문래DDD 준비 서문래
DDD 준비 서문래
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
 
Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksug
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
 
Spring Boot 소개
Spring Boot 소개Spring Boot 소개
Spring Boot 소개
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
Zookeeper 소개
Zookeeper 소개Zookeeper 소개
Zookeeper 소개
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)
 
Storm 훑어보기
Storm 훑어보기Storm 훑어보기
Storm 훑어보기
 
Hive 입문 발표 자료
Hive 입문 발표 자료Hive 입문 발표 자료
Hive 입문 발표 자료
 
HBase 훑어보기
HBase 훑어보기HBase 훑어보기
HBase 훑어보기
 
Flume 훑어보기
Flume 훑어보기Flume 훑어보기
Flume 훑어보기
 

모델링 연습 리뷰

  • 1. 모델링 연습 리뷰 신림프로그래머 최범균 2014-11-25
  • 2. 요구사항 1 • 요청 메시지의 A옵션이 1인 클라이언트C1과 B옵 션이 2인 클라이언트 C2는 서브넷S1의 IP 대역에 서 네트워크 설정(IP 포함)을 할당받는다. • 맥주소가 M3인 클라이언트C3와 M4인 클라이언 트 C4는 서브넷S2의 IP 대역 중에서 앞 쪽 절반에 서 네트워크 설정을 할당받는다. • 요청 메시지의 E옵션이 5인 클라이언트C5와 맥주 소가 M6인 클라이언트C6은 서브넷S2의 IP 대역 중에서 뒤 쪽 절반에서 네트워크 설정을 할당받는 다. • 맥주소 일치가 우선한다. • 임대 IP는 클라이언트 단위로 관리된다. 2
  • 3. 그림으로 보면 C1 C2 C3 (M3) C4 (M4) C5 IP 대역 S1 IP 대역 S2 A=1 B=1 C6 (M6) E=1 3
  • 4. 그림에서 도출 C1 C2 C3 (M3) C4 (M4) C5 IP 대역 S1 IP 대역 S2 A=1 B=1 C6 (M6) E=1 옵션으로 클라이언트 구분 맥주소로 클라이언트 구분 다른 조건을 따르는 클라이언트들이 한 대역으로 묶임 한 대역을 나눠 쓸 수 있음 4
  • 5. 요구사항 2 • 응답 옵션 – IP 대역 별로 응답 옵션을 다르게 설정 – IP 풀 별로 응답 옵션을 다르게 설정 – 클라이언트 그룹(클래스) 별로 응답 옵션을 다르 게 설정 – 특정 조건을 충족하는 클라이언트들 별로 응답 옵 션을 다르게 설정 – 같은 응답 옵션이 존재할 경우 우선 순위 • 클라이언트별 > 클라이언트 그룹 > IP 풀 > 대역 • 네트워크 설정(DNS, GW, 서브넷마스크) – IP 대역 별로 네트워크 설정 – IP 풀 별로 다른 네트워크 설정 • IP 풀에 네트워크 설정이 있을 경우, 우선 적용 5
  • 9. Optional 써 봄 9 public interface ClientFinder { OpFonal<? extends Client> find(DhcpMessage message); } public interface Client { public OpFonal<ClientClass> getClientClass(); ... } public class ClientClass { private Pool pool; public OpFonal<Pool> getPool() { return OpFonal.ofNullable(pool); } ... }
  • 10. 사용 가능 IP 범위 찾기 public class UsableIpRangeFinderImpl implements UsableIpRangeFinder { private ClientFinder clientFinder; @TransacFonal @Override public RangeResult find(DhcpMessage message) { if (message == null) throw new IllegalArgumentExcepFon(); OpFonal<? extends Client> clientOpt = clientFinder.find(message); OpFonal<Pool> poolOpt = clientOpt.flatMap(c -­‐> c.getClientClass()).flatMap(cc -­‐> cc.getPool()); if (!poolOpt.isPresent()) return emptyResult(); Pool pool = poolOpt.get(); return new RangeResult( pool.getIpRange(), getNetworkConfig(pool), getMergedOpFons(clientOpt.get())); } private NetworkConfig getNetworkConfig(Pool pool) { NetworkConfig nc = pool.getNetworkConfig(); return nc != null ? nc : pool.getSubnect().getNetworkConfig(); } private DhcpOpFons getMergedOpFons(Client client) { ... // 다음 장에 코드 표시 } 10 // OpFonal 대신 null 사용 경우 Client client = clientFinder.find(message); if (client == null) return emptyResult(); if (client.getClientClass() == null) return emptyResult(); Pool pool = client.getClientClass().getPool(); if (pool == null) return emptyResult();
  • 11. 응답 옵션 생성 부분 11 // UsableIpRangeFinderImpl 클래스 private DhcpOpFons getMergedOpFons(Client client) { DhcpOpFons cOpFons = client.getDhcpOpFons(); ClientClass clientClass = client.getClientClass().get(); DhcpOpFons ccOpFons = clientClass.getDhcpOpFons(); Pool pool = clientClass.getPool().get(); DhcpOpFons poolOpFons = pool.getDhcpOpFons(); DhcpOpFons subnetOpFons = pool.getSubnect().getDhcpOpFons(); return subnetOp9ons.merge(poolOpFons).merge(ccOpFons).merge(cOpFons); } // DhcpOpFons 클래스 public DhcpOpFons merge(DhcpOpFons other) { DhcpOpFons newOpFons = new DhcpOpFons(this.opFonMap); if (other == null || other.isEmpty()) return newOpFons; other.opFonMap.values().forEach(ov -­‐> newOpFons.add(ov)); return newOpFons; }
  • 12. 클라이언트 찾기 • 두 종류의 클라이언트 매칭 12 public class HardwareAddressClient implements Client { private HardwareAddress hardwareAddress; ... } public class MatchClient implements Client { private List<MatchPredicate> predicates = new ArrayList<>(); public boolean match(DhcpMessage message) { return predicates.stream() .allMatch(p -­‐> p.match(message)); } ... } 1. 하드웨어 주소 2. 조건 일치
  • 13. 클라이언트 찾기 13 public class ClientFinderImpl implements ClientFinder { private HardwareAddressClientRepository hardwareAddressClientRepository; private MatchClientRepository matchClientRepository; @Override public OpFonal<? extends Client> find(DhcpMessage message) { if (message == null) return OpFonal.empty(); // 맥주소 일치가 먼저 OpFonal<HardwareAddressClient> hwAddrClient = hardwareAddressClientRepository.findByHardwareAddress(message.getChaddr()); if (hwAddrClient.isPresent()) return hwAddrClient; // 맥주소 일치 없으면, 조건 충족하는 Client 검색 List<MatchClient> clients = matchClientRepository.findAll(); for (MatchClient mclient : clients) if (mclient.match(message)) return OpFonal.of(mclient); return OpFonal.empty(); } ...
  • 14. MatchClient의 MatchPredicate • 다양한 MatchPredicate 가능성 – 인터페이스/종류별 하위 타입으로 설계 14
  • 15. JPA 적용 • DB 연동은 JPA를 사용하기로 결정 – 기본 데이터 타입은 단순 매핑 설정 사용 – InetAddress 등에 커스텀 변환기 사용 • 적용하기 위한 몇 가지 코드 변경 – DhcpOptions 필드 à List<DhcpOption> – MatchPredicate 계층 à 단일 클래스 15
  • 16. 일부 매핑 설정 예 16 @Entity @Table(name = "SUBNET_CONFIG") public class SubnetConfig { @Id @Column(name = "ID") private Long id; @Column(name = "SUBNET") @Convert(converter = SubnetConverter.class) private Subnet subnet; @Embedded private NetworkConfig networkConfig; ...// DhcpOptions는 다다다...음 장에 @Embeddable public class NetworkConfig { @Column(name = "SUBNETMASK") @Convert(converter = SubnetMaskConverter.class) private SubnetMask subnetMask; @Column(name = "GATEWAY") @Convert(converter = InetAddressConverter.class) private InetAddress gateway; @Column(name = "DNSLIST") @Convert(converter = IpListConverter.class) private IpList domainServers; SUBNET_CONFIG -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ID: int SUBNET: VARCHAR SUBNETMASK: VARCHAR GATEWAY: VARCHAR DNSLIST: VARCHAR
  • 17. 커스텀 변환기 • 값 타입과 DB 한 개 컬럼 간의 변환 위함 17 @Entity @Table(name = "SUBNET_CONFIG") public class SubnetConfig { @Id @Column(name = "ID") private Long id; @Column(name = "SUBNET") @Convert(converter = SubnetConverter.class) private Subnet subnet; ... } public class Subnet { private InetAddress networkAddress; private int bits; ... } SUBNET_CONFIG -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ ID: int SUBNET: VARCHAR SUBNETMASK: VARCHAR GATEWAY: VARCHAR DNSLIST: VARCHAR Java new Subnet("192.168.0.1", 24) 컬럼 값 192.168.0.1/24
  • 18. 커스텀 컨버터 구현 예 18 @Converter public class SubnetConverter implements AttributeConverter<Subnet, String> { @Override public String convertToDatabaseColumn(Subnet subnet) { if (subnet == null) return null; return subnet.toString(); } @Override public Subnet convertToEntityAttribute(String dbData) { if (dbData == null || dbData.isEmpty()) return null; return new Subnet(dbData); } }
  • 19. 커스텀 컨버터 구현 예 19 // List<InetAddress>와 "123.0.2.1,192.168.0.254" DB 데이터 간 변환 처리 @Converter public class IpListConverter implements AttributeConverter<IpList, String> { @Override public String convertToDatabaseColumn(IpList attribute) { if (attribute == null || attribute.isEmpty()) return ""; else return attribute.toString(); } @Override public IpList convertToEntityAttribute(String dbData) { if (dbData == null) return null; String[] ips = dbData.split(","); List<InetAddress> addresses = new ArrayList<>(); for (String ip : ips) { try { addresses.add(InetAddress.getByName(ip)); } catch (UnknownHostException e) { throw new RuntimeException(....생략, e); } } return new IpList(addresses); } }
  • 20. JPA 적용 과정에서의 모델 변화 • DhcpOptions 구현 변경 – 모델과 DB간 불일치 20 @Entity @Table(name = "CLIENT_MATCH") public class MatchClient implements Client { // @Embedded ?? private DhcpOptions options; public DhcpOptions getDhcpOptions() { return options; } ... } // @Embeddable ?? public class DhcpOptions { // ?? private Map<DhcpOption, OptionValue> optionMap; } CM_DHCP_OPTIONS -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ CM_ID: int LIST_INDEX: int OPTION_CODE: int OPTION_VALUE: String 키 vs 인덱스 관리 화면에서 입력한 순서대로 보여줄 필요
  • 21. JPA 적용 과정에서의 모델 변화 • DhcpOptions 구현 변경 – 모델과 DB간 불일치 21 @Entity @Table(name = "CLIENT_MATCH") public class MatchClient implements Client { private DhcpOptions options; public DhcpOptions getDhcpOptions() { return options; } ... } @ElementCollection @CollectionTable(name = "CLIENT_MATCH_DHCP_OPTION", joinColumns = @JoinColumn(name = "CLIENT_MATCH_ID")) @OrderColumn(name = "LIST_INDEX") private List<OptionValue> options = new ArrayList<>(); public DhcpOptions getDhcpOptions() { // 메서드 시그너쳐 유지 return new DhcpOptions(options); } CM_DHCP_OPTIONS -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐ CM_ID: int LIST_INDEX: int OPTION_CODE: int OPTION_VALUE: String
  • 22. JPA 적용 과정에서의 모델 변화 • MatchClient 구현 변경 – @Embeddable 타입의 상속 지원하지 않음 – 계층을 단일 클래스로 변경 22