Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

모델링 연습 리뷰

9,920 views

Published on

모델링 연습한 내용 리뷰 자료입니다.

Published in: Technology
  • Be the first to comment

모델링 연습 리뷰

  1. 1. 모델링 연습 리뷰 신림프로그래머 최범균 2014-11-25
  2. 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. 3. 그림으로 보면 C1 C2 C3 (M3) C4 (M4) C5 IP 대역 S1 IP 대역 S2 A=1 B=1 C6 (M6) E=1 3
  4. 4. 그림에서 도출 C1 C2 C3 (M3) C4 (M4) C5 IP 대역 S1 IP 대역 S2 A=1 B=1 C6 (M6) E=1 옵션으로 클라이언트 구분 맥주소로 클라이언트 구분 다른 조건을 따르는 클라이언트들이 한 대역으로 묶임 한 대역을 나눠 쓸 수 있음 4
  5. 5. 요구사항 2 • 응답 옵션 – IP 대역 별로 응답 옵션을 다르게 설정 – IP 풀 별로 응답 옵션을 다르게 설정 – 클라이언트 그룹(클래스) 별로 응답 옵션을 다르 게 설정 – 특정 조건을 충족하는 클라이언트들 별로 응답 옵 션을 다르게 설정 – 같은 응답 옵션이 존재할 경우 우선 순위 • 클라이언트별 > 클라이언트 그룹 > IP 풀 > 대역 • 네트워크 설정(DNS, GW, 서브넷마스크) – IP 대역 별로 네트워크 설정 – IP 풀 별로 다른 네트워크 설정 • IP 풀에 네트워크 설정이 있을 경우, 우선 적용 5
  6. 6. 최초 끄적임 6
  7. 7. 영역 구분 7
  8. 8. 설정 영역 8
  9. 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. 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. 응답 옵션 생성 부분 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. 클라이언트 찾기 • 두 종류의 클라이언트 매칭 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. 클라이언트 찾기 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. 14. MatchClient의 MatchPredicate • 다양한 MatchPredicate 가능성 – 인터페이스/종류별 하위 타입으로 설계 14
  15. 15. JPA 적용 • DB 연동은 JPA를 사용하기로 결정 – 기본 데이터 타입은 단순 매핑 설정 사용 – InetAddress 등에 커스텀 변환기 사용 • 적용하기 위한 몇 가지 코드 변경 – DhcpOptions 필드 à List<DhcpOption> – MatchPredicate 계층 à 단일 클래스 15
  16. 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. 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. 커스텀 컨버터 구현 예 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. 커스텀 컨버터 구현 예 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. 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. 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. 22. JPA 적용 과정에서의 모델 변화 • MatchClient 구현 변경 – @Embeddable 타입의 상속 지원하지 않음 – 계층을 단일 클래스로 변경 22
  23. 23. 23 끝

×