Successfully reported this slideshow.

모델링 연습 리뷰

27

Share

Loading in …3
×
1 of 23
1 of 23

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

모델링 연습 리뷰

  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 끝

×