View Javadoc
1   /*
2    * Copyright 2019 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.dccon.service;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Optional;
24  import java.util.Set;
25  import java.util.regex.Pattern;
26  import java.util.stream.Collectors;
27  import javax.validation.constraints.NotNull;
28  import lombok.extern.slf4j.Slf4j;
29  import org.bremersee.comparator.ComparatorBuilder;
30  import org.bremersee.dccon.config.DomainControllerProperties;
31  import org.bremersee.dccon.model.DhcpLease;
32  import org.bremersee.dccon.model.DnsNode;
33  import org.bremersee.dccon.model.DnsZone;
34  import org.bremersee.dccon.model.UnknownFilter;
35  import org.bremersee.dccon.repository.DhcpRepository;
36  import org.bremersee.dccon.repository.DnsNodeRepository;
37  import org.bremersee.dccon.repository.DnsZoneRepository;
38  import org.bremersee.dccon.repository.MockRepository;
39  import org.bremersee.exception.ServiceException;
40  import org.springframework.stereotype.Component;
41  import org.springframework.util.StringUtils;
42  
43  /**
44   * The name server service.
45   *
46   * @author Christian Bremer
47   */
48  @Component("nameServerService")
49  @Slf4j
50  public class NameServerServiceImpl implements NameServerService {
51  
52    private final DhcpRepository dhcpRepository;
53  
54    private final DnsZoneRepository dnsZoneRepository;
55  
56    private final DnsNodeRepository dnsNodeRepository;
57  
58    private final DnsNodeComparator dnsNodeComparator;
59  
60    private final DnsZoneComparator dnsZoneComparator;
61  
62    private final Pattern patternMac;
63  
64    private final Pattern patternIp4;
65  
66    /**
67     * Instantiates a new name server service.
68     *
69     * @param properties the properties
70     * @param dhcpRepository the dhcp repository
71     * @param dnsZoneRepository the dns zone repository
72     * @param dnsNodeRepository the dns node repository
73     */
74    public NameServerServiceImpl(
75        final DomainControllerProperties properties,
76        final DhcpRepository dhcpRepository,
77        final DnsZoneRepository dnsZoneRepository,
78        final DnsNodeRepository dnsNodeRepository) {
79      this.dhcpRepository = dhcpRepository;
80      this.dnsZoneRepository = dnsZoneRepository;
81      this.dnsNodeRepository = dnsNodeRepository;
82  
83      this.dnsNodeComparator = new DnsNodeComparator();
84      this.dnsZoneComparator = new DnsZoneComparator(this.dnsZoneRepository);
85  
86      this.patternMac = Pattern.compile(properties.getMacRegex());
87      this.patternIp4 = Pattern.compile(properties.getIp4Regex());
88    }
89  
90    @Override
91    public List<DnsNode> query(final String query, final UnknownFilter unknownFilter) {
92      log.info("msg=[Query dns nodes.] query=[{}] unknownFilter=[{}]", query, unknownFilter);
93      if (!StringUtils.hasText(query)) {
94        return Collections.emptyList();
95      }
96      final Set<String> ips = new HashSet<>();
97      if (patternMac.matcher(query.toUpperCase()).matches()) {
98        findIpByMac(query).ifPresent(ips::add);
99      } else if (patternIp4.matcher(query).matches()) {
100       ips.add(query);
101     }
102     if (!ips.isEmpty()) {
103       return dnsNodeRepository.findByIps(ips, unknownFilter);
104     }
105     return dnsNodeRepository.findByHostName(query, unknownFilter)
106         .map(Collections::singletonList)
107         .orElseGet(Collections::emptyList);
108   }
109 
110   private Optional<String> findIpByMac(String mac) {
111     final String normalizedMac = mac.replace("-", ":").trim();
112     return dhcpRepository.findActiveByIp().values().stream()
113         .filter(dhcpLease -> normalizedMac.equalsIgnoreCase(dhcpLease.getMac()))
114         .map(DhcpLease::getIp)
115         .findFirst();
116   }
117 
118   @Override
119   public List<DhcpLease> getDhcpLeases(final Boolean all, final String sort) {
120     final List<DhcpLease> leases;
121     if (Boolean.TRUE.equals(all)) {
122       leases = dhcpRepository.findAll();
123     } else {
124       leases = new ArrayList<>(dhcpRepository.findActiveByIp().values());
125     }
126     final String sortOrder = StringUtils.hasText(sort) ? sort : DhcpLease.SORT_ORDER_BEGIN_HOSTNAME;
127     leases.sort(ComparatorBuilder.builder()
128         .fromWellKnownText(sortOrder)
129         .build());
130     return leases;
131   }
132 
133   @Override
134   public List<DnsZone> getDnsZones() {
135     return dnsZoneRepository.findAll()
136         .sorted(dnsZoneComparator)
137         .collect(Collectors.toList());
138   }
139 
140   @Override
141   public DnsZone addDnsZone(DnsZone dnsZone) {
142     return dnsZoneRepository.save(dnsZone.getName());
143   }
144 
145   @Override
146   public Boolean deleteDnsZone(String zoneName) {
147     final boolean success = dnsZoneRepository.delete(zoneName);
148     if (success && (dnsNodeRepository instanceof MockRepository)) {
149       dnsNodeRepository.deleteAll(zoneName);
150     }
151     return success;
152   }
153 
154 
155   @Override
156   public List<DnsNode> getDnsNodes(String zoneName, UnknownFilter unknownFilter, String query) {
157     if (!dnsZoneRepository.exists(zoneName)) {
158       throw ServiceException.notFoundWithErrorCode(
159           DnsZone.class.getSimpleName(),
160           zoneName,
161           "org.bremersee:dc-con-app:e7466445-059f-4089-b69a-89bf08a9af1c");
162     }
163     return dnsNodeRepository.findAll(zoneName, unknownFilter, query)
164         .sorted(dnsNodeComparator)
165         .collect(Collectors.toList());
166   }
167 
168   @Override
169   public Optional<DnsNode> save(String zoneName, DnsNode dnsNode) {
170     if (!dnsZoneRepository.exists(zoneName)) {
171       throw ServiceException.notFound(DnsZone.class.getSimpleName(), zoneName);
172     }
173     return dnsNodeRepository.save(zoneName, dnsNode);
174   }
175 
176   @Override
177   public Optional<DnsNode> getDnsNode(
178       String zoneName,
179       String nodeName,
180       UnknownFilter unknownFilter) {
181     if (!dnsZoneRepository.exists(zoneName)) {
182       throw ServiceException.notFoundWithErrorCode(
183           DnsZone.class.getSimpleName(),
184           zoneName,
185           "org.bremersee:dc-con-app:97333c5a-b7e7-46a4-9034-055675d4a604");
186     }
187     return dnsNodeRepository.findOne(zoneName, nodeName, unknownFilter);
188   }
189 
190   @Override
191   public Boolean deleteDnsNode(@NotNull String zoneName, @NotNull String nodeName) {
192     if (!dnsZoneRepository.exists(zoneName)) {
193       throw ServiceException.notFoundWithErrorCode(
194           DnsZone.class.getSimpleName(),
195           zoneName,
196           "org.bremersee:dc-con-app:02b09711-952e-4c05-bcef-2d1ac949b330");
197     }
198     return dnsNodeRepository.delete(zoneName, nodeName);
199   }
200 
201   @Override
202   public void deleteAllDnsNodes(@NotNull String zoneName) {
203     if (!dnsZoneRepository.exists(zoneName)) {
204       throw ServiceException.notFoundWithErrorCode(
205           DnsZone.class.getSimpleName(),
206           zoneName,
207           "org.bremersee:dc-con-app:4a24a3db-7d81-4542-ac1d-68e898fed494");
208     }
209     dnsNodeRepository.deleteAll(zoneName);
210   }
211 
212   @Override
213   public void deleteAllDnsNodes(@NotNull String zoneName, List<String> nodeNames) {
214     if (!dnsZoneRepository.exists(zoneName)) {
215       throw ServiceException.notFoundWithErrorCode(
216           DnsZone.class.getSimpleName(),
217           zoneName,
218           "org.bremersee:dc-con-app:937cdb01-5c89-46be-aae4-747e360b903e");
219     }
220     dnsNodeRepository.deleteAll(zoneName, nodeNames);
221   }
222 
223 }